diff options
author | Karen Arutyunov <karen@codesynthesis.com> | 2021-09-28 19:24:31 +0300 |
---|---|---|
committer | Karen Arutyunov <karen@codesynthesis.com> | 2021-09-28 20:29:59 +0300 |
commit | df1ef68cd8e8582724ce1192bfc202e0b9aeaf0c (patch) | |
tree | b731ca4c68e60c00c7e7d499dbf4868ee7b71f44 /libbutl/small-allocator.mxx | |
parent | 7a4fc37f264cdb67f2f83fa92703c869215bbc86 (diff) |
Get rid of C++ modules related code and rename *.mxx files to *.hxx
Diffstat (limited to 'libbutl/small-allocator.mxx')
-rw-r--r-- | libbutl/small-allocator.mxx | 195 |
1 files changed, 0 insertions, 195 deletions
diff --git a/libbutl/small-allocator.mxx b/libbutl/small-allocator.mxx deleted file mode 100644 index 5ef74be..0000000 --- a/libbutl/small-allocator.mxx +++ /dev/null @@ -1,195 +0,0 @@ -// file : libbutl/small-allocator.mxx -*- C++ -*- -// license : MIT; see accompanying LICENSE file - -#ifndef __cpp_modules_ts -#pragma once -#endif - -#include <cassert> - -#ifndef __cpp_lib_modules_ts -#include <cstddef> // size_t -#include <utility> // move() -#include <type_traits> // true_type, is_same -#endif - -// Other includes. - -#ifdef __cpp_modules_ts -export module butl.small_allocator; -#ifdef __cpp_lib_modules_ts -import std.core; -#endif -#endif - -#include <libbutl/export.hxx> - -LIBBUTL_MODEXPORT namespace butl -{ - // Implementation of the allocator (and its buffer) for small containers. - // - template <typename T, std::size_t N> - struct small_allocator_buffer - { - using value_type = T; - - // Note that the names are decorated in order not to conflict with - // the container's interface. - - // If free_ is true then the buffer is not allocated. - // - alignas (alignof (value_type)) char data_[sizeof (value_type) * N]; - bool free_ = true; - - // Note that the buffer should be constructed before the container and - // destroyed after (since the container's destructor will be destroying - // elements potentially residing in the buffer). This means that the - // buffer should be inherited from and before the std:: container. - // - small_allocator_buffer () = default; - - small_allocator_buffer (small_allocator_buffer&&) = delete; - small_allocator_buffer (const small_allocator_buffer&) = delete; - - small_allocator_buffer& operator= (small_allocator_buffer&&) = delete; - small_allocator_buffer& operator= (const small_allocator_buffer&) = delete; - }; - - template <typename T, - std::size_t N, - typename B = small_allocator_buffer<T, N>> - class small_allocator - { - public: - using buffer_type = B; - - explicit - small_allocator (buffer_type* b) noexcept: buf_ (b) {} - - // Allocator interface. - // - public: - using value_type = T; - - // These shouldn't be required but as usual there are old/broken - // implementations (like std::list in GCC 4.9). - // - using pointer = value_type*; - using const_pointer = const value_type*; - using reference = value_type&; - using const_reference = const value_type&; - - static void destroy (T* p) {p->~T ();} - - template <typename... A> - static void construct (T* p, A&&... a) - { - ::new (static_cast<void*> (p)) T (std::forward<A> (a)...); - } - - // Allocator rebinding. - // - // We assume that only one of the rebound allocators will actually be - // doing allocations and that its value type is the same as buffer value - // type. This is needed, for instance, for std::list since what actually - // gets allocated is the node type, not T (see small_list for details). - // - template <typename U> - struct rebind {using other = small_allocator<U, N, B>;}; - - template <typename U> - explicit - small_allocator (const small_allocator<U, N, B>& x) noexcept - : buf_ (x.buf_) {} - - T* - allocate (std::size_t n) - { - // An implementation can rebind the allocator to something completely - // different. For example, VC15u3 with _ITERATOR_DEBUG_LEVEL != 0 - // allocates some extra stuff which cannot possibly come from the static - // buffer. - // - if (std::is_same<T, typename buffer_type::value_type>::value) - { - if (buf_->free_) - { - assert (n >= N); // We should never be asked for less than N. - - if (n == N) - { - buf_->free_ = false; - return reinterpret_cast<T*> (buf_->data_); - } - // Fall through. - } - } - - return static_cast<T*> (::operator new (sizeof (T) * n)); - } - - void - deallocate (void* p, std::size_t) noexcept - { - if (p == buf_->data_) - buf_->free_ = true; - else - ::operator delete (p); - } - - friend bool - operator== (small_allocator x, small_allocator y) noexcept - { - // We can use y to deallocate x's allocations if they use the same small - // buffer or neither uses its small buffer (which means all allocations, - // if any, have been from the shared heap). - // - // Things get trickier with rebinding. If A is allocator and B is its - // rebinding, then the following must hold true: - // - // A a1(a) => a1==a - // A a(b) => B(a)==b && A(b)==a - // - // As a result, the rebinding constructor above always copies the buffer - // pointer and we decide whether to use the small buffer by comparing - // allocator/buffer value types. - // - // We also expect that any copy of the original allocator made by the - // std:: implementation of the container is temporary (that is, it - // doesn't outlive the small buffer). - // - return (x.buf_ == y.buf_) || (x.buf_->free_ && y.buf_->free_); - } - - friend bool - operator!= (small_allocator x, small_allocator y) noexcept - { - return !(x == y); - } - - // It might get instantiated but should not be called. - // - small_allocator - select_on_container_copy_construction () const noexcept - { - assert (false); - return small_allocator (nullptr); - } - - // propagate_on_container_copy_assignment = false - // propagate_on_container_move_assignment = false - - // Swap is not supported (see explanation in small_vector::swap()). - // - using propagate_on_container_swap = std::true_type; - - void - swap (small_allocator&) = delete; - - private: - template <typename, std::size_t, typename> - friend class small_allocator; // For buffer access in rebind. - - buffer_type* buf_; // Must not be NULL. - }; -} |