aboutsummaryrefslogtreecommitdiff
path: root/libbutl/small-allocator.mxx
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2021-09-28 19:24:31 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2021-09-28 20:29:59 +0300
commitdf1ef68cd8e8582724ce1192bfc202e0b9aeaf0c (patch)
treeb731ca4c68e60c00c7e7d499dbf4868ee7b71f44 /libbutl/small-allocator.mxx
parent7a4fc37f264cdb67f2f83fa92703c869215bbc86 (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.mxx195
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.
- };
-}