diff --git a/README.md b/README.md index e6a1336..e3da0c9 100644 --- a/README.md +++ b/README.md @@ -28,12 +28,407 @@ [flat.hpp][flat] is a header only library. All you need to do is copy the header files (`flat_set.hpp` and `flat_map.hpp`) into your project and include them: ```cpp -#include "flat_set.hpp" // for flat_set -#include "flat_map.hpp" // for flat_map +#include "flat_set.hpp" +#include "flat_map.hpp" ``` -## API +## flat_set -> coming soon! +```cpp +template < typename Key + , typename Compare = std::less + , typename Allocator = std::allocator + , typename Container = std::vector > +class flat_set; +``` + +### Member types + +| Member type | Definition | +|--------------------------|-------------------------------------| +| `key_type` | `Key` | +| `value_type` | `Key` | +| `size_type` | `Container::size_type` | +| `difference_type` | `Container::difference_type` | +| `key_compare` | `Compare` | +| `value_compare` | `Compare` | +| `allocator_type` | `Allocator` | +| `container_type` | `Container` | +| `reference` | `Container::reference` | +| `const_reference` | `Container::const_reference` | +| `pointer` | `Container::pointer` | +| `const_pointer` | `Container::const_pointer` | +| `iterator` | `Container::iterator` | +| `const_iterator` | `Container::const_iterator` | +| `reverse_iterator` | `Container::reverse_iterator` | +| `const_reverse_iterator` | `Container::const_reverse_iterator` | + +### Member functions + +```cpp +explicit flat_set( + const Allocator& a); + +explicit flat_set( + const Compare& c = Compare(), + const Allocator& a = Allocator()); + +template < typename InputIter > +flat_set( + InputIter first, + InputIter last, + const Allocator& a); + +template < typename InputIter > +flat_set( + InputIter first, + InputIter last, + const Compare& c = Compare(), + const Allocator& a = Allocator()); + +flat_set( + std::initializer_list ilist, + const Allocator& a); + +flat_set( + std::initializer_list ilist, + const Compare& c = Compare(), + const Allocator& a = Allocator()); + +flat_set(flat_set&& other); +flat_set(const flat_set& other) + +flat_set& operator=(flat_set&& other); +flat_set& operator=(const flat_set& other); +flat_set& operator=(std::initializer_list ilist); + +allocator_type get_allocator() const; +``` + +### Iterators + +```cpp +iterator begin() noexcept; +const_iterator begin() const noexcept; +const_iterator cbegin() const noexcept; + +iterator end() noexcept; +const_iterator end() const noexcept; +const_iterator cend() const noexcept; + +reverse_iterator rbegin() noexcept; +const_reverse_iterator rbegin() const noexcept; +const_reverse_iterator crbegin() const noexcept; + +reverse_iterator rend() noexcept; +const_reverse_iterator rend() const noexcept; +const_reverse_iterator crend() const noexcept; +``` + +### Capacity + +```cpp +bool empty() const noexcept; +size_type size() const noexcept; +size_type max_size() const noexcept; +``` + +### Modifiers + +```cpp +std::pair insert(value_type&& value); +std::pair insert(const value_type& value); + +iterator insert(const_iterator hint, value_type&& value); +iterator insert(const_iterator hint, const value_type& value); + +template < typename InputIter > +void insert(InputIter first, InputIter last); +void insert(std::initializer_list ilist); + +template < typename... Args > +std::pair emplace(Args&&... args); +template < typename... Args > +iterator emplace_hint(const_iterator hint, Args&&... args); + +void clear() noexcept; +iterator erase(const_iterator iter); +iterator erase(const_iterator first, const_iterator last); +size_type erase(const key_type& key); + +void swap(flat_set& other); +``` + +### Lookup + +```cpp +size_type count(const key_type& key) const; + +iterator find(const key_type& key); +const_iterator find(const key_type& key) const; + +std::pair equal_range(const key_type& key); +std::pair equal_range(const key_type& key) const; + +iterator lower_bound(const key_type& key); +const_iterator lower_bound(const key_type& key) const; + +iterator upper_bound(const key_type& key); +const_iterator upper_bound(const key_type& key) const; +``` + +### Observers + +```cpp +key_compare key_comp() const; +value_compare value_comp() const; +``` + +### Non-member functions + +```cpp +template < typename K, typename C, typename A > +void swap( + flat_set& l, + flat_set& r); + +template < typename K, typename C, typename A > +bool operator==( + const flat_set& l, + const flat_set& r); + +template < typename K, typename C, typename A > +bool operator!=( + const flat_set& l, + const flat_set& r); + +template < typename K, typename C, typename A > +bool operator<( + const flat_set& l, + const flat_set& r); + +template < typename K, typename C, typename A > +bool operator>( + const flat_set& l, + const flat_set& r); + +template < typename K, typename C, typename A > +bool operator<=( + const flat_set& l, + const flat_set& r); + +template < typename K, typename C, typename A > +bool operator>=( + const flat_set& l, + const flat_set& r); +``` + +## flat_map + +```cpp +template < typename Key + , typename Value + , typename Compare = std::less + , typename Allocator = std::allocator> + , typename Container = std::vector, Allocator> > +class flat_map; +``` + +### Member types + +| Member type | Definition | +|--------------------------|-------------------------------------| +| `key_type` | `Key` | +| `mapped_type` | `Value` | +| `value_type` | `Container::value_type` | +| `size_type` | `Container::size_type` | +| `difference_type` | `Container::difference_type` | +| `key_compare` | `Compare` | +| `allocator_type` | `Allocator` | +| `container_type` | `Container` | +| `reference` | `Container::reference` | +| `const_reference` | `Container::const_reference` | +| `pointer` | `Container::pointer` | +| `const_pointer` | `Container::const_pointer` | +| `iterator` | `Container::iterator` | +| `const_iterator` | `Container::const_iterator` | +| `reverse_iterator` | `Container::reverse_iterator` | +| `const_reverse_iterator` | `Container::const_reverse_iterator` | + +### Member classes + +```cpp +class value_compare; +``` + +### Member functions + +```cpp +explicit flat_map( + const Allocator& a); + +explicit flat_map( + const Compare& c = Compare(), + const Allocator& a = Allocator()); + +template < typename InputIter > +flat_map( + InputIter first, + InputIter last, + const Allocator& a); + +template < typename InputIter > +flat_map( + InputIter first, + InputIter last, + const Compare& c = Compare(), + const Allocator& a = Allocator()); + +flat_map( + std::initializer_list ilist, + const Allocator& a); + +flat_map( + std::initializer_list ilist, + const Compare& c = Compare(), + const Allocator& a = Allocator()); + +flat_map(flat_map&& other); +flat_map(const flat_map& other); + +flat_map& operator=(flat_map&& other); +flat_map& operator=(const flat_map& other); +flat_map& operator=(std::initializer_list ilist); + +allocator_type get_allocator() const; +``` + +### Iterators + +```cpp +iterator begin() noexcept; +const_iterator begin() const noexcept; +const_iterator cbegin() const noexcept; + +iterator end() noexcept; +const_iterator end() const noexcept; +const_iterator cend() const noexcept; + +reverse_iterator rbegin() noexcept; +const_reverse_iterator rbegin() const noexcept; +const_reverse_iterator crbegin() const noexcept; + +reverse_iterator rend() noexcept; +const_reverse_iterator rend() const noexcept; +const_reverse_iterator crend() const noexcept; +``` + +### Capacity + +```cpp +bool empty() const noexcept; +size_type size() const noexcept; +size_type max_size() const noexcept; +``` + +### Element access + +```cpp +mapped_type& operator[](key_type&& key); +mapped_type& operator[](const key_type& key); + +mapped_type& at(const key_type& key); +const mapped_type& at(const key_type& key) const; +``` + +### Modifiers + +```cpp +std::pair insert(value_type&& value); +std::pair insert(const value_type& value); + +iterator insert(const_iterator hint, value_type&& value); +iterator insert(const_iterator hint, const value_type& value); + +template < typename InputIter > +void insert(InputIter first, InputIter last); +void insert(std::initializer_list ilist); + +template < typename... Args > +std::pair emplace(Args&&... args); +template < typename... Args > +iterator emplace_hint(const_iterator hint, Args&&... args); + +void clear() noexcept; +iterator erase(const_iterator iter); +iterator erase(const_iterator first, const_iterator last); +size_type erase(const key_type& key); + +void swap(flat_map& other) +``` + +### Lookup + +```cpp +size_type count(const key_type& key) const; + +iterator find(const key_type& key); +const_iterator find(const key_type& key) const; + +std::pair equal_range(const key_type& key); +std::pair equal_range(const key_type& key) const; + +iterator lower_bound(const key_type& key); +const_iterator lower_bound(const key_type& key) const; + +iterator upper_bound(const key_type& key); +const_iterator upper_bound(const key_type& key) const; +``` + +### Observers + +```cpp +key_compare key_comp() const; +value_compare value_comp() const; +``` + +### Non-member functions + +```cpp +template < typename K, typename V, typename C, typename A > +void swap( + flat_map& l, + flat_map& r); + +template < typename K, typename V, typename C, typename A > +bool operator==( + const flat_map& l, + const flat_map& r); + +template < typename K, typename V, typename C, typename A > +bool operator!=( + const flat_map& l, + const flat_map& r); + +template < typename K, typename V, typename C, typename A > +bool operator<( + const flat_map& l, + const flat_map& r); + +template < typename K, typename V, typename C, typename A > +bool operator>( + const flat_map& l, + const flat_map& r); + +template < typename K, typename V, typename C, typename A > +bool operator<=( + const flat_map& l, + const flat_map& r); + +template < typename K, typename V, typename C, typename A > +bool operator>=( + const flat_map& l, + const flat_map& r); +``` ## [License (MIT)](./LICENSE.md) diff --git a/flat_map.hpp b/flat_map.hpp index b117b2a..7b19608 100644 --- a/flat_map.hpp +++ b/flat_map.hpp @@ -20,12 +20,9 @@ namespace flat_hpp template < typename Key , typename Value , typename Compare = std::less - , typename Allocator = std::allocator> > + , typename Allocator = std::allocator> + , typename Container = std::vector, Allocator> > class flat_map final { - using data_type = std::vector< - std::pair, - Allocator>; - class uber_comparer_type : public Compare { public: uber_comparer_type() = default; @@ -35,36 +32,37 @@ namespace flat_hpp return Compare::operator()(l, r); } - bool operator()(const Key& l, typename data_type::const_reference r) const { + bool operator()(const Key& l, typename Container::const_reference r) const { return Compare::operator()(l, r.first); } - bool operator()(typename data_type::const_reference l, const Key& r) const { + bool operator()(typename Container::const_reference l, const Key& r) const { return Compare::operator()(l.first, r); } }; public: using key_type = Key; using mapped_type = Value; - using value_type = typename data_type::value_type; + using value_type = typename Container::value_type; - using size_type = typename data_type::size_type; - using difference_type = typename data_type::difference_type; + using size_type = typename Container::size_type; + using difference_type = typename Container::difference_type; using key_compare = Compare; using allocator_type = Allocator; + using container_type = Container; - using reference = typename data_type::reference; - using const_reference = typename data_type::const_reference; - using pointer = typename data_type::pointer; - using const_pointer = typename data_type::const_pointer; + using reference = typename Container::reference; + using const_reference = typename Container::const_reference; + using pointer = typename Container::pointer; + using const_pointer = typename Container::const_pointer; - using iterator = typename data_type::iterator; - using const_iterator = typename data_type::const_iterator; - using reverse_iterator = typename data_type::reverse_iterator; - using const_reverse_iterator = typename data_type::const_reverse_iterator; + using iterator = typename Container::iterator; + using const_iterator = typename Container::const_iterator; + using reverse_iterator = typename Container::reverse_iterator; + using const_reverse_iterator = typename Container::const_reverse_iterator; - class value_compare final { + class value_compare { public: bool operator()(const value_type& l, const value_type& r) const { return compare_(l.first, r.first); @@ -80,6 +78,14 @@ namespace flat_hpp static_assert( std::is_same::value, "Allocator::value_type must be same type as value_type"); + + static_assert( + std::is_same::value, + "Container::value_type must be same type as value_type"); + + static_assert( + std::is_same::value, + "Container::allocator_type must be same type as allocator_type"); public: explicit flat_map( const Allocator& a) @@ -127,6 +133,37 @@ namespace flat_hpp insert(ilist); } + flat_map(flat_map&& other) + : data_(std::move(other.data_)) + , compare_(std::move(other.compare_)) {} + + flat_map(const flat_map& other) + : data_(other.data_) + , compare_(other.compare_) {} + + flat_map& operator=(flat_map&& other) { + if ( this != &other ) { + flat_map(std::move(other)).swap(*this); + } + return *this; + } + + flat_map& operator=(const flat_map& other) { + if ( this != &other ) { + flat_map(other).swap(*this); + } + return *this; + } + + flat_map& operator=(std::initializer_list ilist) { + flat_map(ilist).swap(*this); + return *this; + } + + allocator_type get_allocator() const { + return data_.get_allocator(); + } + iterator begin() noexcept { return data_.begin(); } const_iterator begin() const noexcept { return data_.begin(); } const_iterator cbegin() const noexcept { return data_.cbegin(); } @@ -156,15 +193,21 @@ namespace flat_hpp } mapped_type& operator[](key_type&& key) { - return insert(value_type(std::move(key), mapped_type())).first->second; + const iterator iter = find(key); + return iter != end() + ? iter->second + : emplace(std::move(key), mapped_type()).first->second; } mapped_type& operator[](const key_type& key) { - return insert(value_type(key, mapped_type())).first->second; + const iterator iter = find(key); + return iter != end() + ? iter->second + : emplace(key, mapped_type()).first->second; } mapped_type& at(const key_type& key) { - const auto iter = find(key); + const iterator iter = find(key); if ( iter != end() ) { return iter->second; } @@ -172,13 +215,20 @@ namespace flat_hpp } const mapped_type& at(const key_type& key) const { - const auto iter = find(key); + const const_iterator iter = find(key); if ( iter != end() ) { return iter->second; } throw std::out_of_range("flat_map::at: key not found"); } + std::pair insert(value_type&& value) { + const iterator iter = lower_bound(value.first); + return iter == end() || compare_(value.first, iter->first) + ? std::make_pair(data_.insert(iter, std::move(value)), true) + : std::make_pair(iter, false); + } + std::pair insert(const value_type& value) { const iterator iter = lower_bound(value.first); return iter == end() || compare_(value.first, iter->first) @@ -186,13 +236,20 @@ namespace flat_hpp : std::make_pair(iter, false); } - iterator insert(const_iterator hint, const value_type& value) { + iterator insert(const_iterator hint, value_type&& value) { return (hint == begin() || compare_((hint - 1)->first, value.first)) && (hint == end() || compare_(value.first, hint->first)) ? data_.insert(hint, std::move(value)) : insert(std::move(value)).first; } + iterator insert(const_iterator hint, const value_type& value) { + return (hint == begin() || compare_((hint - 1)->first, value.first)) + && (hint == end() || compare_(value.first, hint->first)) + ? data_.insert(hint, value) + : insert(value).first; + } + template < typename InputIter > void insert(InputIter first, InputIter last) { while ( first != last ) { @@ -290,7 +347,7 @@ namespace flat_hpp return value_compare(compare_); } private: - data_type data_; + container_type data_; uber_comparer_type compare_; }; } diff --git a/flat_map_tests.cpp b/flat_map_tests.cpp index 1957624..cdacde3 100644 --- a/flat_map_tests.cpp +++ b/flat_map_tests.cpp @@ -18,9 +18,11 @@ namespace using value_type = T; dummy_allocator() = default; + dummy_allocator(int i) : i(i) {} template < typename U > - dummy_allocator(const dummy_allocator&) noexcept { + dummy_allocator(const dummy_allocator& o) noexcept { + i = o.i; } T* allocate(std::size_t n) noexcept { @@ -31,6 +33,8 @@ namespace (void)n; std::free(p); } + + int i = 0; }; template < typename T, typename U > @@ -100,6 +104,9 @@ TEST_CASE("flat_map") { std::greater, alloc_t>; + using vec_t = std::vector< + std::pair>; + { auto s0 = map_t(); auto s1 = map2_t(alloc_t()); @@ -108,8 +115,6 @@ TEST_CASE("flat_map") { } { - using vec_t = std::vector>; - vec_t v{{1,30},{2,20},{3,10}}; auto s0 = map_t(v.cbegin(), v.cend()); auto s1 = map2_t(v.cbegin(), v.cend(), alloc_t()); @@ -127,6 +132,44 @@ TEST_CASE("flat_map") { auto s1 = map_t({{0,1}, {1,2}}, alloc_t()); auto s2 = map_t({{0,1}, {1,2}}, std::less()); auto s3 = map_t({{0,1}, {1,2}}, std::less(), alloc_t()); + + REQUIRE(vec_t(s0.begin(), s0.end()) == vec_t({{0,1},{1,2}})); + REQUIRE(vec_t(s1.begin(), s1.end()) == vec_t({{0,1},{1,2}})); + REQUIRE(vec_t(s2.begin(), s2.end()) == vec_t({{0,1},{1,2}})); + REQUIRE(vec_t(s3.begin(), s3.end()) == vec_t({{0,1},{1,2}})); + } + + { + auto s0 = map_t(); + auto s1 = map_t(alloc_t(42)); + REQUIRE(s0.get_allocator().i == 0); + REQUIRE(s1.get_allocator().i == 42); + } + + { + auto s0 = map_t{{0,1}, {1,2}}; + auto s1 = s0; + REQUIRE(s0 == map_t{{0,1}, {1,2}}); + REQUIRE(s1 == map_t{{0,1}, {1,2}}); + auto s2 = std::move(s1); + REQUIRE(s1.empty()); + REQUIRE(s2 == map_t{{0,1}, {1,2}}); + } + + { + auto s0 = map_t{{0,1}, {1,2}}; + map_t s1; + s1 = s0; + REQUIRE(s0 == map_t{{0,1}, {1,2}}); + REQUIRE(s1 == map_t{{0,1}, {1,2}}); + map_t s2; + s2 = std::move(s1); + REQUIRE(s0 == map_t{{0,1}, {1,2}}); + REQUIRE(s1.empty()); + REQUIRE(s2 == map_t{{0,1}, {1,2}}); + map_t s3; + s3 = {{0,1}, {1,2}}; + REQUIRE(s3 == map_t{{0,1}, {1,2}}); } } SECTION("capacity") { @@ -156,15 +199,34 @@ TEST_CASE("flat_map") { REQUIRE(s0.max_size() == std::allocator>().max_size()); } SECTION("access") { - using map_t = flat_map; + struct obj_t { + obj_t(int i) : i(i) {} + int i; + + bool operator<(const obj_t& o) const { + return i < o.i; + } + + bool operator==(const obj_t& o) const { + return i == o.i; + } + }; + + using map_t = flat_map; map_t s0; - s0[1] = 42; + + obj_t k1(1); + + s0[k1] = 42; + REQUIRE(s0[k1] == 42); REQUIRE(s0 == map_t{{1,42}}); + s0[1] = 84; + REQUIRE(s0[1] == 84); REQUIRE(s0 == map_t{{1,84}}); REQUIRE(s0.at(1) == 84); - REQUIRE(my_as_const(s0).at(1) == 84); + REQUIRE(my_as_const(s0).at(k1) == 84); REQUIRE_THROWS_AS(s0.at(0), std::out_of_range); REQUIRE_THROWS_AS(my_as_const(s0).at(0), std::out_of_range); } @@ -182,12 +244,15 @@ TEST_CASE("flat_map") { } }; - using map_t = flat_map; + using map_t = flat_map; { map_t s0; - auto i0 = s0.insert(std::make_pair(1, 42)); + auto k1_42 = std::make_pair(1, 42); + auto k3_84 = std::make_pair(3, 84); + + auto i0 = s0.insert(k1_42); REQUIRE(s0 == map_t{{1,42}}); REQUIRE(i0 == std::make_pair(s0.begin(), true)); @@ -199,7 +264,7 @@ TEST_CASE("flat_map") { REQUIRE(s0 == map_t{{1,42},{2,42}}); REQUIRE(i2 == std::make_pair(s0.begin() + 1, true)); - auto i3 = s0.insert(s0.cend(), std::make_pair(3, 84)); + auto i3 = s0.insert(s0.cend(), k3_84); REQUIRE(i3 == s0.begin() + 2); s0.insert(s0.cend(), std::make_pair(4, obj_t(84))); diff --git a/flat_set.hpp b/flat_set.hpp index f5652f0..a63e51e 100644 --- a/flat_set.hpp +++ b/flat_set.hpp @@ -19,33 +19,51 @@ namespace flat_hpp { template < typename Key , typename Compare = std::less - , typename Allocator = std::allocator > + , typename Allocator = std::allocator + , typename Container = std::vector > class flat_set final { - using data_type = std::vector; + class uber_comparer_type : public Compare { + public: + uber_comparer_type() = default; + uber_comparer_type(const Compare& c) : Compare(c) {} + + bool operator()(const Key& l, const Key& r) const { + return Compare::operator()(l, r); + } + }; public: using key_type = Key; using value_type = Key; - using size_type = typename data_type::size_type; - using difference_type = typename data_type::difference_type; + using size_type = typename Container::size_type; + using difference_type = typename Container::difference_type; using key_compare = Compare; using value_compare = Compare; using allocator_type = Allocator; + using container_type = Container; - using reference = typename data_type::reference; - using const_reference = typename data_type::const_reference; - using pointer = typename data_type::pointer; - using const_pointer = typename data_type::const_pointer; + using reference = typename Container::reference; + using const_reference = typename Container::const_reference; + using pointer = typename Container::pointer; + using const_pointer = typename Container::const_pointer; - using iterator = typename data_type::iterator; - using const_iterator = typename data_type::const_iterator; - using reverse_iterator = typename data_type::reverse_iterator; - using const_reverse_iterator = typename data_type::const_reverse_iterator; + using iterator = typename Container::iterator; + using const_iterator = typename Container::const_iterator; + using reverse_iterator = typename Container::reverse_iterator; + using const_reverse_iterator = typename Container::const_reverse_iterator; static_assert( std::is_same::value, "Allocator::value_type must be same type as value_type"); + + static_assert( + std::is_same::value, + "Container::value_type must be same type as value_type"); + + static_assert( + std::is_same::value, + "Container::allocator_type must be same type as allocator_type"); public: explicit flat_set( const Allocator& a) @@ -93,6 +111,37 @@ namespace flat_hpp insert(ilist); } + flat_set(flat_set&& other) + : data_(std::move(other.data_)) + , compare_(std::move(other.compare_)) {} + + flat_set(const flat_set& other) + : data_(other.data_) + , compare_(other.compare_) {} + + flat_set& operator=(flat_set&& other) { + if ( this != &other ) { + flat_set(std::move(other)).swap(*this); + } + return *this; + } + + flat_set& operator=(const flat_set& other) { + if ( this != &other ) { + flat_set(other).swap(*this); + } + return *this; + } + + flat_set& operator=(std::initializer_list ilist) { + flat_set(ilist).swap(*this); + return *this; + } + + allocator_type get_allocator() const { + return data_.get_allocator(); + } + iterator begin() noexcept { return data_.begin(); } const_iterator begin() const noexcept { return data_.begin(); } const_iterator cbegin() const noexcept { return data_.cbegin(); } @@ -246,8 +295,8 @@ namespace flat_hpp return value_compare(compare_); } private: - data_type data_; - key_compare compare_; + container_type data_; + uber_comparer_type compare_; }; } diff --git a/flat_set_tests.cpp b/flat_set_tests.cpp index d103f55..5331c3c 100644 --- a/flat_set_tests.cpp +++ b/flat_set_tests.cpp @@ -18,9 +18,11 @@ namespace using value_type = T; dummy_allocator() = default; + dummy_allocator(int i) : i(i) {} template < typename U > - dummy_allocator(const dummy_allocator&) noexcept { + dummy_allocator(const dummy_allocator& o) noexcept { + i = o.i; } T* allocate(std::size_t n) noexcept { @@ -31,6 +33,8 @@ namespace (void)n; std::free(p); } + + int i = 0; }; template < typename T, typename U > @@ -85,6 +89,7 @@ TEST_CASE("flat_set") { using alloc_t = dummy_allocator; using set_t = flat_set, alloc_t>; using set2_t = flat_set, alloc_t>; + using vec_t = std::vector; { auto s0 = set_t(); @@ -94,16 +99,16 @@ TEST_CASE("flat_set") { } { - std::vector v{1,2,3}; + vec_t v{1,2,3}; auto s0 = set_t(v.cbegin(), v.cend()); auto s1 = set2_t(v.cbegin(), v.cend(), alloc_t()); auto s2 = set_t(v.cbegin(), v.cend(), std::less()); auto s3 = set2_t(v.cbegin(), v.cend(), std::greater(), alloc_t()); - REQUIRE(std::vector(s0.begin(), s0.end()) == std::vector({1,2,3})); - REQUIRE(std::vector(s1.begin(), s1.end()) == std::vector({3,2,1})); - REQUIRE(std::vector(s2.begin(), s2.end()) == std::vector({1,2,3})); - REQUIRE(std::vector(s3.begin(), s3.end()) == std::vector({3,2,1})); + REQUIRE(vec_t(s0.begin(), s0.end()) == vec_t({1,2,3})); + REQUIRE(vec_t(s1.begin(), s1.end()) == vec_t({3,2,1})); + REQUIRE(vec_t(s2.begin(), s2.end()) == vec_t({1,2,3})); + REQUIRE(vec_t(s3.begin(), s3.end()) == vec_t({3,2,1})); } { @@ -112,10 +117,43 @@ TEST_CASE("flat_set") { auto s2 = set_t({0,1,2}, std::less()); auto s3 = set2_t({0,1,2}, std::greater(), alloc_t()); - REQUIRE(std::vector(s0.begin(), s0.end()) == std::vector({0,1,2})); - REQUIRE(std::vector(s1.begin(), s1.end()) == std::vector({2,1,0})); - REQUIRE(std::vector(s2.begin(), s2.end()) == std::vector({0,1,2})); - REQUIRE(std::vector(s3.begin(), s3.end()) == std::vector({2,1,0})); + REQUIRE(vec_t(s0.begin(), s0.end()) == vec_t({0,1,2})); + REQUIRE(vec_t(s1.begin(), s1.end()) == vec_t({2,1,0})); + REQUIRE(vec_t(s2.begin(), s2.end()) == vec_t({0,1,2})); + REQUIRE(vec_t(s3.begin(), s3.end()) == vec_t({2,1,0})); + } + + { + auto s0 = set_t(); + auto s1 = set_t(alloc_t(42)); + REQUIRE(s0.get_allocator().i == 0); + REQUIRE(s1.get_allocator().i == 42); + } + + { + auto s0 = set_t{0,1,2}; + auto s1 = s0; + REQUIRE(s0 == set_t{0,1,2}); + REQUIRE(s1 == set_t{0,1,2}); + auto s2 = std::move(s1); + REQUIRE(s1.empty()); + REQUIRE(s2 == set_t{0,1,2}); + } + + { + auto s0 = set_t{0,1,2}; + set_t s1; + s1 = s0; + REQUIRE(s0 == set_t{0,1,2}); + REQUIRE(s1 == set_t{0,1,2}); + set_t s2; + s2 = std::move(s1); + REQUIRE(s0 == set_t{0,1,2}); + REQUIRE(s1.empty()); + REQUIRE(s2 == set_t{0,1,2}); + set_t s3; + s3 = {1,2,3}; + REQUIRE(s3 == set_t{1,2,3}); } } SECTION("capacity") {