From 797d83fcc899e5d5bf2d5ca9eb68b3cef149a9b8 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Fri, 10 May 2019 07:59:00 +0700 Subject: [PATCH 1/4] EBO for flat_set --- headers/flat_hpp/flat_set.hpp | 66 ++++++++++++++++++----------------- untests/flat_set_tests.cpp | 28 +++++++++++++++ 2 files changed, 62 insertions(+), 32 deletions(-) diff --git a/headers/flat_hpp/flat_set.hpp b/headers/flat_hpp/flat_set.hpp index 6437dc1..e1cdeec 100644 --- a/headers/flat_hpp/flat_set.hpp +++ b/headers/flat_hpp/flat_set.hpp @@ -20,7 +20,8 @@ namespace flat_hpp template < typename Key , typename Compare = std::less , typename Container = std::vector > - class flat_set final { + class flat_set : private Compare { + using base_type = Compare; public: using key_type = Key; using value_type = Key; @@ -45,7 +46,7 @@ namespace flat_hpp flat_set() {} explicit flat_set(const Compare& c) - : compare_(c) {} + : base_type(c) {} template < typename Allocator > explicit flat_set(const Allocator& a) @@ -53,8 +54,8 @@ namespace flat_hpp template < typename Allocator > flat_set(const Compare& c, const Allocator& a) - : data_(a) - , compare_(c) {} + : base_type(c) + , data_(a) {} template < typename InputIter > flat_set(InputIter first, InputIter last) { @@ -63,7 +64,7 @@ namespace flat_hpp template < typename InputIter > flat_set(InputIter first, InputIter last, const Compare& c) - : compare_(c) { + : base_type(c) { insert(first, last); } @@ -75,8 +76,8 @@ namespace flat_hpp template < typename InputIter, typename Allocator > flat_set(InputIter first, InputIter last, const Compare& c, const Allocator& a) - : data_(a) - , compare_(c) { + : base_type(c) + , data_(a) { insert(first, last); } @@ -85,7 +86,7 @@ namespace flat_hpp } flat_set(std::initializer_list ilist, const Compare& c) - : compare_(c) { + : base_type(c) { insert(ilist); } @@ -97,20 +98,20 @@ namespace flat_hpp template < typename Allocator > flat_set(std::initializer_list ilist, const Compare& c, const Allocator& a) - : data_(a) - , compare_(c) { + : base_type(c) + , data_(a) { insert(ilist); } template < typename Allocator > flat_set(flat_set&& other, const Allocator& a) - : data_(std::move(other.data_), a) - , compare_(std::move(other.compare_)) {} + : base_type(static_cast(other)) + , data_(std::move(other.data_), a) {} template < typename Allocator > flat_set(const flat_set& other, const Allocator& a) - : data_(other.data_, a) - , compare_(other.compare_) {} + : base_type(static_cast(other)) + , data_(other.data_, a) {} flat_set(flat_set&& other) = default; flat_set(const flat_set& other) = default; @@ -165,28 +166,28 @@ namespace flat_hpp std::pair insert(value_type&& value) { const iterator iter = lower_bound(value); - return iter == end() || compare_(value, *iter) + return iter == end() || this->operator()(value, *iter) ? 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); - return iter == end() || compare_(value, *iter) + return iter == end() || this->operator()(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)) + return (hint == begin() || this->operator()(*(hint - 1), value)) + && (hint == end() || this->operator()(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)) + return (hint == begin() || this->operator()(*(hint - 1), value)) + && (hint == end() || this->operator()(value, *hint)) ? data_.insert(hint, value) : insert(value).first; } @@ -233,8 +234,10 @@ namespace flat_hpp void swap(flat_set& other) { using std::swap; + swap( + static_cast(*this), + static_cast(other)); swap(data_, other.data_); - swap(compare_, other.compare_); } size_type count(const key_type& key) const { @@ -244,52 +247,51 @@ namespace flat_hpp iterator find(const key_type& key) { const iterator iter = lower_bound(key); - return iter != end() && !compare_(key, *iter) + return iter != end() && !this->operator()(key, *iter) ? iter : end(); } const_iterator find(const key_type& key) const { const const_iterator iter = lower_bound(key); - return iter != end() && !compare_(key, *iter) + return iter != end() && !this->operator()(key, *iter) ? iter : end(); } std::pair equal_range(const key_type& key) { - return std::equal_range(begin(), end(), key, compare_); + return std::equal_range(begin(), end(), key, key_comp()); } std::pair equal_range(const key_type& key) const { - return std::equal_range(begin(), end(), key, compare_); + return std::equal_range(begin(), end(), key, key_comp()); } iterator lower_bound(const key_type& key) { - return std::lower_bound(begin(), end(), key, compare_); + return std::lower_bound(begin(), end(), key, key_comp()); } const_iterator lower_bound(const key_type& key) const { - return std::lower_bound(begin(), end(), key, compare_); + return std::lower_bound(begin(), end(), key, key_comp()); } iterator upper_bound(const key_type& key) { - return std::upper_bound(begin(), end(), key, compare_); + return std::upper_bound(begin(), end(), key, key_comp()); } const_iterator upper_bound(const key_type& key) const { - return std::upper_bound(begin(), end(), key, compare_); + return std::upper_bound(begin(), end(), key, key_comp()); } key_compare key_comp() const { - return compare_; + return *this; } value_compare value_comp() const { - return value_compare(compare_); + return value_compare(key_comp()); } private: container_type data_; - Compare compare_; }; } diff --git a/untests/flat_set_tests.cpp b/untests/flat_set_tests.cpp index ad7c508..8c4b98d 100644 --- a/untests/flat_set_tests.cpp +++ b/untests/flat_set_tests.cpp @@ -70,6 +70,16 @@ namespace return !(l == r); } + template < typename T > + class dummy_less { + public: + dummy_less(int i) : i(i) {} + bool operator()(const T& l, const T& r) const { + return l < r; + } + int i = 0; + }; + template < typename T > constexpr std::add_const_t& my_as_const(T& t) noexcept { return t; @@ -77,6 +87,14 @@ namespace } TEST_CASE("flat_set") { + SECTION("sizeof") { + REQUIRE(sizeof(flat_set) == sizeof(std::vector)); + + struct vc : flat_set::value_compare { + int i; + }; + REQUIRE(sizeof(vc) == sizeof(int)); + } SECTION("types") { using set_t = flat_set; @@ -390,6 +408,16 @@ TEST_CASE("flat_set") { REQUIRE(my_as_const(s0).key_comp().i == 42); REQUIRE(my_as_const(s0).value_comp().i == 42); } + SECTION("custom_less") { + using set_t = flat_set>; + auto s0 = set_t(dummy_less(42)); + auto s1 = set_t(dummy_less(21)); + REQUIRE(s0.key_comp().i == 42); + REQUIRE(s1.key_comp().i == 21); + s0.swap(s1); + REQUIRE(s0.key_comp().i == 21); + REQUIRE(s1.key_comp().i == 42); + } SECTION("operators") { using set_t = flat_set; From 13dc07cd155a243a3049ad86e61bef4a376f0604 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Fri, 10 May 2019 08:59:03 +0700 Subject: [PATCH 2/4] EBO for flat_map --- headers/flat_hpp/flat_map.hpp | 144 ++++++++++++++++++++-------------- untests/flat_map_tests.cpp | 28 +++++++ 2 files changed, 114 insertions(+), 58 deletions(-) diff --git a/headers/flat_hpp/flat_map.hpp b/headers/flat_hpp/flat_map.hpp index b531731..85718a1 100644 --- a/headers/flat_hpp/flat_map.hpp +++ b/headers/flat_hpp/flat_map.hpp @@ -17,32 +17,55 @@ namespace flat_hpp { + namespace detail + { + template < typename Value, typename Compare > + class flat_map_compare : public Compare { + public: + flat_map_compare() = default; + + flat_map_compare(const Compare& compare) + : Compare(compare) {} + + bool operator()( + const typename Value::first_type& l, + const typename Value::first_type& r) const + { + return Compare::operator()(l, r); + } + + bool operator()( + const typename Value::first_type& l, + const Value& r) const + { + return Compare::operator()(l, r.first); + } + + bool operator()( + const Value& l, + const typename Value::first_type& r) const + { + return Compare::operator()(l.first, r); + } + + bool operator()(const Value& l, const Value& r) const { + return Compare::operator()(l.first, r.first); + } + }; + } + template < typename Key , typename Value , typename Compare = std::less , typename Container = std::vector> > - class flat_map final { - 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); - } - - bool operator()(const Key& l, typename Container::const_reference r) const { - return Compare::operator()(l, r.first); - } - - bool operator()(typename Container::const_reference l, const Key& r) const { - return Compare::operator()(l.first, r); - } - - bool operator()(typename Container::const_reference l, typename Container::const_reference r) const { - return Compare::operator()(l.first, r.first); - } - }; + class flat_map + : private detail::flat_map_compare< + typename Container::value_type, + Compare> + { + using base_type = detail::flat_map_compare< + typename Container::value_type, + Compare>; public: using key_type = Key; using mapped_type = Value; @@ -64,23 +87,21 @@ namespace flat_hpp using reverse_iterator = typename Container::reverse_iterator; using const_reverse_iterator = typename Container::const_reverse_iterator; - class value_compare { + class value_compare : private key_compare { public: bool operator()(const value_type& l, const value_type& r) const { - return compare_(l.first, r.first); + return key_compare::operator()(l.first, r.first); } protected: friend class flat_map; explicit value_compare(key_compare compare) - : compare_(std::move(compare)) {} - private: - key_compare compare_; + : key_compare(std::move(compare)) {} }; public: flat_map() {} explicit flat_map(const Compare& c) - : compare_(c) {} + : base_type(c) {} template < typename Allocator > explicit flat_map(const Allocator& a) @@ -88,8 +109,8 @@ namespace flat_hpp template < typename Allocator > flat_map(const Compare& c, const Allocator& a) - : data_(a) - , compare_(c) {} + : base_type(c) + , data_(a) {} template < typename InputIter > flat_map(InputIter first, InputIter last) { @@ -98,7 +119,7 @@ namespace flat_hpp template < typename InputIter > flat_map(InputIter first, InputIter last, const Compare& c) - : compare_(c) { + : base_type(c) { insert(first, last); } @@ -110,8 +131,8 @@ namespace flat_hpp template < typename InputIter , typename Allocator > flat_map(InputIter first, InputIter last, const Compare& c, const Allocator& a) - : data_(a) - , compare_(c) { + : base_type(c) + , data_(a) { insert(first, last); } @@ -120,7 +141,7 @@ namespace flat_hpp } flat_map(std::initializer_list ilist, const Compare& c) - : compare_(c) { + : base_type(c) { insert(ilist); } @@ -132,20 +153,20 @@ namespace flat_hpp template < typename Allocator > flat_map(std::initializer_list ilist, const Compare& c, const Allocator& a) - : data_(a) - , compare_(c) { + : base_type(c) + , data_(a) { insert(ilist); } template < typename Allocator > flat_map(flat_map&& other, const Allocator& a) - : data_(std::move(other.data_), a) - , compare_(std::move(other.compare_)) {} + : base_type(static_cast(other)) + , data_(std::move(other.data_), a) {} template < typename Allocator > flat_map(const flat_map& other, const Allocator& a) - : data_(other.data_, a) - , compare_(other.compare_) {} + : base_type(static_cast(other)) + , data_(other.data_, a) {} flat_map(flat_map&& other) = default; flat_map(const flat_map& other) = default; @@ -230,28 +251,28 @@ namespace flat_hpp std::pair insert(value_type&& value) { const iterator iter = lower_bound(value.first); - return iter == end() || compare_(value, *iter) + return iter == end() || this->operator()(value, *iter) ? 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, *iter) + return iter == end() || this->operator()(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)) + return (hint == begin() || this->operator()(*(hint - 1), value)) + && (hint == end() || this->operator()(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)) + return (hint == begin() || this->operator()(*(hint - 1), value)) + && (hint == end() || this->operator()(value, *hint)) ? data_.insert(hint, value) : insert(value).first; } @@ -298,8 +319,10 @@ namespace flat_hpp void swap(flat_map& other) { using std::swap; + swap( + static_cast(*this), + static_cast(other)); swap(data_, other.data_); - swap(compare_, other.compare_); } size_type count(const key_type& key) const { @@ -309,52 +332,57 @@ namespace flat_hpp iterator find(const key_type& key) { const iterator iter = lower_bound(key); - return iter != end() && !compare_(key, iter->first) + return iter != end() && !this->operator()(key, iter->first) ? iter : end(); } const_iterator find(const key_type& key) const { const const_iterator iter = lower_bound(key); - return iter != end() && !compare_(key, iter->first) + return iter != end() && !this->operator()(key, iter->first) ? iter : end(); } std::pair equal_range(const key_type& key) { - return std::equal_range(begin(), end(), key, compare_); + const base_type& comp = *this; + return std::equal_range(begin(), end(), key, comp); } std::pair equal_range(const key_type& key) const { - return std::equal_range(begin(), end(), key, compare_); + const base_type& comp = *this; + return std::equal_range(begin(), end(), key, comp); } iterator lower_bound(const key_type& key) { - return std::lower_bound(begin(), end(), key, compare_); + const base_type& comp = *this; + return std::lower_bound(begin(), end(), key, comp); } const_iterator lower_bound(const key_type& key) const { - return std::lower_bound(begin(), end(), key, compare_); + const base_type& comp = *this; + return std::lower_bound(begin(), end(), key, comp); } iterator upper_bound(const key_type& key) { - return std::upper_bound(begin(), end(), key, compare_); + const base_type& comp = *this; + return std::upper_bound(begin(), end(), key, comp); } const_iterator upper_bound(const key_type& key) const { - return std::upper_bound(begin(), end(), key, compare_); + const base_type& comp = *this; + return std::upper_bound(begin(), end(), key, comp); } key_compare key_comp() const { - return compare_; + return *this; } value_compare value_comp() const { - return value_compare(compare_); + return value_compare(key_comp()); } private: container_type data_; - uber_comparer_type compare_; }; } diff --git a/untests/flat_map_tests.cpp b/untests/flat_map_tests.cpp index eacca10..8e79f08 100644 --- a/untests/flat_map_tests.cpp +++ b/untests/flat_map_tests.cpp @@ -70,6 +70,16 @@ namespace return !(l == r); } + template < typename T > + class dummy_less { + public: + dummy_less(int i) : i(i) {} + bool operator()(const T& l, const T& r) const { + return l < r; + } + int i = 0; + }; + template < typename T > constexpr std::add_const_t& my_as_const(T& t) noexcept { return t; @@ -77,6 +87,14 @@ namespace } TEST_CASE("flat_map") { + SECTION("sizeof") { + REQUIRE(sizeof(flat_map) == sizeof(std::vector>)); + + struct vc : flat_map::value_compare { + int i; + }; + REQUIRE(sizeof(vc) == sizeof(int)); + } SECTION("types") { using map_t = flat_map; @@ -416,6 +434,16 @@ TEST_CASE("flat_map") { REQUIRE(my_as_const(s0).key_comp().i == 42); REQUIRE(my_as_const(s0).value_comp()({2,50},{4,20})); } + SECTION("custom_less") { + using map_t = flat_map>; + auto s0 = map_t(dummy_less(42)); + auto s1 = map_t(dummy_less(21)); + REQUIRE(s0.key_comp().i == 42); + REQUIRE(s1.key_comp().i == 21); + s0.swap(s1); + REQUIRE(s0.key_comp().i == 21); + REQUIRE(s1.key_comp().i == 42); + } SECTION("operators") { using map_t = flat_map; From 519abd69a4d495558488a16549a122b591464da9 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Fri, 10 May 2019 09:12:32 +0700 Subject: [PATCH 3/4] EBO for multiset and multimap --- headers/flat_hpp/flat_multimap.hpp | 140 +++++++++++++++++------------ headers/flat_hpp/flat_multiset.hpp | 62 ++++++------- untests/flat_multimap_tests.cpp | 28 ++++++ untests/flat_multiset_tests.cpp | 28 ++++++ 4 files changed, 172 insertions(+), 86 deletions(-) diff --git a/headers/flat_hpp/flat_multimap.hpp b/headers/flat_hpp/flat_multimap.hpp index c705cd9..27bedee 100644 --- a/headers/flat_hpp/flat_multimap.hpp +++ b/headers/flat_hpp/flat_multimap.hpp @@ -17,32 +17,55 @@ namespace flat_hpp { + namespace detail + { + template < typename Value, typename Compare > + class flat_multimap_compare : public Compare { + public: + flat_multimap_compare() = default; + + flat_multimap_compare(const Compare& compare) + : Compare(compare) {} + + bool operator()( + const typename Value::first_type& l, + const typename Value::first_type& r) const + { + return Compare::operator()(l, r); + } + + bool operator()( + const typename Value::first_type& l, + const Value& r) const + { + return Compare::operator()(l, r.first); + } + + bool operator()( + const Value& l, + const typename Value::first_type& r) const + { + return Compare::operator()(l.first, r); + } + + bool operator()(const Value& l, const Value& r) const { + return Compare::operator()(l.first, r.first); + } + }; + } + template < typename Key , typename Value , typename Compare = std::less , typename Container = std::vector> > - class flat_multimap final { - 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); - } - - bool operator()(const Key& l, typename Container::const_reference r) const { - return Compare::operator()(l, r.first); - } - - bool operator()(typename Container::const_reference l, const Key& r) const { - return Compare::operator()(l.first, r); - } - - bool operator()(typename Container::const_reference l, typename Container::const_reference r) const { - return Compare::operator()(l.first, r.first); - } - }; + class flat_multimap + : private detail::flat_multimap_compare< + typename Container::value_type, + Compare> + { + using base_type = detail::flat_multimap_compare< + typename Container::value_type, + Compare>; public: using key_type = Key; using mapped_type = Value; @@ -64,23 +87,21 @@ namespace flat_hpp using reverse_iterator = typename Container::reverse_iterator; using const_reverse_iterator = typename Container::const_reverse_iterator; - class value_compare { + class value_compare : private key_compare { public: bool operator()(const value_type& l, const value_type& r) const { - return compare_(l.first, r.first); + return key_compare::operator()(l.first, r.first); } protected: friend class flat_multimap; explicit value_compare(key_compare compare) - : compare_(std::move(compare)) {} - private: - key_compare compare_; + : key_compare(std::move(compare)) {} }; public: flat_multimap() {} explicit flat_multimap(const Compare& c) - : compare_(c) {} + : base_type(c) {} template < typename Allocator > explicit flat_multimap(const Allocator& a) @@ -88,8 +109,8 @@ namespace flat_hpp template < typename Allocator > flat_multimap(const Compare& c, const Allocator& a) - : data_(a) - , compare_(c) {} + : base_type(c) + , data_(a) {} template < typename InputIter > flat_multimap(InputIter first, InputIter last) { @@ -98,7 +119,7 @@ namespace flat_hpp template < typename InputIter > flat_multimap(InputIter first, InputIter last, const Compare& c) - : compare_(c) { + : base_type(c) { insert(first, last); } @@ -110,8 +131,8 @@ namespace flat_hpp template < typename InputIter , typename Allocator > flat_multimap(InputIter first, InputIter last, const Compare& c, const Allocator& a) - : data_(a) - , compare_(c) { + : base_type(c) + , data_(a) { insert(first, last); } @@ -120,7 +141,7 @@ namespace flat_hpp } flat_multimap(std::initializer_list ilist, const Compare& c) - : compare_(c) { + : base_type(c) { insert(ilist); } @@ -132,20 +153,20 @@ namespace flat_hpp template < typename Allocator > flat_multimap(std::initializer_list ilist, const Compare& c, const Allocator& a) - : data_(a) - , compare_(c) { + : base_type(c) + , data_(a) { insert(ilist); } template < typename Allocator > flat_multimap(flat_multimap&& other, const Allocator& a) - : data_(std::move(other.data_), a) - , compare_(std::move(other.compare_)) {} + : base_type(static_cast(other)) + , data_(std::move(other.data_), a) {} template < typename Allocator > flat_multimap(const flat_multimap& other, const Allocator& a) - : data_(other.data_, a) - , compare_(other.compare_) {} + : base_type(static_cast(other)) + , data_(other.data_, a) {} flat_multimap(flat_multimap&& other) = default; flat_multimap(const flat_multimap& other) = default; @@ -239,15 +260,15 @@ namespace flat_hpp } iterator insert(const_iterator hint, value_type&& value) { - return (hint == begin() || !compare_(value, *(hint - 1))) - && (hint == end() || !compare_(*hint, value)) + return (hint == begin() || !this->operator()(value, *(hint - 1))) + && (hint == end() || !this->operator()(*hint, value)) ? data_.insert(hint, std::move(value)) : insert(std::move(value)); } iterator insert(const_iterator hint, const value_type& value) { - return (hint == begin() || !compare_(value, *(hint - 1))) - && (hint == end() || !compare_(*hint, value)) + return (hint == begin() || !this->operator()(value, *(hint - 1))) + && (hint == end() || !this->operator()(*hint, value)) ? data_.insert(hint, value) : insert(value); } @@ -294,8 +315,10 @@ namespace flat_hpp void swap(flat_multimap& other) { using std::swap; + swap( + static_cast(*this), + static_cast(other)); swap(data_, other.data_); - swap(compare_, other.compare_); } size_type count(const key_type& key) const { @@ -305,52 +328,57 @@ namespace flat_hpp iterator find(const key_type& key) { const iterator iter = lower_bound(key); - return iter != end() && !compare_(key, iter->first) + return iter != end() && !this->operator()(key, iter->first) ? iter : end(); } const_iterator find(const key_type& key) const { const const_iterator iter = lower_bound(key); - return iter != end() && !compare_(key, iter->first) + return iter != end() && !this->operator()(key, iter->first) ? iter : end(); } std::pair equal_range(const key_type& key) { - return std::equal_range(begin(), end(), key, compare_); + const base_type& comp = *this; + return std::equal_range(begin(), end(), key, comp); } std::pair equal_range(const key_type& key) const { - return std::equal_range(begin(), end(), key, compare_); + const base_type& comp = *this; + return std::equal_range(begin(), end(), key, comp); } iterator lower_bound(const key_type& key) { - return std::lower_bound(begin(), end(), key, compare_); + const base_type& comp = *this; + return std::lower_bound(begin(), end(), key, comp); } const_iterator lower_bound(const key_type& key) const { - return std::lower_bound(begin(), end(), key, compare_); + const base_type& comp = *this; + return std::lower_bound(begin(), end(), key, comp); } iterator upper_bound(const key_type& key) { - return std::upper_bound(begin(), end(), key, compare_); + const base_type& comp = *this; + return std::upper_bound(begin(), end(), key, comp); } const_iterator upper_bound(const key_type& key) const { - return std::upper_bound(begin(), end(), key, compare_); + const base_type& comp = *this; + return std::upper_bound(begin(), end(), key, comp); } key_compare key_comp() const { - return compare_; + return *this; } value_compare value_comp() const { - return value_compare(compare_); + return value_compare(key_comp()); } private: container_type data_; - uber_comparer_type compare_; }; } diff --git a/headers/flat_hpp/flat_multiset.hpp b/headers/flat_hpp/flat_multiset.hpp index d4250f0..a87fdf6 100644 --- a/headers/flat_hpp/flat_multiset.hpp +++ b/headers/flat_hpp/flat_multiset.hpp @@ -20,7 +20,8 @@ namespace flat_hpp template < typename Key , typename Compare = std::less , typename Container = std::vector > - class flat_multiset final { + class flat_multiset : private Compare { + using base_type = Compare; public: using key_type = Key; using value_type = Key; @@ -45,7 +46,7 @@ namespace flat_hpp flat_multiset() {} explicit flat_multiset(const Compare& c) - : compare_(c) {} + : base_type(c) {} template < typename Allocator > explicit flat_multiset(const Allocator& a) @@ -53,8 +54,8 @@ namespace flat_hpp template < typename Allocator > flat_multiset(const Compare& c, const Allocator& a) - : data_(a) - , compare_(c) {} + : base_type(c) + , data_(a) {} template < typename InputIter > flat_multiset(InputIter first, InputIter last) { @@ -63,7 +64,7 @@ namespace flat_hpp template < typename InputIter > flat_multiset(InputIter first, InputIter last, const Compare& c) - : compare_(c) { + : base_type(c) { insert(first, last); } @@ -75,8 +76,8 @@ namespace flat_hpp template < typename InputIter, typename Allocator > flat_multiset(InputIter first, InputIter last, const Compare& c, const Allocator& a) - : data_(a) - , compare_(c) { + : base_type(c) + , data_(a) { insert(first, last); } @@ -85,7 +86,7 @@ namespace flat_hpp } flat_multiset(std::initializer_list ilist, const Compare& c) - : compare_(c) { + : base_type(c) { insert(ilist); } @@ -97,20 +98,20 @@ namespace flat_hpp template < typename Allocator > flat_multiset(std::initializer_list ilist, const Compare& c, const Allocator& a) - : data_(a) - , compare_(c) { + : base_type(c) + , data_(a) { insert(ilist); } template < typename Allocator > flat_multiset(flat_multiset&& other, const Allocator& a) - : data_(std::move(other.data_), a) - , compare_(std::move(other.compare_)) {} + : base_type(static_cast(other)) + , data_(std::move(other.data_), a) {} template < typename Allocator > flat_multiset(const flat_multiset& other, const Allocator& a) - : data_(other.data_, a) - , compare_(other.compare_) {} + : base_type(static_cast(other)) + , data_(other.data_, a) {} flat_multiset(flat_multiset&& other) = default; flat_multiset(const flat_multiset& other) = default; @@ -174,15 +175,15 @@ namespace flat_hpp } iterator insert(const_iterator hint, value_type&& value) { - return (hint == begin() || !compare_(value, *(hint - 1))) - && (hint == end() || !compare_(*hint, value)) + return (hint == begin() || !this->operator()(value, *(hint - 1))) + && (hint == end() || !this->operator()(*hint, value)) ? data_.insert(hint, std::move(value)) : insert(std::move(value)); } iterator insert(const_iterator hint, const value_type& value) { - return (hint == begin() || !compare_(value, *(hint - 1))) - && (hint == end() || !compare_(*hint, value)) + return (hint == begin() || !this->operator()(value, *(hint - 1))) + && (hint == end() || !this->operator()(*hint, value)) ? data_.insert(hint, value) : insert(value); } @@ -229,8 +230,10 @@ namespace flat_hpp void swap(flat_multiset& other) { using std::swap; + swap( + static_cast(*this), + static_cast(other)); swap(data_, other.data_); - swap(compare_, other.compare_); } size_type count(const key_type& key) const { @@ -240,52 +243,51 @@ namespace flat_hpp iterator find(const key_type& key) { const iterator iter = lower_bound(key); - return iter != end() && !compare_(key, *iter) + return iter != end() && !this->operator()(key, *iter) ? iter : end(); } const_iterator find(const key_type& key) const { const const_iterator iter = lower_bound(key); - return iter != end() && !compare_(key, *iter) + return iter != end() && !this->operator()(key, *iter) ? iter : end(); } std::pair equal_range(const key_type& key) { - return std::equal_range(begin(), end(), key, compare_); + return std::equal_range(begin(), end(), key, key_comp()); } std::pair equal_range(const key_type& key) const { - return std::equal_range(begin(), end(), key, compare_); + return std::equal_range(begin(), end(), key, key_comp()); } iterator lower_bound(const key_type& key) { - return std::lower_bound(begin(), end(), key, compare_); + return std::lower_bound(begin(), end(), key, key_comp()); } const_iterator lower_bound(const key_type& key) const { - return std::lower_bound(begin(), end(), key, compare_); + return std::lower_bound(begin(), end(), key, key_comp()); } iterator upper_bound(const key_type& key) { - return std::upper_bound(begin(), end(), key, compare_); + return std::upper_bound(begin(), end(), key, key_comp()); } const_iterator upper_bound(const key_type& key) const { - return std::upper_bound(begin(), end(), key, compare_); + return std::upper_bound(begin(), end(), key, key_comp()); } key_compare key_comp() const { - return compare_; + return *this; } value_compare value_comp() const { - return value_compare(compare_); + return value_compare(key_comp()); } private: container_type data_; - Compare compare_; }; } diff --git a/untests/flat_multimap_tests.cpp b/untests/flat_multimap_tests.cpp index f3e024a..99bfa2e 100644 --- a/untests/flat_multimap_tests.cpp +++ b/untests/flat_multimap_tests.cpp @@ -70,6 +70,16 @@ namespace return !(l == r); } + template < typename T > + class dummy_less { + public: + dummy_less(int i) : i(i) {} + bool operator()(const T& l, const T& r) const { + return l < r; + } + int i = 0; + }; + template < typename T > constexpr std::add_const_t& my_as_const(T& t) noexcept { return t; @@ -77,6 +87,14 @@ namespace } TEST_CASE("flat_multimap") { + SECTION("sizeof") { + REQUIRE(sizeof(flat_multimap) == sizeof(std::vector>)); + + struct vc : flat_multimap::value_compare { + int i; + }; + REQUIRE(sizeof(vc) == sizeof(int)); + } SECTION("types") { using map_t = flat_multimap; @@ -418,6 +436,16 @@ TEST_CASE("flat_multimap") { REQUIRE(my_as_const(s0).key_comp().i == 42); REQUIRE(my_as_const(s0).value_comp()({2,50},{4,20})); } + SECTION("custom_less") { + using map_t = flat_multimap>; + auto s0 = map_t(dummy_less(42)); + auto s1 = map_t(dummy_less(21)); + REQUIRE(s0.key_comp().i == 42); + REQUIRE(s1.key_comp().i == 21); + s0.swap(s1); + REQUIRE(s0.key_comp().i == 21); + REQUIRE(s1.key_comp().i == 42); + } SECTION("operators") { using map_t = flat_multimap; diff --git a/untests/flat_multiset_tests.cpp b/untests/flat_multiset_tests.cpp index d25a23d..35dc06f 100644 --- a/untests/flat_multiset_tests.cpp +++ b/untests/flat_multiset_tests.cpp @@ -70,6 +70,16 @@ namespace return !(l == r); } + template < typename T > + class dummy_less { + public: + dummy_less(int i) : i(i) {} + bool operator()(const T& l, const T& r) const { + return l < r; + } + int i = 0; + }; + template < typename T > constexpr std::add_const_t& my_as_const(T& t) noexcept { return t; @@ -77,6 +87,14 @@ namespace } TEST_CASE("flat_multiset") { + SECTION("sizeof") { + REQUIRE(sizeof(flat_multiset) == sizeof(std::vector)); + + struct vc : flat_multiset::value_compare { + int i; + }; + REQUIRE(sizeof(vc) == sizeof(int)); + } SECTION("types") { using set_t = flat_multiset; @@ -392,6 +410,16 @@ TEST_CASE("flat_multiset") { REQUIRE(my_as_const(s0).key_comp().i == 42); REQUIRE(my_as_const(s0).value_comp().i == 42); } + SECTION("custom_less") { + using set_t = flat_multiset>; + auto s0 = set_t(dummy_less(42)); + auto s1 = set_t(dummy_less(21)); + REQUIRE(s0.key_comp().i == 42); + REQUIRE(s1.key_comp().i == 21); + s0.swap(s1); + REQUIRE(s0.key_comp().i == 21); + REQUIRE(s1.key_comp().i == 42); + } SECTION("operators") { using set_t = flat_multiset; From 47b24bb0adde70db5d205697211a354eb73ee1ae Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Fri, 10 May 2019 10:06:14 +0700 Subject: [PATCH 4/4] add default ctor noexcept --- headers/flat_hpp/flat_map.hpp | 4 +++- headers/flat_hpp/flat_multimap.hpp | 4 +++- headers/flat_hpp/flat_multiset.hpp | 4 +++- headers/flat_hpp/flat_set.hpp | 4 +++- untests/flat_map_tests.cpp | 17 ++++++++++++++++- untests/flat_multimap_tests.cpp | 17 ++++++++++++++++- untests/flat_multiset_tests.cpp | 17 ++++++++++++++++- untests/flat_set_tests.cpp | 17 ++++++++++++++++- 8 files changed, 76 insertions(+), 8 deletions(-) diff --git a/headers/flat_hpp/flat_map.hpp b/headers/flat_hpp/flat_map.hpp index 85718a1..191e310 100644 --- a/headers/flat_hpp/flat_map.hpp +++ b/headers/flat_hpp/flat_map.hpp @@ -98,7 +98,9 @@ namespace flat_hpp : key_compare(std::move(compare)) {} }; public: - flat_map() {} + flat_map() + noexcept(std::is_nothrow_default_constructible::value + && std::is_nothrow_default_constructible::value) {} explicit flat_map(const Compare& c) : base_type(c) {} diff --git a/headers/flat_hpp/flat_multimap.hpp b/headers/flat_hpp/flat_multimap.hpp index 27bedee..f6b5b7b 100644 --- a/headers/flat_hpp/flat_multimap.hpp +++ b/headers/flat_hpp/flat_multimap.hpp @@ -98,7 +98,9 @@ namespace flat_hpp : key_compare(std::move(compare)) {} }; public: - flat_multimap() {} + flat_multimap() + noexcept(std::is_nothrow_default_constructible::value + && std::is_nothrow_default_constructible::value) {} explicit flat_multimap(const Compare& c) : base_type(c) {} diff --git a/headers/flat_hpp/flat_multiset.hpp b/headers/flat_hpp/flat_multiset.hpp index a87fdf6..a3b9c17 100644 --- a/headers/flat_hpp/flat_multiset.hpp +++ b/headers/flat_hpp/flat_multiset.hpp @@ -43,7 +43,9 @@ namespace flat_hpp using reverse_iterator = typename Container::const_reverse_iterator; using const_reverse_iterator = typename Container::const_reverse_iterator; public: - flat_multiset() {} + flat_multiset() + noexcept(std::is_nothrow_default_constructible::value + && std::is_nothrow_default_constructible::value) {} explicit flat_multiset(const Compare& c) : base_type(c) {} diff --git a/headers/flat_hpp/flat_set.hpp b/headers/flat_hpp/flat_set.hpp index e1cdeec..7d53d76 100644 --- a/headers/flat_hpp/flat_set.hpp +++ b/headers/flat_hpp/flat_set.hpp @@ -43,7 +43,9 @@ namespace flat_hpp using reverse_iterator = typename Container::const_reverse_iterator; using const_reverse_iterator = typename Container::const_reverse_iterator; public: - flat_set() {} + flat_set() + noexcept(std::is_nothrow_default_constructible::value + && std::is_nothrow_default_constructible::value) {} explicit flat_set(const Compare& c) : base_type(c) {} diff --git a/untests/flat_map_tests.cpp b/untests/flat_map_tests.cpp index 8e79f08..8c59382 100644 --- a/untests/flat_map_tests.cpp +++ b/untests/flat_map_tests.cpp @@ -73,7 +73,8 @@ namespace template < typename T > class dummy_less { public: - dummy_less(int i) : i(i) {} + dummy_less() = default; + dummy_less(int i) noexcept : i(i) {} bool operator()(const T& l, const T& r) const { return l < r; } @@ -95,6 +96,20 @@ TEST_CASE("flat_map") { }; REQUIRE(sizeof(vc) == sizeof(int)); } + SECTION("noexcept") { + using alloc_t = dummy_allocator>; + using map_t = flat_map, std::vector, alloc_t>>; + + static_assert( + std::is_nothrow_default_constructible::value, + "unit test static error"); + static_assert( + std::is_nothrow_move_constructible::value, + "unit test static error"); + static_assert( + std::is_nothrow_move_assignable::value, + "unit test static error"); + } SECTION("types") { using map_t = flat_map; diff --git a/untests/flat_multimap_tests.cpp b/untests/flat_multimap_tests.cpp index 99bfa2e..9f23252 100644 --- a/untests/flat_multimap_tests.cpp +++ b/untests/flat_multimap_tests.cpp @@ -73,7 +73,8 @@ namespace template < typename T > class dummy_less { public: - dummy_less(int i) : i(i) {} + dummy_less() = default; + dummy_less(int i) noexcept : i(i) {} bool operator()(const T& l, const T& r) const { return l < r; } @@ -95,6 +96,20 @@ TEST_CASE("flat_multimap") { }; REQUIRE(sizeof(vc) == sizeof(int)); } + SECTION("noexcept") { + using alloc_t = dummy_allocator>; + using map_t = flat_multimap, std::vector, alloc_t>>; + + static_assert( + std::is_nothrow_default_constructible::value, + "unit test static error"); + static_assert( + std::is_nothrow_move_constructible::value, + "unit test static error"); + static_assert( + std::is_nothrow_move_assignable::value, + "unit test static error"); + } SECTION("types") { using map_t = flat_multimap; diff --git a/untests/flat_multiset_tests.cpp b/untests/flat_multiset_tests.cpp index 35dc06f..b3e6bb2 100644 --- a/untests/flat_multiset_tests.cpp +++ b/untests/flat_multiset_tests.cpp @@ -73,7 +73,8 @@ namespace template < typename T > class dummy_less { public: - dummy_less(int i) : i(i) {} + dummy_less() = default; + dummy_less(int i) noexcept : i(i) {} bool operator()(const T& l, const T& r) const { return l < r; } @@ -95,6 +96,20 @@ TEST_CASE("flat_multiset") { }; REQUIRE(sizeof(vc) == sizeof(int)); } + SECTION("noexcept") { + using alloc_t = dummy_allocator; + using set_t = flat_multiset, std::vector>; + + static_assert( + std::is_nothrow_default_constructible::value, + "unit test static error"); + static_assert( + std::is_nothrow_move_constructible::value, + "unit test static error"); + static_assert( + std::is_nothrow_move_assignable::value, + "unit test static error"); + } SECTION("types") { using set_t = flat_multiset; diff --git a/untests/flat_set_tests.cpp b/untests/flat_set_tests.cpp index 8c4b98d..18f1e80 100644 --- a/untests/flat_set_tests.cpp +++ b/untests/flat_set_tests.cpp @@ -73,7 +73,8 @@ namespace template < typename T > class dummy_less { public: - dummy_less(int i) : i(i) {} + dummy_less() = default; + dummy_less(int i) noexcept : i(i) {} bool operator()(const T& l, const T& r) const { return l < r; } @@ -95,6 +96,20 @@ TEST_CASE("flat_set") { }; REQUIRE(sizeof(vc) == sizeof(int)); } + SECTION("noexcept") { + using alloc_t = dummy_allocator; + using set_t = flat_set, std::vector>; + + static_assert( + std::is_nothrow_default_constructible::value, + "unit test static error"); + static_assert( + std::is_nothrow_move_constructible::value, + "unit test static error"); + static_assert( + std::is_nothrow_move_assignable::value, + "unit test static error"); + } SECTION("types") { using set_t = flat_set;