first flat_map impl and tests

This commit is contained in:
2019-05-04 17:44:47 +07:00
parent 8bf9a3f66d
commit 60765fcaaf
2 changed files with 245 additions and 107 deletions

View File

@@ -22,7 +22,27 @@ namespace flat_hpp
, typename Compare = std::less<Key> , typename Compare = std::less<Key>
, typename Allocator = std::allocator<std::pair<Key, Value>> > , typename Allocator = std::allocator<std::pair<Key, Value>> >
class flat_map final { class flat_map final {
using data_type = std::vector<std::pair<Key, Value>, Allocator>; using data_type = std::vector<
std::pair<Key, Value>,
Allocator>;
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 data_type::const_reference r) const {
return Compare::operator()(l, r.first);
}
bool operator()(typename data_type::const_reference l, const Key& r) const {
return Compare::operator()(l.first, r);
}
};
public: public:
using key_type = Key; using key_type = Key;
using mapped_type = Value; using mapped_type = Value;
@@ -44,7 +64,7 @@ namespace flat_hpp
using reverse_iterator = typename data_type::reverse_iterator; using reverse_iterator = typename data_type::reverse_iterator;
using const_reverse_iterator = typename data_type::const_reverse_iterator; using const_reverse_iterator = typename data_type::const_reverse_iterator;
class value_compare final : public std::binary_function<value_type, value_type, bool> { class value_compare final {
public: public:
bool operator()(const value_type& l, const value_type& r) const { bool operator()(const value_type& l, const value_type& r) const {
return compare_(l.first, r.first); return compare_(l.first, r.first);
@@ -92,19 +112,19 @@ namespace flat_hpp
} }
flat_map( flat_map(
std::initializer_list<value_type> il, std::initializer_list<value_type> ilist,
const Allocator& a) const Allocator& a)
: data_(a) { : data_(a) {
insert(il.begin(), il.end()); insert(ilist);
} }
flat_map( flat_map(
std::initializer_list<value_type> il, std::initializer_list<value_type> ilist,
const Compare& c = Compare(), const Compare& c = Compare(),
const Allocator& a = Allocator()) const Allocator& a = Allocator())
: data_(a) : data_(a)
, compare_(c) { , compare_(c) {
insert(il.begin(), il.end()); insert(ilist);
} }
iterator begin() noexcept { return data_.begin(); } iterator begin() noexcept { return data_.begin(); }
@@ -160,36 +180,37 @@ namespace flat_hpp
} }
std::pair<iterator, bool> insert(const value_type& value) { std::pair<iterator, bool> insert(const value_type& value) {
bool found = true; const iterator iter = lower_bound(value.first);
iterator iter = lower_bound(value.first); return iter == end() || compare_(value.first, iter->first)
if ( iter == end() || compare_(value.first, iter->first) ) { ? std::make_pair(data_.insert(iter, value), true)
iter = data_.insert(iter, value); : std::make_pair(iter, false);
found = false;
}
return std::make_pair(iter, !found);
} }
std::pair<iterator, bool> insert(const_iterator hint, const value_type& value) { iterator insert(const_iterator hint, const value_type& value) {
//TODO(BlackMat): implme return (hint == begin() || compare_((hint - 1)->first, value.first))
return insert(value); && (hint == end() || compare_(value.first, hint->first))
? data_.insert(hint, std::move(value))
: insert(std::move(value)).first;
} }
template < typename InputIter > template < typename InputIter >
void insert(InputIter first, InputIter last) { void insert(InputIter first, InputIter last) {
for ( auto iter = first; iter != last; ++iter ) { while ( first != last ) {
insert(*iter); insert(*first++);
} }
} }
void insert(std::initializer_list<value_type> ilist) {
insert(ilist.begin(), ilist.end());
}
template < typename... Args > template < typename... Args >
std::pair<iterator, bool> emplace(Args&&... args) { std::pair<iterator, bool> emplace(Args&&... args) {
//TODO(BlackMat): implme
return insert(value_type(std::forward<Args>(args)...)); return insert(value_type(std::forward<Args>(args)...));
} }
template < typename... Args > template < typename... Args >
std::pair<iterator, bool> emplace_hint(const_iterator hint, Args&&... args) { iterator emplace_hint(const_iterator hint, Args&&... args) {
//TODO(BlackMat): implme
return insert(hint, value_type(std::forward<Args>(args)...)); return insert(hint, value_type(std::forward<Args>(args)...));
} }
@@ -198,22 +219,24 @@ namespace flat_hpp
} }
iterator erase(const_iterator iter) { iterator erase(const_iterator iter) {
//TODO(BlackMat): implme return data_.erase(iter);
return end();
} }
iterator erase(const_iterator first, const_iterator last) { iterator erase(const_iterator first, const_iterator last) {
//TODO(BlackMat): implme return data_.erase(first, last);
return end();
} }
iterator erase(const key_type& key) { size_type erase(const key_type& key) {
//TODO(BlackMat): implme const iterator iter = find(key);
return end(); return iter != end()
? (erase(iter), 1)
: 0;
} }
void swap(flat_map& other) { void swap(flat_map& other) {
//TODO(BlackMat): implme using std::swap;
swap(data_, other.data_);
swap(compare_, other.compare_);
} }
size_type count(const key_type& key) const { size_type count(const key_type& key) const {
@@ -222,57 +245,41 @@ namespace flat_hpp
} }
iterator find(const key_type& key) { iterator find(const key_type& key) {
iterator iter = lower_bound(key); const iterator iter = lower_bound(key);
if ( iter != end() && compare_(key, iter->first) ) { return iter != end() && !compare_(key, iter->first)
iter = end(); ? iter
} : end();
return iter;
} }
const_iterator find(const key_type& key) const { const_iterator find(const key_type& key) const {
const_iterator iter = lower_bound(key); const const_iterator iter = lower_bound(key);
if ( iter != end() && compare_(key, iter->first) ) { return iter != end() && !compare_(key, iter->first)
iter = end(); ? iter
} : end();
return iter;
} }
std::pair<iterator, iterator> equal_range(const key_type& key) { std::pair<iterator, iterator> equal_range(const key_type& key) {
//TODO(BlackMat): implme return std::equal_range(begin(), end(), key, compare_);
return {end(), end()};
} }
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 {
//TODO(BlackMat): implme return std::equal_range(begin(), end(), key, compare_);
return {end(), end()};
} }
iterator lower_bound(const key_type& key) { iterator lower_bound(const key_type& key) {
//TODO(BlackMat): implme return std::lower_bound(begin(), end(), key, compare_);
return std::lower_bound(begin(), end(), key, [this](const value_type& l, const key_type& r){
return compare_(l.first, r);
});
} }
const_iterator lower_bound(const key_type& key) const { const_iterator lower_bound(const key_type& key) const {
//TODO(BlackMat): implme return std::lower_bound(begin(), end(), key, compare_);
return std::lower_bound(begin(), end(), key, [this](const value_type& l, const key_type& r){
return compare_(l.first, r);
});
} }
iterator upper_bound(const key_type& key) { iterator upper_bound(const key_type& key) {
//TODO(BlackMat): implme return std::upper_bound(begin(), end(), key, compare_);
return std::upper_bound(begin(), end(), key, [this](const key_type& l, const value_type& r){
return compare_(l, r.first);
});
} }
const_iterator upper_bound(const key_type& key) const { const_iterator upper_bound(const key_type& key) const {
//TODO(BlackMat): implme return std::upper_bound(begin(), end(), key, compare_);
return std::upper_bound(begin(), end(), key, [this](const key_type& l, const value_type& r){
return compare_(l, r.first);
});
} }
key_compare key_comp() const { key_compare key_comp() const {
@@ -284,7 +291,7 @@ namespace flat_hpp
} }
private: private:
data_type data_; data_type data_;
key_compare compare_; uber_comparer_type compare_;
}; };
} }

