From df1ef68cd8e8582724ce1192bfc202e0b9aeaf0c Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Tue, 28 Sep 2021 19:24:31 +0300 Subject: Get rid of C++ modules related code and rename *.mxx files to *.hxx --- libbutl/small-list.hxx | 150 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 libbutl/small-list.hxx (limited to 'libbutl/small-list.hxx') diff --git a/libbutl/small-list.hxx b/libbutl/small-list.hxx new file mode 100644 index 0000000..aaeef22 --- /dev/null +++ b/libbutl/small-list.hxx @@ -0,0 +1,150 @@ +// file : libbutl/small-list.hxx -*- C++ -*- +// license : MIT; see accompanying LICENSE file + +#pragma once + +#include +#include // size_t +#include // move() + +#include + +#include + +namespace butl +{ + // Issues and limitations. + // + // - VC's implementation of std::list allocates an extra "headnode" + // (something to do with additional iterator stability guarantees). Which + // means only empty small list will actually be "small". As a result, + // unless you don't care about VC, you should use small_forward_list + // instead. + // + // - Because small_allocator currently expects us to allocate the entire + // small buffer and there is no reserve() in std::list, we currently + // only support N==1 (which we static_assert). + // + // - swap() is deleted (see notes below). + // + // - The implementation doesn't allocate T but rather a "node" that normally + // consists of two pointers (prev/next) and T. + // + template + using small_list_node = +#if defined (_MSC_VER) + std::_List_node; +#elif defined (__GLIBCXX__) + std::_List_node; +#elif defined (_LIBCPP_VERSION) + std::__list_node; +#else +#error unknown standard library implementation +#endif + + template + using small_list_buffer = small_allocator_buffer, N>; + + template + class small_list: + private small_list_buffer, + public std::list>> + { + static_assert (N == 1, "only small_list or 1 currently supported"); + + public: + static constexpr const std::size_t small_size = N; + + using buffer_type = small_list_buffer; + using allocator_type = small_allocator; + using base_type = std::list; + + small_list () + : base_type (allocator_type (this)) {} + + small_list (std::initializer_list v) + : base_type (allocator_type (this)) + { + static_cast (*this) = v; + } + + template + small_list (I b, I e) + : base_type (allocator_type (this)) + { + this->assign (b, e); + } + + explicit + small_list (std::size_t n) + : base_type (allocator_type (this)) + { + this->resize (n); + } + + small_list (std::size_t n, const T& x) + : base_type (allocator_type (this)) + { + this->assign (n, x); + } + + small_list (const small_list& v) + : buffer_type (), base_type (allocator_type (this)) + { + static_cast (*this) = v; + } + + small_list& + operator= (const small_list& v) + { + // Note: propagate_on_container_copy_assignment = false + // + static_cast (*this) = v; + return *this; + } + + small_list (small_list&& v) + : base_type (allocator_type (this)) + { + *this = std::move (v); // Delegate to operator=(&&). + } + + small_list& + operator= (small_list&& v) + { + // libstdc++'s implementation prior to GCC 6 is broken (calls swap()). + // Since there is no easy way to determine this library's version, for + // now this is always enabled. + // + // Similarly, VC14's implementation of operator=(&&) swaps pointers + // without regard for allocator (fixed in 15). + // +#if defined(__GLIBCXX__) || (defined(_MSC_VER) && _MSC_VER <= 1900) + this->clear (); + for (T& x: v) + this->push_back (std::move (x)); + v.clear (); +#else + // Note: propagate_on_container_move_assignment = false + // + static_cast (*this) = std::move (v); +#endif + + return *this; + } + + small_list& + operator= (std::initializer_list v) + { + static_cast (*this) = v; + return *this; + } + + // Implementing swap() under small buffer optimization is not trivial, to + // say the least (think of swapping two such buffers of different sizes). + // One easy option would be to force both in to the heap. + // + void + swap (small_list&) = delete; + }; +} -- cgit v1.1