diff --git a/flat_set.hpp b/flat_set.hpp index 9c661e9..f5652f0 100644 --- a/flat_set.hpp +++ b/flat_set.hpp @@ -78,19 +78,19 @@ namespace flat_hpp } flat_set( - std::initializer_list il, + std::initializer_list ilist, const Allocator& a) : data_(a) { - insert(il.begin(), il.end()); + insert(ilist); } flat_set( - std::initializer_list il, + std::initializer_list ilist, const Compare& c = Compare(), const Allocator& a = Allocator()) : data_(a) , compare_(c) { - insert(il.begin(), il.end()); + insert(ilist); } iterator begin() noexcept { return data_.begin(); } @@ -121,36 +121,52 @@ namespace flat_hpp return data_.max_size(); } - template < typename P - , typename = std::enable_if_t::value> > - std::pair insert(P&& p) { - //TODO(BlackMat): implme - return std::make_pair(end(), false); + std::pair insert(value_type&& value) { + const iterator iter = lower_bound(value); + return iter == end() || compare_(value, *iter) + ? std::make_pair(data_.insert(iter, std::move(value)), true) + : std::make_pair(iter, false); } - template < typename P - , typename = std::enable_if_t::value> > - std::pair insert(const_iterator hint, P&& p) { - //TODO(BlackMat): implme - return std::make_pair(end(), false); + std::pair insert(const value_type& value) { + const iterator iter = lower_bound(value); + return iter == end() || compare_(value, *iter) + ? std::make_pair(data_.insert(iter, value), true) + : std::make_pair(iter, false); + } + + iterator insert(const_iterator hint, value_type&& value) { + return (hint == begin() || compare_(*(hint - 1), value)) + && (hint == end() || compare_(value, *hint)) + ? 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), value)) + && (hint == end() || compare_(value, *hint)) + ? data_.insert(hint, value) + : insert(value).first; } template < typename InputIter > void insert(InputIter first, InputIter last) { - for ( auto iter = first; iter != last; ++iter ) { - insert(*iter); + while ( first != last ) { + insert(*first++); } } + void insert(std::initializer_list ilist) { + insert(ilist.begin(), ilist.end()); + } + template < typename... Args > std::pair emplace(Args&&... args) { - //TODO(BlackMat): implme return insert(value_type(std::forward(args)...)); } template < typename... Args > - std::pair emplace_hint(const_iterator hint, Args&&... args) { - //TODO(BlackMat): implme + iterator emplace_hint(const_iterator hint, Args&&... args) { return insert(hint, value_type(std::forward(args)...)); } @@ -159,67 +175,67 @@ namespace flat_hpp } iterator erase(const_iterator iter) { - //TODO(BlackMat): implme - return end(); + return data_.erase(iter); } iterator erase(const_iterator first, const_iterator last) { - //TODO(BlackMat): implme - return end(); + return data_.erase(first, last); } - iterator erase(const key_type& key) { - //TODO(BlackMat): implme - return end(); + size_type erase(const key_type& key) { + const iterator iter = find(key); + return iter != end() + ? (erase(iter), 1) + : 0; } void swap(flat_set& other) { - //TODO(BlackMat): implme + using std::swap; + swap(data_, other.data_); + swap(compare_, other.compare_); } size_type count(const key_type& key) const { - const auto iter = find(key); + const const_iterator iter = find(key); return iter != end() ? 1 : 0; } iterator find(const key_type& key) { - //TODO(BlackMat): implme - return end(); + const iterator iter = lower_bound(key); + return iter != end() && !compare_(key, *iter) + ? iter + : end(); } const_iterator find(const key_type& key) const { - //TODO(BlackMat): implme - return end(); + const const_iterator iter = lower_bound(key); + return iter != end() && !compare_(key, *iter) + ? iter + : end(); } std::pair equal_range(const key_type& key) { - //TODO(BlackMat): implme - return {end(), end()}; + return std::equal_range(begin(), end(), key, compare_); } std::pair equal_range(const key_type& key) const { - //TODO(BlackMat): implme - return {end(), end()}; + return std::equal_range(begin(), end(), key, compare_); } iterator lower_bound(const key_type& key) { - //TODO(BlackMat): implme - return end(); + return std::lower_bound(begin(), end(), key, compare_); } const_iterator lower_bound(const key_type& key) const { - //TODO(BlackMat): implme - return end(); + return std::lower_bound(begin(), end(), key, compare_); } iterator upper_bound(const key_type& key) { - //TODO(BlackMat): implme - return end(); + return std::upper_bound(begin(), end(), key, compare_); } const_iterator upper_bound(const key_type& key) const { - //TODO(BlackMat): implme - return end(); + return std::upper_bound(begin(), end(), key, compare_); } key_compare key_comp() const { diff --git a/flat_set_tests.cpp b/flat_set_tests.cpp index 8e0451b..cafc05a 100644 --- a/flat_set_tests.cpp +++ b/flat_set_tests.cpp @@ -18,13 +18,12 @@ namespace using value_type = T; T* allocate(std::size_t n) { - (void)n; - return nullptr; + return static_cast(std::malloc(sizeof(T) * n)); } void deallocate(T* p, std::size_t n) { - (void)p; (void)n; + std::free(p); } }; @@ -69,95 +68,244 @@ TEST_CASE("flat_set") { SECTION("ctors") { using alloc_t = dummy_allocator; using set_t = flat_set, alloc_t>; + using set2_t = flat_set, alloc_t>; { auto s0 = set_t(); - auto s1 = set_t(alloc_t()); + auto s1 = set2_t(alloc_t()); auto s2 = set_t(std::less()); - auto s3 = set_t(std::less(), alloc_t()); + auto s3 = set2_t(std::greater(), alloc_t()); } { - std::vector v; + std::vector v{1,2,3}; auto s0 = set_t(v.cbegin(), v.cend()); - auto s1 = set_t(v.cbegin(), v.cend(), alloc_t()); + auto s1 = set2_t(v.cbegin(), v.cend(), alloc_t()); auto s2 = set_t(v.cbegin(), v.cend(), std::less()); - auto s3 = set_t(v.cbegin(), v.cend(), std::less(), alloc_t()); + 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})); } { auto s0 = set_t({0,1,2}); - auto s1 = set_t({0,1,2}, alloc_t()); + auto s1 = set2_t({0,1,2}, alloc_t()); auto s2 = set_t({0,1,2}, std::less()); - auto s3 = set_t({0,1,2}, std::less(), alloc_t()); + 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})); } } SECTION("capacity") { using set_t = flat_set; set_t s0; - s0.empty(); - s0.size(); - s0.max_size(); + + REQUIRE(s0.empty()); + REQUIRE_FALSE(s0.size()); + REQUIRE(s0.max_size() == std::allocator().max_size()); + + s0.insert(42); + + REQUIRE_FALSE(s0.empty()); + REQUIRE(s0.size() == 1u); + REQUIRE(s0.max_size() == std::allocator().max_size()); + + s0.insert(42); + REQUIRE(s0.size() == 1u); + + s0.insert(84); + REQUIRE(s0.size() == 2u); + + s0.clear(); + + REQUIRE(s0.empty()); + REQUIRE_FALSE(s0.size()); + REQUIRE(s0.max_size() == std::allocator().max_size()); } SECTION("inserts") { 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 set_t = flat_set; { set_t s0; - s0.insert(42); - s0.insert(obj_t(42)); - s0.insert(s0.cend(), 84); - s0.insert(s0.cend(), obj_t(84)); - s0.emplace(100500); - s0.emplace_hint(s0.cend(), 100500); + + auto i0 = s0.insert(1); + REQUIRE(s0 == set_t{1}); + REQUIRE(i0 == std::make_pair(s0.begin(), true)); + + auto i1 = s0.insert(obj_t(1)); + REQUIRE(s0 == set_t{1}); + REQUIRE(i1 == std::make_pair(s0.begin(), false)); + + auto i2 = s0.insert(obj_t(2)); + REQUIRE(s0 == set_t{1,2}); + REQUIRE(i2 == std::make_pair(s0.begin() + 1, true)); + + s0.insert(s0.cbegin(), 1); + s0.insert(s0.cbegin(), 2); + s0.insert(s0.cend(), 1); + s0.insert(s0.cend(), 2); + REQUIRE(s0 == set_t{1,2}); + + s0.insert(s0.cbegin(), 0); + REQUIRE(s0 == set_t{0,1,2}); + s0.insert(s0.cend(), 3); + REQUIRE(s0 == set_t{0,1,2,3}); + s0.insert(s0.cbegin(), 4); + s0.insert(s0.cend(), -1); + REQUIRE(s0 == set_t{-1,0,1,2,3,4}); + + s0.insert(s0.cbegin() + 2, obj_t(5)); + REQUIRE(s0 == set_t{-1,0,1,2,3,4,5}); + s0.insert(s0.cbegin(), obj_t(-2)); + REQUIRE(s0 == set_t{-2,-1,0,1,2,3,4,5}); + } + + { + set_t s0; + + auto e0 = s0.emplace(3); + REQUIRE(s0 == set_t{3}); + REQUIRE(e0 == std::make_pair(s0.begin(), true)); + + auto e1 = s0.emplace(obj_t(3)); + REQUIRE(e1 == std::make_pair(s0.begin(), false)); + + auto e2 = s0.emplace(4); + REQUIRE(s0 == set_t{3,4}); + REQUIRE(e2 == std::make_pair(s0.begin() + 1, true)); + + auto e3 = s0.emplace_hint(s0.cbegin(), 1); + REQUIRE(e3 == s0.begin()); + auto e4 = s0.emplace_hint(s0.cend(), 2); + REQUIRE(e4 == s0.begin() + 1); + s0.emplace_hint(s0.cbegin(), 5); + s0.emplace_hint(s0.cend(), 6); + REQUIRE(s0 == set_t{1,2,3,4,5,6}); } } SECTION("erasers") { using set_t = flat_set; - set_t s0; - s0.clear(); - s0.erase(s0.begin()); - s0.erase(s0.cbegin()); - s0.erase(s0.begin(), s0.end()); - s0.erase(s0.cbegin(), s0.cend()); - s0.erase(42); - set_t s1; - s0.swap(s1); - swap(s0, s1); + { + set_t s0{1,2,3,4,5}; + s0.clear(); + REQUIRE(s0.empty()); + } + { + set_t s0{1,2,3,4,5}; + auto i = s0.erase(s0.find(3)); + REQUIRE(i == s0.begin() + 2); + REQUIRE(s0 == set_t{1,2,4,5}); + } + { + set_t s0{1,2,3,4,5}; + auto i = s0.erase(s0.begin() + 2, s0.end()); + REQUIRE(i == s0.end()); + REQUIRE(s0 == set_t{1,2}); + } + { + set_t s0{1,2,3,4,5}; + REQUIRE(s0.erase(2) == 1); + REQUIRE(s0.erase(6) == 0); + REQUIRE(s0 == set_t{1,3,4,5}); + } + { + set_t s0{1,2,3}; + set_t s1{3,4,5}; + s0.swap(s1); + REQUIRE(s0 == set_t{3,4,5}); + REQUIRE(s1 == set_t{1,2,3}); + swap(s1, s0); + REQUIRE(s0 == set_t{1,2,3}); + REQUIRE(s1 == set_t{3,4,5}); + } } SECTION("lookup") { using set_t = flat_set; - set_t s0; - s0.count(10); - s0.find(10); - my_as_const(s0).find(10); - s0.equal_range(20); - my_as_const(s0).equal_range(20); - s0.lower_bound(30); - my_as_const(s0).lower_bound(30); - s0.upper_bound(30); - my_as_const(s0).upper_bound(30); + { + set_t s0{1,2,3,4,5}; + REQUIRE(s0.count(3)); + REQUIRE_FALSE(s0.count(6)); + REQUIRE(my_as_const(s0).count(5)); + REQUIRE_FALSE(my_as_const(s0).count(0)); + } + { + set_t s0{1,2,3,4,5}; + REQUIRE(s0.find(2) == s0.begin() + 1); + REQUIRE(my_as_const(s0).find(3) == s0.cbegin() + 2); + REQUIRE(s0.find(6) == s0.end()); + REQUIRE(my_as_const(s0).find(0) == s0.cend()); + } + { + set_t s0{1,2,3,4,5}; + REQUIRE(s0.equal_range(3) == std::make_pair(s0.begin() + 2, s0.begin() + 3)); + REQUIRE(s0.equal_range(6) == std::make_pair(s0.end(), s0.end())); + REQUIRE(my_as_const(s0).equal_range(3) == std::make_pair(s0.cbegin() + 2, s0.cbegin() + 3)); + REQUIRE(my_as_const(s0).equal_range(0) == std::make_pair(s0.cbegin(), s0.cbegin())); + } + { + set_t s0{0,3,6,9}; + REQUIRE(s0.lower_bound(0) == s0.begin()); + REQUIRE(s0.lower_bound(1) == s0.begin() + 1); + REQUIRE(s0.lower_bound(10) == s0.end()); + REQUIRE(my_as_const(s0).lower_bound(-1) == s0.cbegin()); + REQUIRE(my_as_const(s0).lower_bound(7) == s0.cbegin() + 3); + } } SECTION("observers") { - using set_t = flat_set; - set_t s0; - my_as_const(s0).key_comp(); - my_as_const(s0).value_comp(); + struct my_less { + int i; + my_less(int i) : i(i) {} + bool operator()(int l, int r) const { + return l < r; + } + }; + using set_t = flat_set; + set_t s0(my_less(42)); + REQUIRE(my_as_const(s0).key_comp().i == 42); + REQUIRE(my_as_const(s0).value_comp().i == 42); } SECTION("operators") { using set_t = flat_set; - set_t s0; - set_t s1; - REQUIRE(s0 == s1); - REQUIRE_FALSE(s0 != s1); - REQUIRE_FALSE(s0 < s1); - REQUIRE_FALSE(s0 > s1); - REQUIRE(s0 <= s1); - REQUIRE(s0 >= s1); + + REQUIRE(set_t{1,2,3} == set_t{3,2,1}); + REQUIRE_FALSE(set_t{1,2,3} == set_t{3,2,4}); + REQUIRE_FALSE(set_t{1,2,3} == set_t{1,2,3,4}); + + REQUIRE(set_t{1,2,3} != set_t{3,2,4}); + REQUIRE_FALSE(set_t{1,2,3} != set_t{3,2,1}); + + REQUIRE(set_t{2,3,4,6} < set_t{2,3,5}); + REQUIRE(set_t{2,3,4,6} <= set_t{2,3,5}); + REQUIRE_FALSE(set_t{2,3,5} < set_t{2,3,4,6}); + REQUIRE_FALSE(set_t{2,3,5} <= set_t{2,3,4,6}); + + REQUIRE_FALSE(set_t{2,3,4,6} > set_t{2,3,5}); + REQUIRE_FALSE(set_t{2,3,4,6} >= set_t{2,3,5}); + REQUIRE(set_t{2,3,5} > set_t{2,3,4,6}); + REQUIRE(set_t{2,3,5} >= set_t{2,3,4,6}); + + REQUIRE_FALSE(set_t{1,2,3} < set_t{1,2,3}); + REQUIRE(set_t{1,2,3} <= set_t{1,2,3}); + REQUIRE_FALSE(set_t{1,2,3} > set_t{1,2,3}); + REQUIRE(set_t{1,2,3} >= set_t{1,2,3}); } }