brintos

brintos / llvm-project-archived public Read only

0
0
Text · 14.0 KiB · be517d6 Raw
509 lines · c
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef SUPPORT_CONTROLLED_ALLOCATORS_H10#define SUPPORT_CONTROLLED_ALLOCATORS_H11 12#include <memory>13#include <type_traits>14#include <cstddef>15#include <cstdlib>16#include <cstring>17#include <cstdint>18#include <cassert>19#include <new>20 21#include "test_macros.h"22#include "type_id.h"23 24#if TEST_STD_VER < 1125#error This header requires C++11 or greater26#endif27 28struct AllocController;29    // 'AllocController' is a concrete type that instruments and controls the30    // behavior of test allocators.31 32template <class T, std::size_t ID = 0>33class CountingAllocator;34    // 'CountingAllocator' is an basic implementation of the 'Allocator'35    // requirements that use the 'AllocController' interface.36 37template <class T>38class MinAlignAllocator;39    // 'MinAlignAllocator' is an instrumented test type which implements the40    // 'Allocator' requirements. 'MinAlignAllocator' ensures that it *never*41    // returns a pointer to over-aligned storage. For example42    // 'MinAlignPointer<char>{}.allocate(...)' will never a 2-byte aligned43    // pointer.44 45template <class T>46class NullAllocator;47    // 'NullAllocator' is an instrumented test type which implements the48    // 'Allocator' requirements except that 'allocator' and 'deallocate' are49    // nops.50 51 52#define DISALLOW_COPY(Type) \53  Type(Type const&) = delete; \54  Type& operator=(Type const&) = delete55 56constexpr std::size_t MaxAlignV = alignof(std::max_align_t);57 58struct TestException {};59 60struct AllocController {61    int copy_constructed = 0;62    int move_constructed = 0;63 64    int alive = 0;65    int alloc_count = 0;66    int dealloc_count = 0;67    int is_equal_count = 0;68 69    std::size_t alive_size;70    std::size_t allocated_size;71    std::size_t deallocated_size;72 73    std::size_t last_size = 0;74    std::size_t last_align = 0;75    void * last_pointer = 0;76 77    std::size_t last_alloc_size = 0;78    std::size_t last_alloc_align = 0;79    void * last_alloc_pointer = nullptr;80 81    std::size_t last_dealloc_size = 0;82    std::size_t last_dealloc_align = 0;83    void * last_dealloc_pointer = nullptr;84 85    bool throw_on_alloc = false;86 87    int construct_called = 0;88    void *last_construct_pointer = nullptr;89    TypeID const* last_construct_alloc = nullptr;90    TypeID const* last_construct_type = nullptr;91    TypeID const* last_construct_args = nullptr;92 93    int destroy_called = 0;94    void *last_destroy_pointer = nullptr;95    TypeID const* last_destroy_alloc = nullptr;96    TypeID const* last_destroy_type = nullptr;97 98    AllocController() = default;99 100    void countAlloc(void* p, std::size_t s, size_t a) {101        ++alive;102        ++alloc_count;103        alive_size += s;104        allocated_size += s;105        last_pointer = last_alloc_pointer = p;106        last_size = last_alloc_size = s;107        last_align = last_alloc_align = a;108    }109 110    void countDealloc(void* p, std::size_t s, size_t a) {111        --alive;112        ++dealloc_count;113        alive_size -= s;114        deallocated_size += s;115        last_pointer = last_dealloc_pointer = p;116        last_size = last_dealloc_size = s;117        last_align = last_dealloc_align = a;118    }119 120    template <class ...Args, class Alloc, class Tp>121    void countConstruct(Alloc const&, Tp *p) {122      ++construct_called;123      last_construct_pointer = p;124      last_construct_alloc = &makeTypeID<Alloc>();125      last_construct_type = &makeTypeID<Tp>();126      last_construct_args = &makeArgumentID<Args...>();127    }128 129    template <class Alloc, class Tp>130    void countDestroy(Alloc const&, Tp *p) {131      ++destroy_called;132      last_destroy_alloc = &makeTypeID<Alloc>();133      last_destroy_type = &makeTypeID<Tp>();134      last_destroy_pointer = p;135    }136 137    void reset() { std::memset(this, 0, sizeof(*this)); }138    void resetConstructDestroy() {139      construct_called = 0;140      last_construct_pointer = nullptr;141      last_construct_alloc = last_construct_args = last_construct_type = nullptr;142      destroy_called = 0;143      last_destroy_alloc = nullptr;144      last_destroy_pointer = nullptr;145    }146public:147    bool checkAlloc(void* p, std::size_t s, size_t a) const {148        return p == last_alloc_pointer &&149               s == last_alloc_size &&150               a == last_alloc_align;151    }152 153    bool checkAlloc(void* p, std::size_t s) const {154        return p == last_alloc_pointer &&155               s == last_alloc_size;156    }157 158    bool checkAllocAtLeast(void* p, std::size_t s, size_t a) const {159        return p == last_alloc_pointer &&160               s <= last_alloc_size &&161               a <= last_alloc_align;162    }163 164    bool checkAllocAtLeast(void* p, std::size_t s) const {165        return p == last_alloc_pointer &&166               s <= last_alloc_size;167    }168 169    bool checkDealloc(void* p, std::size_t s, size_t a) const {170        return p == last_dealloc_pointer &&171               s == last_dealloc_size &&172               a == last_dealloc_align;173    }174 175    bool checkDealloc(void* p, std::size_t s) const {176        return p == last_dealloc_pointer &&177               s == last_dealloc_size;178    }179 180    bool checkDeallocMatchesAlloc() const {181        return last_dealloc_pointer == last_alloc_pointer &&182               last_dealloc_size == last_alloc_size &&183               last_dealloc_align == last_alloc_align;184    }185 186    template <class ...Args, class Alloc, class Tp>187    bool checkConstruct(Alloc const&, Tp *p) const {188        auto expectAlloc = &makeTypeID<Alloc>();189        auto expectTp = &makeTypeID<Tp>();190        auto expectArgs = &makeArgumentID<Args...>();191        if (last_construct_pointer != p)192            return false;193        if (last_construct_alloc != expectAlloc)194            return false;195        if (last_construct_type != expectTp)196            return false;197        if (last_construct_args != expectArgs)198            return false;199        return true;200    }201 202    template <class Alloc, class Tp>203    bool checkDestroy(Alloc const&, Tp *p) const {204      return last_destroy_pointer == p &&205          last_destroy_alloc == &makeTypeID<Alloc>() &&206          last_destroy_type == &makeTypeID<Tp>();207    }208 209    bool checkDestroyMatchesConstruct() const {210      return last_destroy_pointer == last_construct_pointer &&211          last_destroy_type == last_construct_type;212    }213 214    void countIsEqual() {215        ++is_equal_count;216    }217 218    bool checkIsEqualCalledEq(int n) const {219        return is_equal_count == n;220    }221private:222  DISALLOW_COPY(AllocController);223};224 225template <class T, std::size_t ID>226class CountingAllocator227{228public:229    typedef T value_type;230    typedef T* pointer;231 232    template <class U>233    struct rebind { using other = CountingAllocator<U, ID>; };234 235    CountingAllocator() = delete;236    explicit CountingAllocator(AllocController& PP) : P(&PP) {}237 238    CountingAllocator(CountingAllocator const& other) : P(other.P) {239        P->copy_constructed += 1;240    }241 242    CountingAllocator(CountingAllocator&& other) : P(other.P) {243        P->move_constructed += 1;244    }245 246    template <class U>247    CountingAllocator(CountingAllocator<U, ID> const& other) TEST_NOEXCEPT : P(other.P) {248        P->copy_constructed += 1;249    }250 251    template <class U>252    CountingAllocator(CountingAllocator<U, ID>&& other) TEST_NOEXCEPT : P(other.P) {253        P->move_constructed += 1;254    }255 256    T* allocate(std::size_t n)257    {258        void* ret = ::operator new(n*sizeof(T));259        P->countAlloc(ret, n*sizeof(T), alignof(T));260        return static_cast<T*>(ret);261    }262 263    void deallocate(T* p, std::size_t n)264    {265        void* vp = static_cast<void*>(p);266        P->countDealloc(vp, n*sizeof(T), alignof(T));267        ::operator delete(vp);268    }269 270    template <class U, class ...Args>271    void construct(U *p, Args&&... args) {272      ::new ((void*)p) U(std::forward<Args>(args)...);273      P->countConstruct<Args&&...>(*this, p);274    }275 276    template <class U>277    void destroy(U* p) {278      p->~U();279      P->countDestroy(*this, p);280    }281 282    AllocController& getController() const { return *P; }283 284private:285    template <class Tp, std::size_t XID> friend class CountingAllocator;286    AllocController *P;287};288 289 290template <std::size_t ID>291class CountingAllocator<void, ID>292{293public:294    typedef void* pointer;295    typedef const void* const_pointer;296    typedef void value_type;297 298    template <class U>299    struct rebind { using other = CountingAllocator<U, ID>; };300 301    CountingAllocator() = delete;302    explicit CountingAllocator(AllocController& PP) : P(&PP) {}303 304    CountingAllocator(CountingAllocator const& other) : P(other.P) {305        P->copy_constructed += 1;306    }307 308    CountingAllocator(CountingAllocator&& other) : P(other.P) {309        P->move_constructed += 1;310    }311 312    template <class U>313    CountingAllocator(CountingAllocator<U, ID> const& other) TEST_NOEXCEPT : P(other.P) {314        P->copy_constructed += 1;315    }316 317    template <class U>318    CountingAllocator(CountingAllocator<U, ID>&& other) TEST_NOEXCEPT : P(other.P) {319        P->move_constructed += 1;320    }321 322    void construct(...) = delete;323    void destroy(void*) = delete;324 325    AllocController& getController() const { return *P; }326 327private:328    template <class Tp, std::size_t> friend class CountingAllocator;329    AllocController *P;330};331 332template <class T, class U, std::size_t ID>333inline bool operator==(CountingAllocator<T, ID> const& x,334                       CountingAllocator<U, ID> const& y) {335    return &x.getController() == &y.getController();336}337 338template <class T, class U, std::size_t ID>339inline bool operator!=(CountingAllocator<T, ID> const& x,340                       CountingAllocator<U, ID> const& y) {341    return !(x == y);342}343 344template <class T>345class MinAlignedAllocator346{347public:348    typedef T value_type;349    typedef T* pointer;350 351    MinAlignedAllocator() = delete;352 353    explicit MinAlignedAllocator(AllocController& R) : P(&R) {}354 355    MinAlignedAllocator(MinAlignedAllocator const& other) : P(other.P) {356        P->copy_constructed += 1;357    }358 359    MinAlignedAllocator(MinAlignedAllocator&& other) : P(other.P) {360        P->move_constructed += 1;361    }362 363    template <class U>364    MinAlignedAllocator(MinAlignedAllocator<U> const& other) TEST_NOEXCEPT : P(other.P) {365        P->copy_constructed += 1;366    }367 368    template <class U>369    MinAlignedAllocator(MinAlignedAllocator<U>&& other) TEST_NOEXCEPT : P(other.P) {370        P->move_constructed += 1;371    }372 373    T* allocate(std::size_t n) {374        char* aligned_ptr = (char*)::operator new(alloc_size(n*sizeof(T)));375        assert(is_max_aligned(aligned_ptr));376 377        char* unaligned_ptr = aligned_ptr + alignof(T);378        assert(is_min_aligned(unaligned_ptr));379 380        P->countAlloc(unaligned_ptr, n * sizeof(T), alignof(T));381 382        return ((T*)unaligned_ptr);383    }384 385    void deallocate(T* p, std::size_t n) {386        assert(is_min_aligned(p));387 388        char* aligned_ptr = ((char*)p) - alignof(T);389        assert(is_max_aligned(aligned_ptr));390 391        P->countDealloc(p, n*sizeof(T), alignof(T));392 393        return ::operator delete(static_cast<void*>(aligned_ptr));394    }395 396    template <class U, class ...Args>397    void construct(U *p, Args&&... args) {398      auto *c = ::new ((void*)p) U(std::forward<Args>(args)...);399      P->countConstruct<Args&&...>(*this, p);400    }401 402    template <class U>403    void destroy(U* p) {404      p->~U();405      P->countDestroy(*this, p);406    }407 408    AllocController& getController() const { return *P; }409 410private:411    static const std::size_t BlockSize = alignof(std::max_align_t);412 413    static std::size_t alloc_size(std::size_t s) {414        std::size_t bytes = (s + BlockSize - 1) & ~(BlockSize - 1);415        bytes += BlockSize;416        assert(bytes % BlockSize == 0);417        return bytes;418    }419 420    static bool is_max_aligned(void* p) {421        return reinterpret_cast<std::uintptr_t>(p) % BlockSize == 0;422    }423 424    static bool is_min_aligned(void* p) {425        if (alignof(T) == BlockSize) {426            return is_max_aligned(p);427        } else {428            return reinterpret_cast<std::uintptr_t>(p) % BlockSize == alignof(T);429        }430    }431 432    template <class Tp> friend class MinAlignedAllocator;433    mutable AllocController *P;434};435 436 437template <class T, class U>438inline bool operator==(MinAlignedAllocator<T> const& x,439                       MinAlignedAllocator<U> const& y) {440    return &x.getController() == &y.getController();441}442 443template <class T, class U>444inline bool operator!=(MinAlignedAllocator<T> const& x,445                       MinAlignedAllocator<U> const& y) {446    return !(x == y);447}448 449template <class T>450class NullAllocator451{452public:453    typedef T value_type;454    typedef T* pointer;455    NullAllocator() = delete;456    explicit NullAllocator(AllocController& PP) : P(&PP) {}457 458    NullAllocator(NullAllocator const& other) : P(other.P) {459        P->copy_constructed += 1;460    }461 462    NullAllocator(NullAllocator&& other) : P(other.P) {463        P->move_constructed += 1;464    }465 466    template <class U>467    NullAllocator(NullAllocator<U> const& other) TEST_NOEXCEPT : P(other.P) {468        P->copy_constructed += 1;469    }470 471    template <class U>472    NullAllocator(NullAllocator<U>&& other) TEST_NOEXCEPT : P(other.P) {473        P->move_constructed += 1;474    }475 476    T* allocate(std::size_t n)477    {478        P->countAlloc(nullptr, n*sizeof(T), alignof(T));479        return nullptr;480    }481 482    void deallocate(T* p, std::size_t n)483    {484        void* vp = static_cast<void*>(p);485        P->countDealloc(vp, n*sizeof(T), alignof(T));486    }487 488    AllocController& getController() const { return *P; }489 490private:491    template <class Tp> friend class NullAllocator;492    AllocController *P;493};494 495template <class T, class U>496inline bool operator==(NullAllocator<T> const& x,497                       NullAllocator<U> const& y) {498    return &x.getController() == &y.getController();499}500 501template <class T, class U>502inline bool operator!=(NullAllocator<T> const& x,503                       NullAllocator<U> const& y) {504    return !(x == y);505}506 507 508#endif /* SUPPORT_CONTROLLED_ALLOCATORS_H */509