View File

@@ -78,19 +78,32 @@ TEST_CASE("flat_map") {
std::less<int>, std::less<int>,
alloc_t>; alloc_t>;
using map2_t = flat_map<
int,
unsigned,
std::greater<int>,
alloc_t>;
{ {
auto s0 = map_t(); auto s0 = map_t();
auto s1 = map_t(alloc_t()); auto s1 = map2_t(alloc_t());
auto s2 = map_t(std::less<int>()); auto s2 = map_t(std::less<int>());
auto s3 = map_t(std::less<int>(), alloc_t()); auto s3 = map2_t(std::greater<int>(), alloc_t());
} }
{ {
std::vector<std::pair<int,unsigned>> v; using vec_t = std::vector<std::pair<int,unsigned>>;
vec_t v{{1,30},{2,20},{3,10}};
auto s0 = map_t(v.cbegin(), v.cend()); auto s0 = map_t(v.cbegin(), v.cend());
auto s1 = map_t(v.cbegin(), v.cend(), alloc_t()); auto s1 = map2_t(v.cbegin(), v.cend(), alloc_t());
auto s2 = map_t(v.cbegin(), v.cend(), std::less<int>()); auto s2 = map_t(v.cbegin(), v.cend(), std::less<int>());
auto s3 = map_t(v.cbegin(), v.cend(), std::less<int>(), alloc_t()); auto s3 = map2_t(v.cbegin(), v.cend(), std::greater<int>(), alloc_t());
REQUIRE(vec_t(s0.begin(), s0.end()) == vec_t({{1,30},{2,20},{3,10}}));
REQUIRE(vec_t(s1.begin(), s1.end()) == vec_t({{3,10},{2,20},{1,30}}));
REQUIRE(vec_t(s2.begin(), s2.end()) == vec_t({{1,30},{2,20},{3,10}}));
REQUIRE(vec_t(s3.begin(), s3.end()) == vec_t({{3,10},{2,20},{1,30}}));
} }
{ {
@@ -103,16 +116,40 @@ TEST_CASE("flat_map") {
SECTION("capacity") { SECTION("capacity") {
using map_t = flat_map<int, unsigned>; using map_t = flat_map<int, unsigned>;
map_t s0; map_t s0;
s0.empty();
s0.size(); REQUIRE(s0.empty());
s0.max_size(); REQUIRE_FALSE(s0.size());
REQUIRE(s0.max_size() == std::allocator<std::pair<int,unsigned>>().max_size());
s0.insert({2,42});
REQUIRE_FALSE(s0.empty());
REQUIRE(s0.size() == 1u);
REQUIRE(s0.max_size() == std::allocator<std::pair<int,unsigned>>().max_size());
s0.insert({2,84});
REQUIRE(s0.size() == 1u);
s0.insert({3,84});
REQUIRE(s0.size() == 2u);
s0.clear();
REQUIRE(s0.empty());
REQUIRE_FALSE(s0.size());
REQUIRE(s0.max_size() == std::allocator<std::pair<int,unsigned>>().max_size());
} }
SECTION("access") { SECTION("access") {
using map_t = flat_map<int, unsigned>; using map_t = flat_map<int, unsigned>;
map_t s0; map_t s0;
s0[1] = 42; s0[1] = 42;
s0.at(1); REQUIRE(s0 == map_t{{1,42}});
my_as_const(s0).at(1); s0[1] = 84;
REQUIRE(s0 == map_t{{1,84}});
REQUIRE(s0.at(1) == 84);
REQUIRE(my_as_const(s0).at(1) == 84);
REQUIRE_THROWS_AS(s0.at(0), std::out_of_range);
} }
SECTION("inserts") { SECTION("inserts") {
struct obj_t { struct obj_t {
@@ -122,61 +159,155 @@ TEST_CASE("flat_map") {
bool operator<(const obj_t& o) const { bool operator<(const obj_t& o) const {
return i < o.i; return i < o.i;
} }
bool operator==(const obj_t& o) const {
return i == o.i;
}
}; };
using map_t = flat_map<int, obj_t>; using map_t = flat_map<int, obj_t>;
{ {
map_t s0; map_t s0;
s0.insert(std::make_pair(1, 42));
s0.insert(std::make_pair(2, obj_t(42))); auto i0 = s0.insert(std::make_pair(1, 42));
s0.insert(s0.cend(), std::make_pair(3, 84)); REQUIRE(s0 == map_t{{1,42}});
REQUIRE(i0 == std::make_pair(s0.begin(), true));
auto i1 = s0.insert(std::make_pair(1, obj_t(42)));
REQUIRE(s0 == map_t{{1,42}});
REQUIRE(i1 == std::make_pair(s0.begin(), false));
auto i2 = s0.insert(std::make_pair(2, obj_t(42)));
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));
REQUIRE(i3 == s0.begin() + 2);
s0.insert(s0.cend(), std::make_pair(4, obj_t(84))); s0.insert(s0.cend(), std::make_pair(4, obj_t(84)));
s0.emplace(5, 100500);
s0.emplace_hint(s0.cend(), 6, 100500); auto i4 = s0.emplace(5, 100500);
REQUIRE(i4 == std::make_pair(s0.end() - 1, true));
REQUIRE(s0 == map_t{{1,42},{2,42},{3,84},{4,84},{5,100500}});
auto i5 = s0.emplace_hint(s0.cend(), 6, 100500);
REQUIRE(s0 == map_t{{1,42},{2,42},{3,84},{4,84},{5,100500},{6,100500}});
} }
} }
SECTION("erasers") { SECTION("erasers") {
using map_t = flat_map<int, unsigned>; using map_t = flat_map<int, unsigned>;
map_t s0; {
s0.clear(); map_t s0{{1,2},{2,3},{3,4}};
s0.erase(s0.begin()); s0.clear();
s0.erase(s0.cbegin()); REQUIRE(s0.empty());
s0.erase(s0.begin(), s0.end()); }
s0.erase(s0.cbegin(), s0.cend()); {
s0.erase(42); map_t s0{{1,2},{2,3},{3,4}};
map_t s1; auto i = s0.erase(s0.find(2));
s0.swap(s1); REQUIRE(i == s0.begin() + 1);
swap(s0, s1); REQUIRE(s0 == map_t{{1,2},{3,4}});
}
{
map_t s0{{1,2},{2,3},{3,4}};
auto i = s0.erase(s0.begin() + 1, s0.end());
REQUIRE(i == s0.end());
REQUIRE(s0 == map_t{{1,2}});
}
{
map_t s0{{1,2},{2,3},{3,4}};
REQUIRE(s0.erase(1) == 1);
REQUIRE(s0.erase(6) == 0);
REQUIRE(s0 == map_t{{2,3},{3,4}});
}
{
map_t s0{{1,2},{2,3},{3,4}};
map_t s1{{2,3},{3,4},{5,6}};
s0.swap(s1);
REQUIRE(s0 == map_t{{2,3},{3,4},{5,6}});
REQUIRE(s1 == map_t{{1,2},{2,3},{3,4}});
swap(s1, s0);
REQUIRE(s0 == map_t{{1,2},{2,3},{3,4}});
REQUIRE(s1 == map_t{{2,3},{3,4},{5,6}});
}
} }
SECTION("lookup") { SECTION("lookup") {
using map_t = flat_map<int, unsigned>; using map_t = flat_map<int, unsigned>;
map_t s0; {
s0.count(10); map_t s0{{1,2},{2,3},{3,4},{4,5},{5,6}};
s0.find(10); REQUIRE(s0.count(3));
my_as_const(s0).find(10); REQUIRE_FALSE(s0.count(6));
s0.equal_range(20); REQUIRE(my_as_const(s0).count(5));
my_as_const(s0).equal_range(20); REQUIRE_FALSE(my_as_const(s0).count(0));
s0.lower_bound(30); }
my_as_const(s0).lower_bound(30); {
s0.upper_bound(30); map_t s0{{1,2},{2,3},{3,4},{4,5},{5,6}};
my_as_const(s0).upper_bound(30); 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());
}
{
map_t s0{{1,2},{2,3},{3,4},{4,5},{5,6}};
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()));
}
{
map_t s0{{0,1},{3,2},{6,3}};
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") { SECTION("observers") {
using map_t = flat_map<int, unsigned>; struct my_less {
map_t s0; int i;
my_as_const(s0).key_comp(); my_less(int i) : i(i) {}
my_as_const(s0).value_comp(); bool operator()(int l, int r) const {
return l < r;
}
};
using map_t = flat_map<int, unsigned, my_less>;
map_t s0(my_less(42));
REQUIRE(my_as_const(s0).key_comp().i == 42);
REQUIRE(my_as_const(s0).value_comp()({2,50},{4,20}));
} }
SECTION("operators") { SECTION("operators") {
using map_t = flat_map<int, unsigned>; using map_t = flat_map<int, unsigned>;
map_t s0;
map_t s1; REQUIRE(map_t{{1,2},{3,4}} == map_t{{3,4},{1,2}});
REQUIRE(s0 == s1); REQUIRE_FALSE(map_t{{1,2},{3,4}} == map_t{{2,4},{1,2}});
REQUIRE_FALSE(s0 != s1); REQUIRE_FALSE(map_t{{1,2},{3,4}} == map_t{{1,3},{1,2}});
REQUIRE_FALSE(s0 < s1); REQUIRE_FALSE(map_t{{1,2},{3,4}} == map_t{{3,4},{1,2},{0,0}});
REQUIRE_FALSE(s0 > s1);
REQUIRE(s0 <= s1); REQUIRE_FALSE(map_t{{1,2},{3,4}} != map_t{{3,4},{1,2}});
REQUIRE(s0 >= s1); REQUIRE(map_t{{1,2},{3,4}} != map_t{{2,4},{1,2}});
REQUIRE(map_t{{1,2},{3,4}} != map_t{{1,3},{1,2}});
REQUIRE(map_t{{1,2},{3,4}} != map_t{{3,4},{1,2},{0,0}});
REQUIRE(map_t{{0,2},{3,4}} < map_t{{1,2},{3,4}});
REQUIRE(map_t{{1,1},{3,4}} < map_t{{1,2},{3,4}});
REQUIRE(map_t{{1,2},{3,4}} < map_t{{1,2},{3,4},{5,6}});
REQUIRE(map_t{{0,2},{3,4}} <= map_t{{1,2},{3,4}});
REQUIRE(map_t{{1,1},{3,4}} <= map_t{{1,2},{3,4}});
REQUIRE(map_t{{1,2},{3,4}} <= map_t{{1,2},{3,4},{5,6}});
REQUIRE(map_t{{1,2},{3,4}} > map_t{{0,2},{3,4}});
REQUIRE(map_t{{1,2},{3,4}} > map_t{{1,1},{3,4}});
REQUIRE(map_t{{1,2},{3,4},{5,6}} > map_t{{1,2},{3,4}});
REQUIRE(map_t{{1,2},{3,4}} >= map_t{{0,2},{3,4}});
REQUIRE(map_t{{1,2},{3,4}} >= map_t{{1,1},{3,4}});
REQUIRE(map_t{{1,2},{3,4},{5,6}} >= map_t{{1,2},{3,4}});
REQUIRE_FALSE(map_t{{1,2},{3,4}} < map_t{{1,2},{3,4}});
REQUIRE(map_t{{1,2},{3,4}} <= map_t{{1,2},{3,4}});
REQUIRE_FALSE(map_t{{1,2},{3,4}} > map_t{{1,2},{3,4}});
REQUIRE(map_t{{1,2},{3,4}} >= map_t{{1,2},{3,4}});
} }
} }