From 33fd5f964a6ed2efcecb09c02124a747743d060c Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Sat, 4 May 2019 10:17:52 +0700 Subject: [PATCH 01/12] add set and map ctors --- flat_map.hpp | 82 ++++++++++++++++++++++++++++++++++++++++++++++ flat_map_tests.cpp | 51 ++++++++++++++++++++++++++-- flat_set.hpp | 82 ++++++++++++++++++++++++++++++++++++++++++++++ flat_set_tests.cpp | 45 +++++++++++++++++++++++-- 4 files changed, 256 insertions(+), 4 deletions(-) diff --git a/flat_map.hpp b/flat_map.hpp index 8e03418..ac75aa1 100644 --- a/flat_map.hpp +++ b/flat_map.hpp @@ -9,8 +9,11 @@ #include #include #include +#include +#include #include #include +#include namespace flat_hpp { @@ -40,5 +43,84 @@ namespace flat_hpp 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; + + static_assert( + std::is_same::value, + "Allocator::value_type must be same type as value_type"); + public: + explicit flat_map( + const Allocator& a) + : data_(a) {} + + explicit flat_map( + const Compare& c = Compare(), + const Allocator& a = Allocator()) + : data_(a) + , compare_(c) {} + + template < typename InputIter > + flat_map( + InputIter first, + InputIter last, + const Allocator& a) + : data_(a) { + insert(first, last); + } + + template < typename InputIter > + flat_map( + InputIter first, + InputIter last, + const Compare& c = Compare(), + const Allocator& a = Allocator()) + : data_(a) + , compare_(c) { + insert(first, last); + } + + flat_map( + std::initializer_list il, + const Allocator& a) + : data_(a) { + insert(il.begin(), il.end()); + } + + flat_map( + std::initializer_list il, + const Compare& c = Compare(), + const Allocator& a = Allocator()) + : data_(a) + , compare_(c) { + insert(il.begin(), il.end()); + } + + iterator begin() noexcept { return data_.begin(); } + const_iterator begin() const noexcept { return data_.begin(); } + iterator end() noexcept { return data_.end(); } + const_iterator end() const noexcept { return data_.end(); } + reverse_iterator rbegin() noexcept { return data_.rbegin(); } + const_reverse_iterator rbegin() const noexcept { return data_.rbegin(); } + reverse_iterator rend() noexcept { return data_.rend(); } + const_reverse_iterator rend() const noexcept { return data_.rend(); } + + std::pair insert(value_type&& value) { + //TODO(BlackMat): implme + return std::make_pair(end(), false); + } + + std::pair insert(const value_type& value) { + //TODO(BlackMat): implme + return std::make_pair(end(), false); + } + + template < typename InputIter > + void insert(InputIter first, InputIter last) { + for ( auto iter = first; iter != last; ++iter ) { + insert(*iter); + } + } + private: + data_type data_; + key_compare compare_; }; } diff --git a/flat_map_tests.cpp b/flat_map_tests.cpp index 2a51191..aa0b702 100644 --- a/flat_map_tests.cpp +++ b/flat_map_tests.cpp @@ -8,15 +8,30 @@ #include "catch.hpp" #include "flat_map.hpp" -namespace flat = flat_hpp; +using namespace flat_hpp; namespace { + template < typename T > + class dummy_allocator { + public: + using value_type = T; + + T* allocate(std::size_t n) { + (void)n; + return nullptr; + } + + void deallocate(T* p, std::size_t n) { + (void)p; + (void)n; + } + }; } TEST_CASE("flat_map") { { - using map_t = flat::flat_map; + using map_t = flat_map; static_assert( std::is_same::value, @@ -49,4 +64,36 @@ TEST_CASE("flat_map") { std::is_same*>::value, "unit test static error"); } + { + using alloc_t = dummy_allocator< + std::pair>; + + using map_t = flat_map< + int, + unsigned, + std::less, + alloc_t>; + + { + auto s0 = map_t(); + auto s1 = map_t(alloc_t()); + auto s2 = map_t(std::less()); + auto s3 = map_t(std::less(), alloc_t()); + } + + { + std::vector> v; + auto s0 = map_t(v.cbegin(), v.cend()); + auto s1 = map_t(v.cbegin(), v.cend(), alloc_t()); + auto s2 = map_t(v.cbegin(), v.cend(), std::less()); + auto s3 = map_t(v.cbegin(), v.cend(), std::less(), alloc_t()); + } + + { + auto s0 = map_t({{0,1}, {1,2}}); + 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()); + } + } } diff --git a/flat_set.hpp b/flat_set.hpp index f132a1a..a6d1267 100644 --- a/flat_set.hpp +++ b/flat_set.hpp @@ -9,8 +9,11 @@ #include #include #include +#include +#include #include #include +#include namespace flat_hpp { @@ -39,5 +42,84 @@ namespace flat_hpp 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; + + static_assert( + std::is_same::value, + "Allocator::value_type must be same type as value_type"); + public: + explicit flat_set( + const Allocator& a) + : data_(a) {} + + explicit flat_set( + const Compare& c = Compare(), + const Allocator& a = Allocator()) + : data_(a) + , compare_(c) {} + + template < typename InputIter > + flat_set( + InputIter first, + InputIter last, + const Allocator& a) + : data_(a) { + insert(first, last); + } + + template < typename InputIter > + flat_set( + InputIter first, + InputIter last, + const Compare& c = Compare(), + const Allocator& a = Allocator()) + : data_(a) + , compare_(c) { + insert(first, last); + } + + flat_set( + std::initializer_list il, + const Allocator& a) + : data_(a) { + insert(il.begin(), il.end()); + } + + flat_set( + std::initializer_list il, + const Compare& c = Compare(), + const Allocator& a = Allocator()) + : data_(a) + , compare_(c) { + insert(il.begin(), il.end()); + } + + iterator begin() noexcept { return data_.begin(); } + const_iterator begin() const noexcept { return data_.begin(); } + iterator end() noexcept { return data_.end(); } + const_iterator end() const noexcept { return data_.end(); } + reverse_iterator rbegin() noexcept { return data_.rbegin(); } + const_reverse_iterator rbegin() const noexcept { return data_.rbegin(); } + reverse_iterator rend() noexcept { return data_.rend(); } + const_reverse_iterator rend() const noexcept { return data_.rend(); } + + std::pair insert(value_type&& value) { + //TODO(BlackMat): implme + return std::make_pair(end(), false); + } + + std::pair insert(const value_type& value) { + //TODO(BlackMat): implme + return std::make_pair(end(), false); + } + + template < typename InputIter > + void insert(InputIter first, InputIter last) { + for ( auto iter = first; iter != last; ++iter ) { + insert(*iter); + } + } + private: + data_type data_; + key_compare compare_; }; } diff --git a/flat_set_tests.cpp b/flat_set_tests.cpp index 284ee7a..e0ca0f7 100644 --- a/flat_set_tests.cpp +++ b/flat_set_tests.cpp @@ -8,15 +8,30 @@ #include "catch.hpp" #include "flat_set.hpp" -namespace flat = flat_hpp; +using namespace flat_hpp; namespace { + template < typename T > + class dummy_allocator { + public: + using value_type = T; + + T* allocate(std::size_t n) { + (void)n; + return nullptr; + } + + void deallocate(T* p, std::size_t n) { + (void)p; + (void)n; + } + }; } TEST_CASE("flat_set") { { - using set_t = flat::flat_set; + using set_t = flat_set; static_assert( std::is_same::value, @@ -46,4 +61,30 @@ TEST_CASE("flat_set") { std::is_same::value, "unit test static error"); } + { + using alloc_t = dummy_allocator; + using set_t = flat_set, alloc_t>; + + { + auto s0 = set_t(); + auto s1 = set_t(alloc_t()); + auto s2 = set_t(std::less()); + auto s3 = set_t(std::less(), alloc_t()); + } + + { + std::vector v; + auto s0 = set_t(v.cbegin(), v.cend()); + auto s1 = set_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 s0 = set_t({0,1,2}); + auto s1 = set_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()); + } + } } From 49dff175dd40615b9980128117113fdf06036f16 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Sat, 4 May 2019 10:45:06 +0700 Subject: [PATCH 02/12] add dummy insert interface --- flat_map.hpp | 27 +++++++++++++++++++++++++-- flat_map_tests.cpp | 22 ++++++++++++++++++++-- flat_set.hpp | 27 +++++++++++++++++++++++++-- flat_set_tests.cpp | 22 ++++++++++++++++++++-- 4 files changed, 90 insertions(+), 8 deletions(-) diff --git a/flat_map.hpp b/flat_map.hpp index ac75aa1..32081b3 100644 --- a/flat_map.hpp +++ b/flat_map.hpp @@ -96,19 +96,30 @@ namespace flat_hpp iterator begin() noexcept { return data_.begin(); } const_iterator begin() const noexcept { return data_.begin(); } + const_iterator cbegin() const noexcept { return data_.cbegin(); } + iterator end() noexcept { return data_.end(); } const_iterator end() const noexcept { return data_.end(); } + const_iterator cend() const noexcept { return data_.cend(); } + reverse_iterator rbegin() noexcept { return data_.rbegin(); } const_reverse_iterator rbegin() const noexcept { return data_.rbegin(); } + const_reverse_iterator crbegin() const noexcept { return data_.crbegin(); } + reverse_iterator rend() noexcept { return data_.rend(); } const_reverse_iterator rend() const noexcept { return data_.rend(); } + const_reverse_iterator crend() const noexcept { return data_.crend(); } - std::pair insert(value_type&& value) { + 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(const value_type& value) { + 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); } @@ -119,6 +130,18 @@ namespace flat_hpp insert(*iter); } } + + 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 + return insert(value_type(std::forward(args)...)); + } private: data_type data_; key_compare compare_; diff --git a/flat_map_tests.cpp b/flat_map_tests.cpp index aa0b702..0ea5e12 100644 --- a/flat_map_tests.cpp +++ b/flat_map_tests.cpp @@ -30,7 +30,7 @@ namespace } TEST_CASE("flat_map") { - { + SECTION("types") { using map_t = flat_map; static_assert( @@ -64,7 +64,7 @@ TEST_CASE("flat_map") { std::is_same*>::value, "unit test static error"); } - { + SECTION("ctors") { using alloc_t = dummy_allocator< std::pair>; @@ -96,4 +96,22 @@ TEST_CASE("flat_map") { auto s3 = map_t({{0,1}, {1,2}}, std::less(), alloc_t()); } } + SECTION("inserts") { + struct obj_t { + obj_t(int i) : i(i) {} + int i; + }; + + using map_t = flat_map; + + { + map_t s0; + s0.insert(std::make_pair(1, 42)); + s0.insert(std::make_pair(2, obj_t(42))); + s0.insert(s0.cend(), std::make_pair(3, 84)); + s0.insert(s0.cend(), std::make_pair(4, obj_t(84))); + s0.emplace(5, 100500); + s0.emplace_hint(s0.cend(), 6, 100500); + } + } } diff --git a/flat_set.hpp b/flat_set.hpp index a6d1267..9704ebd 100644 --- a/flat_set.hpp +++ b/flat_set.hpp @@ -95,19 +95,30 @@ namespace flat_hpp iterator begin() noexcept { return data_.begin(); } const_iterator begin() const noexcept { return data_.begin(); } + const_iterator cbegin() const noexcept { return data_.cbegin(); } + iterator end() noexcept { return data_.end(); } const_iterator end() const noexcept { return data_.end(); } + const_iterator cend() const noexcept { return data_.cend(); } + reverse_iterator rbegin() noexcept { return data_.rbegin(); } const_reverse_iterator rbegin() const noexcept { return data_.rbegin(); } + const_reverse_iterator crbegin() const noexcept { return data_.crbegin(); } + reverse_iterator rend() noexcept { return data_.rend(); } const_reverse_iterator rend() const noexcept { return data_.rend(); } + const_reverse_iterator crend() const noexcept { return data_.crend(); } - std::pair insert(value_type&& value) { + 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(const value_type& value) { + 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); } @@ -118,6 +129,18 @@ namespace flat_hpp insert(*iter); } } + + 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 + return insert(hint, value_type(std::forward(args)...)); + } private: data_type data_; key_compare compare_; diff --git a/flat_set_tests.cpp b/flat_set_tests.cpp index e0ca0f7..61bb706 100644 --- a/flat_set_tests.cpp +++ b/flat_set_tests.cpp @@ -30,7 +30,7 @@ namespace } TEST_CASE("flat_set") { - { + SECTION("types") { using set_t = flat_set; static_assert( @@ -61,7 +61,7 @@ TEST_CASE("flat_set") { std::is_same::value, "unit test static error"); } - { + SECTION("ctors") { using alloc_t = dummy_allocator; using set_t = flat_set, alloc_t>; @@ -87,4 +87,22 @@ TEST_CASE("flat_set") { auto s3 = set_t({0,1,2}, std::less(), alloc_t()); } } + SECTION("inserts") { + struct obj_t { + obj_t(int i) : i(i) {} + int 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); + } + } } From cd3e02093f12f6f2e307dbf981610802f45ed70e Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Sat, 4 May 2019 10:49:54 +0700 Subject: [PATCH 03/12] add capacity interface --- flat_map.hpp | 12 ++++++++++++ flat_map_tests.cpp | 7 +++++++ flat_set.hpp | 12 ++++++++++++ flat_set_tests.cpp | 7 +++++++ 4 files changed, 38 insertions(+) diff --git a/flat_map.hpp b/flat_map.hpp index 32081b3..f9d98f4 100644 --- a/flat_map.hpp +++ b/flat_map.hpp @@ -110,6 +110,18 @@ namespace flat_hpp const_reverse_iterator rend() const noexcept { return data_.rend(); } const_reverse_iterator crend() const noexcept { return data_.crend(); } + bool empty() const noexcept { + return data_.empty(); + } + + size_type size() const noexcept { + return data_.size(); + } + + size_type max_size() const noexcept { + return data_.max_size(); + } + template < typename P , typename = std::enable_if_t::value> > std::pair insert(P&& p) { diff --git a/flat_map_tests.cpp b/flat_map_tests.cpp index 0ea5e12..227af3e 100644 --- a/flat_map_tests.cpp +++ b/flat_map_tests.cpp @@ -96,6 +96,13 @@ TEST_CASE("flat_map") { auto s3 = map_t({{0,1}, {1,2}}, std::less(), alloc_t()); } } + SECTION("capacity") { + using map_t = flat_map; + map_t s0; + s0.empty(); + s0.size(); + s0.max_size(); + } SECTION("inserts") { struct obj_t { obj_t(int i) : i(i) {} diff --git a/flat_set.hpp b/flat_set.hpp index 9704ebd..e11a9e4 100644 --- a/flat_set.hpp +++ b/flat_set.hpp @@ -109,6 +109,18 @@ namespace flat_hpp const_reverse_iterator rend() const noexcept { return data_.rend(); } const_reverse_iterator crend() const noexcept { return data_.crend(); } + bool empty() const noexcept { + return data_.empty(); + } + + size_type size() const noexcept { + return data_.size(); + } + + size_type max_size() const noexcept { + return data_.max_size(); + } + template < typename P , typename = std::enable_if_t::value> > std::pair insert(P&& p) { diff --git a/flat_set_tests.cpp b/flat_set_tests.cpp index 61bb706..7e57727 100644 --- a/flat_set_tests.cpp +++ b/flat_set_tests.cpp @@ -87,6 +87,13 @@ TEST_CASE("flat_set") { auto s3 = set_t({0,1,2}, std::less(), alloc_t()); } } + SECTION("capacity") { + using set_t = flat_set; + set_t s0; + s0.empty(); + s0.size(); + s0.max_size(); + } SECTION("inserts") { struct obj_t { obj_t(int i) : i(i) {} From beb5d0a2c840392f274e52f3105b9c134045ea05 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Sat, 4 May 2019 11:19:10 +0700 Subject: [PATCH 04/12] add erasers interface --- flat_map.hpp | 38 ++++++++++++++++++++++++++++++++++++-- flat_map_tests.cpp | 25 +++++++++++++++++++------ flat_set.hpp | 33 +++++++++++++++++++++++++++++++++ flat_set_tests.cpp | 13 +++++++++++++ 4 files changed, 101 insertions(+), 8 deletions(-) diff --git a/flat_map.hpp b/flat_map.hpp index f9d98f4..3ad42db 100644 --- a/flat_map.hpp +++ b/flat_map.hpp @@ -20,9 +20,9 @@ namespace flat_hpp template < typename Key , typename Value , typename Compare = std::less - , typename Allocator = std::allocator> > + , typename Allocator = std::allocator> > class flat_map final { - using data_type = std::vector, Allocator>; + using data_type = std::vector, Allocator>; public: using key_type = Key; using mapped_type = Value; @@ -154,8 +154,42 @@ namespace flat_hpp //TODO(BlackMat): implme return insert(value_type(std::forward(args)...)); } + + void clear() noexcept { + data_.clear(); + } + + iterator erase(const_iterator iter) { + //TODO(BlackMat): implme + return end(); + } + + iterator erase(const_iterator first, const_iterator last) { + //TODO(BlackMat): implme + return end(); + } + + iterator erase(const key_type& key) { + //TODO(BlackMat): implme + return end(); + } + + void swap(flat_map& other) { + //TODO(BlackMat): implme + } private: data_type data_; key_compare compare_; }; + + template < typename Key + , typename Value + , typename Compare + , typename Allocator > + void swap( + flat_map& l, + flat_map& r) + { + l.swap(r); + } } diff --git a/flat_map_tests.cpp b/flat_map_tests.cpp index 227af3e..0b8ef77 100644 --- a/flat_map_tests.cpp +++ b/flat_map_tests.cpp @@ -40,7 +40,7 @@ TEST_CASE("flat_map") { std::is_same::value, "unit test static error"); static_assert( - std::is_same>::value, + std::is_same>::value, "unit test static error"); static_assert( @@ -51,22 +51,22 @@ TEST_CASE("flat_map") { "unit test static error"); static_assert( - std::is_same&>::value, + std::is_same&>::value, "unit test static error"); static_assert( - std::is_same&>::value, + std::is_same&>::value, "unit test static error"); static_assert( - std::is_same*>::value, + std::is_same*>::value, "unit test static error"); static_assert( - std::is_same*>::value, + std::is_same*>::value, "unit test static error"); } SECTION("ctors") { using alloc_t = dummy_allocator< - std::pair>; + std::pair>; using map_t = flat_map< int, @@ -121,4 +121,17 @@ TEST_CASE("flat_map") { s0.emplace_hint(s0.cend(), 6, 100500); } } + SECTION("erasers") { + using map_t = flat_map; + map_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); + map_t s1; + s0.swap(s1); + swap(s0, s1); + } } diff --git a/flat_set.hpp b/flat_set.hpp index e11a9e4..0478ddf 100644 --- a/flat_set.hpp +++ b/flat_set.hpp @@ -153,8 +153,41 @@ namespace flat_hpp //TODO(BlackMat): implme return insert(hint, value_type(std::forward(args)...)); } + + void clear() noexcept { + data_.clear(); + } + + iterator erase(const_iterator iter) { + //TODO(BlackMat): implme + return end(); + } + + iterator erase(const_iterator first, const_iterator last) { + //TODO(BlackMat): implme + return end(); + } + + iterator erase(const key_type& key) { + //TODO(BlackMat): implme + return end(); + } + + void swap(flat_set& other) { + //TODO(BlackMat): implme + } private: data_type data_; key_compare compare_; }; + + template < typename Key + , typename Compare + , typename Allocator > + void swap( + flat_set& l, + flat_set& r) + { + l.swap(r); + } } diff --git a/flat_set_tests.cpp b/flat_set_tests.cpp index 7e57727..cea309e 100644 --- a/flat_set_tests.cpp +++ b/flat_set_tests.cpp @@ -112,4 +112,17 @@ TEST_CASE("flat_set") { s0.emplace_hint(s0.cend(), 100500); } } + 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); + } } From b29067b6edc8c942657b78681506f463bd6ec959 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Sat, 4 May 2019 12:21:16 +0700 Subject: [PATCH 05/12] add lookup interface --- flat_map.hpp | 45 +++++++++++++++++++++++++++++++++++++++++++++ flat_map_tests.cpp | 18 ++++++++++++++++++ flat_set.hpp | 45 +++++++++++++++++++++++++++++++++++++++++++++ flat_set_tests.cpp | 18 ++++++++++++++++++ 4 files changed, 126 insertions(+) diff --git a/flat_map.hpp b/flat_map.hpp index 3ad42db..c882c9f 100644 --- a/flat_map.hpp +++ b/flat_map.hpp @@ -177,6 +177,51 @@ namespace flat_hpp void swap(flat_map& other) { //TODO(BlackMat): implme } + + size_type count(const key_type& key) const { + const auto iter = find(key); + return iter != end() ? 1 : 0; + } + + iterator find(const key_type& key) { + //TODO(BlackMat): implme + return end(); + } + + const_iterator find(const key_type& key) const { + //TODO(BlackMat): implme + return end(); + } + + std::pair equal_range(const key_type& key) { + //TODO(BlackMat): implme + return {end(), end()}; + } + + std::pair equal_range(const key_type& key) const { + //TODO(BlackMat): implme + return {end(), end()}; + } + + iterator lower_bound(const key_type& key) { + //TODO(BlackMat): implme + return end(); + } + + const_iterator lower_bound(const key_type& key) const { + //TODO(BlackMat): implme + return end(); + } + + iterator upper_bound(const key_type& key) { + //TODO(BlackMat): implme + return end(); + } + + const_iterator upper_bound(const key_type& key) const { + //TODO(BlackMat): implme + return end(); + } private: data_type data_; key_compare compare_; diff --git a/flat_map_tests.cpp b/flat_map_tests.cpp index 0b8ef77..d1d8283 100644 --- a/flat_map_tests.cpp +++ b/flat_map_tests.cpp @@ -27,6 +27,11 @@ namespace (void)n; } }; + + template < typename T > + constexpr std::add_const_t& my_as_const(T& t) noexcept { + return t; + } } TEST_CASE("flat_map") { @@ -134,4 +139,17 @@ TEST_CASE("flat_map") { s0.swap(s1); swap(s0, s1); } + SECTION("lookup") { + using map_t = flat_map; + map_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); + } } diff --git a/flat_set.hpp b/flat_set.hpp index 0478ddf..f985ada 100644 --- a/flat_set.hpp +++ b/flat_set.hpp @@ -176,6 +176,51 @@ namespace flat_hpp void swap(flat_set& other) { //TODO(BlackMat): implme } + + size_type count(const key_type& key) const { + const auto iter = find(key); + return iter != end() ? 1 : 0; + } + + iterator find(const key_type& key) { + //TODO(BlackMat): implme + return end(); + } + + const_iterator find(const key_type& key) const { + //TODO(BlackMat): implme + return end(); + } + + std::pair equal_range(const key_type& key) { + //TODO(BlackMat): implme + return {end(), end()}; + } + + std::pair equal_range(const key_type& key) const { + //TODO(BlackMat): implme + return {end(), end()}; + } + + iterator lower_bound(const key_type& key) { + //TODO(BlackMat): implme + return end(); + } + + const_iterator lower_bound(const key_type& key) const { + //TODO(BlackMat): implme + return end(); + } + + iterator upper_bound(const key_type& key) { + //TODO(BlackMat): implme + return end(); + } + + const_iterator upper_bound(const key_type& key) const { + //TODO(BlackMat): implme + return end(); + } private: data_type data_; key_compare compare_; diff --git a/flat_set_tests.cpp b/flat_set_tests.cpp index cea309e..f251a15 100644 --- a/flat_set_tests.cpp +++ b/flat_set_tests.cpp @@ -27,6 +27,11 @@ namespace (void)n; } }; + + template < typename T > + constexpr std::add_const_t& my_as_const(T& t) noexcept { + return t; + } } TEST_CASE("flat_set") { @@ -125,4 +130,17 @@ TEST_CASE("flat_set") { s0.swap(s1); swap(s0, s1); } + 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); + } } From d95c6f9b05ddfdb428e06651e3380d8612c43d52 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Sat, 4 May 2019 12:45:22 +0700 Subject: [PATCH 06/12] add observers interface --- flat_map.hpp | 21 +++++++++++++++++++++ flat_map_tests.cpp | 6 ++++++ flat_set.hpp | 8 ++++++++ flat_set_tests.cpp | 6 ++++++ 4 files changed, 41 insertions(+) diff --git a/flat_map.hpp b/flat_map.hpp index c882c9f..7c6ad6d 100644 --- a/flat_map.hpp +++ b/flat_map.hpp @@ -44,6 +44,19 @@ namespace flat_hpp using reverse_iterator = typename data_type::reverse_iterator; using const_reverse_iterator = typename data_type::const_reverse_iterator; + class value_compare final : public std::binary_function { + public: + bool operator()(const value_type& l, const value_type& r) const { + return compare_(l.first, r.first); + } + private: + friend class flat_map; + explicit value_compare(const key_compare& compare) + : compare_(compare) {} + private: + key_compare compare_; + }; + static_assert( std::is_same::value, "Allocator::value_type must be same type as value_type"); @@ -222,6 +235,14 @@ namespace flat_hpp //TODO(BlackMat): implme return end(); } + + key_compare key_comp() const { + return compare_; + } + + value_compare value_comp() const { + return value_compare(compare_); + } private: data_type data_; key_compare compare_; diff --git a/flat_map_tests.cpp b/flat_map_tests.cpp index d1d8283..78564e1 100644 --- a/flat_map_tests.cpp +++ b/flat_map_tests.cpp @@ -152,4 +152,10 @@ TEST_CASE("flat_map") { s0.upper_bound(30); my_as_const(s0).upper_bound(30); } + SECTION("observers") { + using map_t = flat_map; + map_t s0; + my_as_const(s0).key_comp(); + my_as_const(s0).value_comp(); + } } diff --git a/flat_set.hpp b/flat_set.hpp index f985ada..d9bf478 100644 --- a/flat_set.hpp +++ b/flat_set.hpp @@ -221,6 +221,14 @@ namespace flat_hpp //TODO(BlackMat): implme return end(); } + + key_compare key_comp() const { + return compare_; + } + + value_compare value_comp() const { + return value_compare(compare_); + } private: data_type data_; key_compare compare_; diff --git a/flat_set_tests.cpp b/flat_set_tests.cpp index f251a15..d360cd4 100644 --- a/flat_set_tests.cpp +++ b/flat_set_tests.cpp @@ -143,4 +143,10 @@ TEST_CASE("flat_set") { s0.upper_bound(30); my_as_const(s0).upper_bound(30); } + SECTION("observers") { + using set_t = flat_set; + set_t s0; + my_as_const(s0).key_comp(); + my_as_const(s0).value_comp(); + } } From 4e6c24a126ceec48fdd97329a7f28f5b5adf274a Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Sat, 4 May 2019 12:59:35 +0700 Subject: [PATCH 07/12] add operators interface --- flat_map.hpp | 44 ++++++++++++++++++++++++++++++++++++-------- flat_map_tests.cpp | 11 +++++++++++ flat_set.hpp | 43 ++++++++++++++++++++++++++++++++++++------- flat_set_tests.cpp | 11 +++++++++++ 4 files changed, 94 insertions(+), 15 deletions(-) diff --git a/flat_map.hpp b/flat_map.hpp index 7c6ad6d..6b47b63 100644 --- a/flat_map.hpp +++ b/flat_map.hpp @@ -247,15 +247,43 @@ namespace flat_hpp data_type data_; key_compare compare_; }; +} - template < typename Key - , typename Value - , typename Compare - , typename Allocator > - void swap( - flat_map& l, - flat_map& r) - { +namespace flat_hpp +{ + template < typename K, typename V, typename C, typename A > + void swap(flat_map& l, flat_map& r) { l.swap(r); } + + template < typename K, typename V, typename C, typename A > + bool operator==(const flat_map& l, const flat_map& r) { + return l.size() == r.size() + && std::equal(l.begin(), l.end(), r.begin(), r.end()); + } + + template < typename K, typename V, typename C, typename A > + bool operator!=(const flat_map& l, const flat_map& r) { + return !(l == r); + } + + template < typename K, typename V, typename C, typename A > + bool operator<(const flat_map& l, const flat_map& r) { + return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end()); + } + + template < typename K, typename V, typename C, typename A > + bool operator>(const flat_map& l, const flat_map& r) { + return r < l; + } + + template < typename K, typename V, typename C, typename A > + bool operator<=(const flat_map& l, const flat_map& r) { + return !(r < l); + } + + template < typename K, typename V, typename C, typename A > + bool operator>=(const flat_map& l, const flat_map& r) { + return !(l < r); + } } diff --git a/flat_map_tests.cpp b/flat_map_tests.cpp index 78564e1..287578c 100644 --- a/flat_map_tests.cpp +++ b/flat_map_tests.cpp @@ -158,4 +158,15 @@ TEST_CASE("flat_map") { my_as_const(s0).key_comp(); my_as_const(s0).value_comp(); } + SECTION("operators") { + using map_t = flat_map; + map_t s0; + map_t s1; + REQUIRE(s0 == s1); + REQUIRE_FALSE(s0 != s1); + REQUIRE_FALSE(s0 < s1); + REQUIRE_FALSE(s0 > s1); + REQUIRE(s0 <= s1); + REQUIRE(s0 >= s1); + } } diff --git a/flat_set.hpp b/flat_set.hpp index d9bf478..9c661e9 100644 --- a/flat_set.hpp +++ b/flat_set.hpp @@ -233,14 +233,43 @@ namespace flat_hpp data_type data_; key_compare compare_; }; +} - template < typename Key - , typename Compare - , typename Allocator > - void swap( - flat_set& l, - flat_set& r) - { +namespace flat_hpp +{ + template < typename K, typename C, typename A > + void swap(flat_set& l, flat_set& r) { l.swap(r); } + + template < typename K, typename C, typename A > + bool operator==(const flat_set& l, const flat_set& r) { + return l.size() == r.size() + && std::equal(l.begin(), l.end(), r.begin(), r.end()); + } + + template < typename K, typename C, typename A > + bool operator!=(const flat_set& l, const flat_set& r) { + return !(l == r); + } + + template < typename K, typename C, typename A > + bool operator<(const flat_set& l, const flat_set& r) { + return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end()); + } + + template < typename K, typename C, typename A > + bool operator>(const flat_set& l, const flat_set& r) { + return r < l; + } + + template < typename K, typename C, typename A > + bool operator<=(const flat_set& l, const flat_set& r) { + return !(r < l); + } + + template < typename K, typename C, typename A > + bool operator>=(const flat_set& l, const flat_set& r) { + return !(l < r); + } } diff --git a/flat_set_tests.cpp b/flat_set_tests.cpp index d360cd4..8e0451b 100644 --- a/flat_set_tests.cpp +++ b/flat_set_tests.cpp @@ -149,4 +149,15 @@ TEST_CASE("flat_set") { my_as_const(s0).key_comp(); my_as_const(s0).value_comp(); } + 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); + } } From d4e85987778674236a94a268873b0c729a22c473 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Sat, 4 May 2019 13:49:34 +0700 Subject: [PATCH 08/12] map access interface --- flat_map.hpp | 75 +++++++++++++++++++++++++++++++++++----------- flat_map_tests.cpp | 18 ++++++++--- 2 files changed, 71 insertions(+), 22 deletions(-) diff --git a/flat_map.hpp b/flat_map.hpp index 6b47b63..c223ad5 100644 --- a/flat_map.hpp +++ b/flat_map.hpp @@ -135,18 +135,43 @@ 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); + mapped_type& operator[](key_type&& key) { + return insert(value_type(std::move(key), mapped_type())).first->second; } - template < typename P - , typename = std::enable_if_t::value> > - std::pair insert(const_iterator hint, P&& p) { + mapped_type& operator[](const key_type& key) { + return insert(value_type(key, mapped_type())).first->second; + } + + mapped_type& at(const key_type& key) { + const auto iter = find(key); + if ( iter != end() ) { + return iter->second; + } + throw std::out_of_range("flat_map::at: key not found"); + } + + const mapped_type& at(const key_type& key) const { + const auto iter = find(key); + if ( iter != end() ) { + return iter->second; + } + throw std::out_of_range("flat_map::at: key not found"); + } + + std::pair insert(const value_type& value) { + bool found = true; + iterator iter = lower_bound(value.first); + if ( iter == end() || compare_(value.first, iter->first) ) { + iter = data_.insert(iter, value); + found = false; + } + return std::make_pair(iter, !found); + } + + std::pair insert(const_iterator hint, const value_type& value) { //TODO(BlackMat): implme - return std::make_pair(end(), false); + return insert(value); } template < typename InputIter > @@ -165,7 +190,7 @@ namespace flat_hpp template < typename... Args > std::pair emplace_hint(const_iterator hint, Args&&... args) { //TODO(BlackMat): implme - return insert(value_type(std::forward(args)...)); + return insert(hint, value_type(std::forward(args)...)); } void clear() noexcept { @@ -197,13 +222,19 @@ namespace flat_hpp } iterator find(const key_type& key) { - //TODO(BlackMat): implme - return end(); + iterator iter = lower_bound(key); + if ( iter != end() && compare_(key, iter->first) ) { + iter = end(); + } + return iter; } const_iterator find(const key_type& key) const { - //TODO(BlackMat): implme - return end(); + const_iterator iter = lower_bound(key); + if ( iter != end() && compare_(key, iter->first) ) { + iter = end(); + } + return iter; } std::pair equal_range(const key_type& key) { @@ -218,22 +249,30 @@ namespace flat_hpp iterator lower_bound(const key_type& key) { //TODO(BlackMat): implme - return end(); + 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 { //TODO(BlackMat): implme - return end(); + 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) { //TODO(BlackMat): implme - return end(); + 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 { //TODO(BlackMat): implme - return end(); + 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 { diff --git a/flat_map_tests.cpp b/flat_map_tests.cpp index 287578c..aab7a16 100644 --- a/flat_map_tests.cpp +++ b/flat_map_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); } }; @@ -87,7 +86,7 @@ TEST_CASE("flat_map") { } { - std::vector> v; + std::vector> v; auto s0 = map_t(v.cbegin(), v.cend()); auto s1 = map_t(v.cbegin(), v.cend(), alloc_t()); auto s2 = map_t(v.cbegin(), v.cend(), std::less()); @@ -108,10 +107,21 @@ TEST_CASE("flat_map") { s0.size(); s0.max_size(); } + SECTION("access") { + using map_t = flat_map; + map_t s0; + s0[1] = 42; + s0.at(1); + my_as_const(s0).at(1); + } SECTION("inserts") { struct obj_t { obj_t(int i) : i(i) {} int i; + + bool operator<(const obj_t& o) const { + return i < o.i; + } }; using map_t = flat_map; From 8bf9a3f66d7099fe692d999c9194f26257930364 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Sat, 4 May 2019 15:26:29 +0700 Subject: [PATCH 09/12] first flat_set impl --- flat_set.hpp | 104 +++++++++++-------- flat_set_tests.cpp | 250 ++++++++++++++++++++++++++++++++++++--------- 2 files changed, 259 insertions(+), 95 deletions(-) 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}); } } From 60765fcaafabfc3b26fca2a2ab5fc0c609a55052 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Sat, 4 May 2019 17:44:47 +0700 Subject: [PATCH 10/12] first flat_map impl and tests --- flat_map.hpp | 127 +++++++++++++------------ flat_map_tests.cpp | 225 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 245 insertions(+), 107 deletions(-) diff --git a/flat_map.hpp b/flat_map.hpp index c223ad5..b117b2a 100644 --- a/flat_map.hpp +++ b/flat_map.hpp @@ -22,7 +22,27 @@ namespace flat_hpp , typename Compare = std::less , typename Allocator = std::allocator> > class flat_map final { - using data_type = std::vector, Allocator>; + using data_type = std::vector< + std::pair, + 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: using key_type = Key; using mapped_type = Value; @@ -44,7 +64,7 @@ namespace flat_hpp using reverse_iterator = typename data_type::reverse_iterator; using const_reverse_iterator = typename data_type::const_reverse_iterator; - class value_compare final : public std::binary_function { + class value_compare final { public: bool operator()(const value_type& l, const value_type& r) const { return compare_(l.first, r.first); @@ -92,19 +112,19 @@ namespace flat_hpp } flat_map( - std::initializer_list il, + std::initializer_list ilist, const Allocator& a) : data_(a) { - insert(il.begin(), il.end()); + insert(ilist); } flat_map( - 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(); } @@ -160,36 +180,37 @@ namespace flat_hpp } std::pair insert(const value_type& value) { - bool found = true; - iterator iter = lower_bound(value.first); - if ( iter == end() || compare_(value.first, iter->first) ) { - iter = data_.insert(iter, value); - found = false; - } - return std::make_pair(iter, !found); + const iterator iter = lower_bound(value.first); + return iter == end() || compare_(value.first, iter->first) + ? std::make_pair(data_.insert(iter, value), true) + : std::make_pair(iter, false); } - std::pair insert(const_iterator hint, const value_type& value) { - //TODO(BlackMat): implme - return insert(value); + 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, std::move(value)) + : insert(std::move(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)...)); } @@ -198,22 +219,24 @@ 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_map& other) { - //TODO(BlackMat): implme + using std::swap; + swap(data_, other.data_); + swap(compare_, other.compare_); } size_type count(const key_type& key) const { @@ -222,57 +245,41 @@ namespace flat_hpp } iterator find(const key_type& key) { - iterator iter = lower_bound(key); - if ( iter != end() && compare_(key, iter->first) ) { - iter = end(); - } - return iter; + const iterator iter = lower_bound(key); + return iter != end() && !compare_(key, iter->first) + ? iter + : end(); } const_iterator find(const key_type& key) const { - const_iterator iter = lower_bound(key); - if ( iter != end() && compare_(key, iter->first) ) { - iter = end(); - } - return iter; + const const_iterator iter = lower_bound(key); + return iter != end() && !compare_(key, iter->first) + ? 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 std::lower_bound(begin(), end(), key, [this](const value_type& l, const key_type& r){ - return compare_(l.first, r); - }); + return std::lower_bound(begin(), end(), key, compare_); } const_iterator lower_bound(const key_type& key) const { - //TODO(BlackMat): implme - return std::lower_bound(begin(), end(), key, [this](const value_type& l, const key_type& r){ - return compare_(l.first, r); - }); + return std::lower_bound(begin(), end(), key, compare_); } iterator upper_bound(const key_type& key) { - //TODO(BlackMat): implme - return std::upper_bound(begin(), end(), key, [this](const key_type& l, const value_type& r){ - return compare_(l, r.first); - }); + return std::upper_bound(begin(), end(), key, compare_); } const_iterator upper_bound(const key_type& key) const { - //TODO(BlackMat): implme - return std::upper_bound(begin(), end(), key, [this](const key_type& l, const value_type& r){ - return compare_(l, r.first); - }); + return std::upper_bound(begin(), end(), key, compare_); } key_compare key_comp() const { @@ -284,7 +291,7 @@ namespace flat_hpp } private: data_type data_; - key_compare compare_; + uber_comparer_type compare_; }; } diff --git a/flat_map_tests.cpp b/flat_map_tests.cpp index aab7a16..fa2eeeb 100644 --- a/flat_map_tests.cpp +++ b/flat_map_tests.cpp @@ -78,19 +78,32 @@ TEST_CASE("flat_map") { std::less, alloc_t>; + using map2_t = flat_map< + int, + unsigned, + std::greater, + alloc_t>; + { auto s0 = map_t(); - auto s1 = map_t(alloc_t()); + auto s1 = map2_t(alloc_t()); auto s2 = map_t(std::less()); - auto s3 = map_t(std::less(), alloc_t()); + auto s3 = map2_t(std::greater(), alloc_t()); } { - std::vector> v; + using vec_t = std::vector>; + + vec_t v{{1,30},{2,20},{3,10}}; 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()); - auto s3 = map_t(v.cbegin(), v.cend(), std::less(), alloc_t()); + auto s3 = map2_t(v.cbegin(), v.cend(), std::greater(), 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") { using map_t = flat_map; map_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({2,42}); + + REQUIRE_FALSE(s0.empty()); + REQUIRE(s0.size() == 1u); + REQUIRE(s0.max_size() == std::allocator>().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>().max_size()); } SECTION("access") { using map_t = flat_map; map_t s0; s0[1] = 42; - s0.at(1); - my_as_const(s0).at(1); + REQUIRE(s0 == map_t{{1,42}}); + 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") { struct obj_t { @@ -122,61 +159,155 @@ TEST_CASE("flat_map") { 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.insert(std::make_pair(1, 42)); - s0.insert(std::make_pair(2, obj_t(42))); - s0.insert(s0.cend(), std::make_pair(3, 84)); + + auto i0 = s0.insert(std::make_pair(1, 42)); + 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.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") { using map_t = flat_map; - map_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); - map_t s1; - s0.swap(s1); - swap(s0, s1); + { + map_t s0{{1,2},{2,3},{3,4}}; + s0.clear(); + REQUIRE(s0.empty()); + } + { + map_t s0{{1,2},{2,3},{3,4}}; + auto i = s0.erase(s0.find(2)); + REQUIRE(i == s0.begin() + 1); + 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") { using map_t = flat_map; - map_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); + { + map_t s0{{1,2},{2,3},{3,4},{4,5},{5,6}}; + REQUIRE(s0.count(3)); + REQUIRE_FALSE(s0.count(6)); + REQUIRE(my_as_const(s0).count(5)); + REQUIRE_FALSE(my_as_const(s0).count(0)); + } + { + map_t s0{{1,2},{2,3},{3,4},{4,5},{5,6}}; + 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") { - using map_t = flat_map; - map_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 map_t = flat_map; + 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") { using map_t = flat_map; - map_t s0; - map_t s1; - REQUIRE(s0 == s1); - REQUIRE_FALSE(s0 != s1); - REQUIRE_FALSE(s0 < s1); - REQUIRE_FALSE(s0 > s1); - REQUIRE(s0 <= s1); - REQUIRE(s0 >= s1); + + REQUIRE(map_t{{1,2},{3,4}} == map_t{{3,4},{1,2}}); + REQUIRE_FALSE(map_t{{1,2},{3,4}} == map_t{{2,4},{1,2}}); + REQUIRE_FALSE(map_t{{1,2},{3,4}} == map_t{{1,3},{1,2}}); + REQUIRE_FALSE(map_t{{1,2},{3,4}} == map_t{{3,4},{1,2},{0,0}}); + + REQUIRE_FALSE(map_t{{1,2},{3,4}} != map_t{{3,4},{1,2}}); + 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}}); } } From c0ad79ff235d2834f9a306f091af867806460a9e Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Sat, 4 May 2019 17:58:25 +0700 Subject: [PATCH 11/12] fix msvc compilation --- flat_map_tests.cpp | 34 +++++++++++++++++++++++++++------- flat_set_tests.cpp | 24 ++++++++++++++++++++++-- 2 files changed, 49 insertions(+), 9 deletions(-) diff --git a/flat_map_tests.cpp b/flat_map_tests.cpp index fa2eeeb..1957624 100644 --- a/flat_map_tests.cpp +++ b/flat_map_tests.cpp @@ -17,16 +17,32 @@ namespace public: using value_type = T; - T* allocate(std::size_t n) { + dummy_allocator() = default; + + template < typename U > + dummy_allocator(const dummy_allocator&) noexcept { + } + + T* allocate(std::size_t n) noexcept { return static_cast(std::malloc(sizeof(T) * n)); } - void deallocate(T* p, std::size_t n) { + void deallocate(T* p, std::size_t n) noexcept { (void)n; std::free(p); } }; + template < typename T, typename U > + bool operator==(const dummy_allocator&, const dummy_allocator&) noexcept { + return true; + } + + template < typename T, typename U > + bool operator!=(const dummy_allocator& l, const dummy_allocator& r) noexcept { + return !(l == r); + } + template < typename T > constexpr std::add_const_t& my_as_const(T& t) noexcept { return t; @@ -150,6 +166,7 @@ TEST_CASE("flat_map") { REQUIRE(s0.at(1) == 84); REQUIRE(my_as_const(s0).at(1) == 84); REQUIRE_THROWS_AS(s0.at(0), std::out_of_range); + REQUIRE_THROWS_AS(my_as_const(s0).at(0), std::out_of_range); } SECTION("inserts") { struct obj_t { @@ -186,13 +203,16 @@ TEST_CASE("flat_map") { REQUIRE(i3 == s0.begin() + 2); s0.insert(s0.cend(), std::make_pair(4, obj_t(84))); + auto i4 = s0.insert(s0.cend(), std::make_pair(0, obj_t(21))); + REQUIRE(i4 == s0.begin()); - 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(5, 100500); + REQUIRE(i5 == std::make_pair(s0.end() - 1, true)); + REQUIRE(s0 == map_t{{0,21},{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}}); + auto i6 = s0.emplace_hint(s0.cend(), 6, 100500); + REQUIRE(i6 == s0.end() - 1); + REQUIRE(s0 == map_t{{0,21},{1,42},{2,42},{3,84},{4,84},{5,100500},{6,100500}}); } } SECTION("erasers") { diff --git a/flat_set_tests.cpp b/flat_set_tests.cpp index cafc05a..d103f55 100644 --- a/flat_set_tests.cpp +++ b/flat_set_tests.cpp @@ -17,16 +17,32 @@ namespace public: using value_type = T; - T* allocate(std::size_t n) { + dummy_allocator() = default; + + template < typename U > + dummy_allocator(const dummy_allocator&) noexcept { + } + + T* allocate(std::size_t n) noexcept { return static_cast(std::malloc(sizeof(T) * n)); } - void deallocate(T* p, std::size_t n) { + void deallocate(T* p, std::size_t n) noexcept { (void)n; std::free(p); } }; + template < typename T, typename U > + bool operator==(const dummy_allocator&, const dummy_allocator&) noexcept { + return true; + } + + template < typename T, typename U > + bool operator!=(const dummy_allocator& l, const dummy_allocator& r) noexcept { + return !(l == r); + } + template < typename T > constexpr std::add_const_t& my_as_const(T& t) noexcept { return t; @@ -159,6 +175,10 @@ TEST_CASE("flat_set") { REQUIRE(s0 == set_t{1,2}); REQUIRE(i2 == std::make_pair(s0.begin() + 1, true)); + auto o2 = obj_t(2); + auto i3 = s0.insert(o2); + REQUIRE(i3 == std::make_pair(s0.begin() + 1, false)); + s0.insert(s0.cbegin(), 1); s0.insert(s0.cbegin(), 2); s0.insert(s0.cend(), 1); From 6cd6c416fcaf1c83baa5afb8c355811ca1905c24 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Sat, 4 May 2019 18:20:29 +0700 Subject: [PATCH 12/12] update README --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4ce8409..e6a1336 100644 --- a/README.md +++ b/README.md @@ -25,10 +25,11 @@ ## Installation -[flat.hpp][flat] is a single header library. All you need to do is copy the header file into your project and include this file: +[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.hpp" +#include "flat_set.hpp" // for flat_set +#include "flat_map.hpp" // for flat_map ``` ## API