EBO for flat_set

This commit is contained in:
2019-05-10 07:59:00 +07:00
parent 02b780b9da
commit 797d83fcc8
2 changed files with 62 additions and 32 deletions

View File

@@ -20,7 +20,8 @@ namespace flat_hpp
template < typename Key template < typename Key
, typename Compare = std::less<Key> , typename Compare = std::less<Key>
, typename Container = std::vector<Key> > , typename Container = std::vector<Key> >
class flat_set final { class flat_set : private Compare {
using base_type = Compare;
public: public:
using key_type = Key; using key_type = Key;
using value_type = Key; using value_type = Key;
@@ -45,7 +46,7 @@ namespace flat_hpp
flat_set() {} flat_set() {}
explicit flat_set(const Compare& c) explicit flat_set(const Compare& c)
: compare_(c) {} : base_type(c) {}
template < typename Allocator > template < typename Allocator >
explicit flat_set(const Allocator& a) explicit flat_set(const Allocator& a)
@@ -53,8 +54,8 @@ namespace flat_hpp
template < typename Allocator > template < typename Allocator >
flat_set(const Compare& c, const Allocator& a) flat_set(const Compare& c, const Allocator& a)
: data_(a) : base_type(c)
, compare_(c) {} , data_(a) {}
template < typename InputIter > template < typename InputIter >
flat_set(InputIter first, InputIter last) { flat_set(InputIter first, InputIter last) {
@@ -63,7 +64,7 @@ namespace flat_hpp
template < typename InputIter > template < typename InputIter >
flat_set(InputIter first, InputIter last, const Compare& c) flat_set(InputIter first, InputIter last, const Compare& c)
: compare_(c) { : base_type(c) {
insert(first, last); insert(first, last);
} }
@@ -75,8 +76,8 @@ namespace flat_hpp
template < typename InputIter, typename Allocator > template < typename InputIter, typename Allocator >
flat_set(InputIter first, InputIter last, const Compare& c, const Allocator& a) flat_set(InputIter first, InputIter last, const Compare& c, const Allocator& a)
: data_(a) : base_type(c)
, compare_(c) { , data_(a) {
insert(first, last); insert(first, last);
} }
@@ -85,7 +86,7 @@ namespace flat_hpp
} }
flat_set(std::initializer_list<value_type> ilist, const Compare& c) flat_set(std::initializer_list<value_type> ilist, const Compare& c)
: compare_(c) { : base_type(c) {
insert(ilist); insert(ilist);
} }
@@ -97,20 +98,20 @@ namespace flat_hpp
template < typename Allocator > template < typename Allocator >
flat_set(std::initializer_list<value_type> ilist, const Compare& c, const Allocator& a) flat_set(std::initializer_list<value_type> ilist, const Compare& c, const Allocator& a)
: data_(a) : base_type(c)
, compare_(c) { , data_(a) {
insert(ilist); insert(ilist);
} }
template < typename Allocator > template < typename Allocator >
flat_set(flat_set&& other, const Allocator& a) flat_set(flat_set&& other, const Allocator& a)
: data_(std::move(other.data_), a) : base_type(static_cast<base_type&&>(other))
, compare_(std::move(other.compare_)) {} , data_(std::move(other.data_), a) {}
template < typename Allocator > template < typename Allocator >
flat_set(const flat_set& other, const Allocator& a) flat_set(const flat_set& other, const Allocator& a)
: data_(other.data_, a) : base_type(static_cast<const base_type&>(other))
, compare_(other.compare_) {} , data_(other.data_, a) {}
flat_set(flat_set&& other) = default; flat_set(flat_set&& other) = default;
flat_set(const flat_set& other) = default; flat_set(const flat_set& other) = default;
@@ -165,28 +166,28 @@ namespace flat_hpp
std::pair<iterator, bool> insert(value_type&& value) { std::pair<iterator, bool> insert(value_type&& value) {
const iterator iter = lower_bound(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(data_.insert(iter, std::move(value)), true)
: std::make_pair(iter, false); : std::make_pair(iter, false);
} }
std::pair<iterator, bool> insert(const value_type& value) { std::pair<iterator, bool> insert(const value_type& value) {
const iterator iter = lower_bound(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(data_.insert(iter, value), true)
: std::make_pair(iter, false); : std::make_pair(iter, false);
} }
iterator insert(const_iterator hint, value_type&& value) { iterator insert(const_iterator hint, value_type&& value) {
return (hint == begin() || compare_(*(hint - 1), value)) return (hint == begin() || this->operator()(*(hint - 1), value))
&& (hint == end() || compare_(value, *hint)) && (hint == end() || this->operator()(value, *hint))
? data_.insert(hint, std::move(value)) ? data_.insert(hint, std::move(value))
: insert(std::move(value)).first; : insert(std::move(value)).first;
} }
iterator insert(const_iterator hint, const value_type& value) { iterator insert(const_iterator hint, const value_type& value) {
return (hint == begin() || compare_(*(hint - 1), value)) return (hint == begin() || this->operator()(*(hint - 1), value))
&& (hint == end() || compare_(value, *hint)) && (hint == end() || this->operator()(value, *hint))
? data_.insert(hint, value) ? data_.insert(hint, value)
: insert(value).first; : insert(value).first;
} }
@@ -233,8 +234,10 @@ namespace flat_hpp
void swap(flat_set& other) { void swap(flat_set& other) {
using std::swap; using std::swap;
swap(
static_cast<base_type&>(*this),
static_cast<base_type&>(other));
swap(data_, other.data_); swap(data_, other.data_);
swap(compare_, other.compare_);
} }
size_type count(const key_type& key) const { size_type count(const key_type& key) const {
@@ -244,52 +247,51 @@ namespace flat_hpp
iterator find(const key_type& key) { iterator find(const key_type& key) {
const iterator iter = lower_bound(key); const iterator iter = lower_bound(key);
return iter != end() && !compare_(key, *iter) return iter != end() && !this->operator()(key, *iter)
? iter ? iter
: end(); : end();
} }
const_iterator find(const key_type& key) const { const_iterator find(const key_type& key) const {
const const_iterator iter = lower_bound(key); const const_iterator iter = lower_bound(key);
return iter != end() && !compare_(key, *iter) return iter != end() && !this->operator()(key, *iter)
? iter ? iter
: end(); : end();
} }
std::pair<iterator, iterator> equal_range(const key_type& key) { std::pair<iterator, iterator> 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<const_iterator, const_iterator> equal_range(const key_type& key) const { std::pair<const_iterator, const_iterator> 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) { 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 { 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) { 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 { 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 { key_compare key_comp() const {
return compare_; return *this;
} }
value_compare value_comp() const { value_compare value_comp() const {
return value_compare(compare_); return value_compare(key_comp());
} }
private: private:
container_type data_; container_type data_;
Compare compare_;
}; };
} }

View File

@@ -70,6 +70,16 @@ namespace
return !(l == r); 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 > template < typename T >
constexpr std::add_const_t<T>& my_as_const(T& t) noexcept { constexpr std::add_const_t<T>& my_as_const(T& t) noexcept {
return t; return t;
@@ -77,6 +87,14 @@ namespace
} }
TEST_CASE("flat_set") { TEST_CASE("flat_set") {
SECTION("sizeof") {
REQUIRE(sizeof(flat_set<int>) == sizeof(std::vector<int>));
struct vc : flat_set<int>::value_compare {
int i;
};
REQUIRE(sizeof(vc) == sizeof(int));
}
SECTION("types") { SECTION("types") {
using set_t = flat_set<int>; using set_t = flat_set<int>;
@@ -390,6 +408,16 @@ TEST_CASE("flat_set") {
REQUIRE(my_as_const(s0).key_comp().i == 42); REQUIRE(my_as_const(s0).key_comp().i == 42);
REQUIRE(my_as_const(s0).value_comp().i == 42); REQUIRE(my_as_const(s0).value_comp().i == 42);
} }
SECTION("custom_less") {
using set_t = flat_set<int, dummy_less<int>>;
auto s0 = set_t(dummy_less<int>(42));
auto s1 = set_t(dummy_less<int>(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") { SECTION("operators") {
using set_t = flat_set<int>; using set_t = flat_set<int>;