From 00d676f998132642c172ee85baf90aa9f755be4b Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Mon, 27 May 2019 16:51:01 +0700 Subject: [PATCH 1/3] heterogeneous find, lower_bound and upper_bound --- .travis.yml | 1 - README.md | 36 +++++++ headers/flat.hpp/detail/is_transparent.hpp | 23 +++++ headers/flat.hpp/detail/pair_compare.hpp | 62 ++++++++++++ headers/flat.hpp/flat_map.hpp | 106 +++++++++++++-------- headers/flat.hpp/flat_multimap.hpp | 106 +++++++++++++-------- headers/flat.hpp/flat_multiset.hpp | 56 +++++++++++ headers/flat.hpp/flat_set.hpp | 56 +++++++++++ untests/flat_map_tests.cpp | 14 +++ untests/flat_multimap_tests.cpp | 14 +++ untests/flat_multiset_tests.cpp | 14 +++ untests/flat_set_tests.cpp | 14 +++ 12 files changed, 419 insertions(+), 83 deletions(-) create mode 100644 headers/flat.hpp/detail/is_transparent.hpp create mode 100644 headers/flat.hpp/detail/pair_compare.hpp diff --git a/.travis.yml b/.travis.yml index 8f3cc8b..1a7301c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,7 +35,6 @@ before_install: - if [ "$TRAVIS_OS_NAME" == 'osx' ]; then brew update; brew upgrade cmake; - brew install git-lfs; fi - if [ "$TRAVIS_OS_NAME" == 'linux' ]; then mkdir $HOME/cmake; diff --git a/README.md b/README.md index 7a1a839..95f119c 100644 --- a/README.md +++ b/README.md @@ -195,14 +195,23 @@ size_type count(const key_type& key) const; iterator find(const key_type& key); const_iterator find(const key_type& key) const; +template < typename K > iterator find(const K& key); +template < typename K > const_iterator find(const K& key) const; + std::pair equal_range(const key_type& key); std::pair equal_range(const key_type& key) const; iterator lower_bound(const key_type& key); const_iterator lower_bound(const key_type& key) const; +template < typename K > iterator lower_bound(const K& key); +template < typename K > const_iterator lower_bound(const K& key) const; + iterator upper_bound(const key_type& key); const_iterator upper_bound(const key_type& key) const; + +template < typename K > iterator upper_bound(const K& key); +template < typename K > const_iterator upper_bound(const K& key) const; ``` ### Observers @@ -426,14 +435,23 @@ size_type count(const key_type& key) const; iterator find(const key_type& key); const_iterator find(const key_type& key) const; +template < typename K > iterator find(const K& key); +template < typename K > const_iterator find(const K& key) const; + std::pair equal_range(const key_type& key); std::pair equal_range(const key_type& key) const; iterator lower_bound(const key_type& key); const_iterator lower_bound(const key_type& key) const; +template < typename K > iterator lower_bound(const K& key); +template < typename K > const_iterator lower_bound(const K& key) const; + iterator upper_bound(const key_type& key); const_iterator upper_bound(const key_type& key) const; + +template < typename K > iterator upper_bound(const K& key); +template < typename K > const_iterator upper_bound(const K& key) const; ``` ### Observers @@ -647,14 +665,23 @@ size_type count(const key_type& key) const; iterator find(const key_type& key); const_iterator find(const key_type& key) const; +template < typename K > iterator find(const K& key); +template < typename K > const_iterator find(const K& key) const; + std::pair equal_range(const key_type& key); std::pair equal_range(const key_type& key) const; iterator lower_bound(const key_type& key); const_iterator lower_bound(const key_type& key) const; +template < typename K > iterator lower_bound(const K& key); +template < typename K > const_iterator lower_bound(const K& key) const; + iterator upper_bound(const key_type& key); const_iterator upper_bound(const key_type& key) const; + +template < typename K > iterator upper_bound(const K& key); +template < typename K > const_iterator upper_bound(const K& key) const; ``` ### Observers @@ -878,14 +905,23 @@ size_type count(const key_type& key) const; iterator find(const key_type& key); const_iterator find(const key_type& key) const; +template < typename K > iterator find(const K& key); +template < typename K > const_iterator find(const K& key) const; + std::pair equal_range(const key_type& key); std::pair equal_range(const key_type& key) const; iterator lower_bound(const key_type& key); const_iterator lower_bound(const key_type& key) const; +template < typename K > iterator lower_bound(const K& key); +template < typename K > const_iterator lower_bound(const K& key) const; + iterator upper_bound(const key_type& key); const_iterator upper_bound(const key_type& key) const; + +template < typename K > iterator upper_bound(const K& key); +template < typename K > const_iterator upper_bound(const K& key) const; ``` ### Observers diff --git a/headers/flat.hpp/detail/is_transparent.hpp b/headers/flat.hpp/detail/is_transparent.hpp new file mode 100644 index 0000000..2f6ec11 --- /dev/null +++ b/headers/flat.hpp/detail/is_transparent.hpp @@ -0,0 +1,23 @@ +/******************************************************************************* + * This file is part of the "https://github.com/blackmatov/flat.hpp" + * For conditions of distribution and use, see copyright notice in LICENSE.md + * Copyright (C) 2019, by Matvey Cherevko (blackmatov@gmail.com) + ******************************************************************************/ + +#pragma once + +#include + +namespace flat_hpp::detail +{ + template < typename T, typename U, typename = void > + struct is_transparent + : std::false_type {}; + + template < typename T, typename U > + struct is_transparent> + : std::true_type {}; + + template < typename T, typename U > + inline constexpr bool is_transparent_v = is_transparent::value; +} diff --git a/headers/flat.hpp/detail/pair_compare.hpp b/headers/flat.hpp/detail/pair_compare.hpp new file mode 100644 index 0000000..3d90c44 --- /dev/null +++ b/headers/flat.hpp/detail/pair_compare.hpp @@ -0,0 +1,62 @@ +/******************************************************************************* + * This file is part of the "https://github.com/blackmatov/flat.hpp" + * For conditions of distribution and use, see copyright notice in LICENSE.md + * Copyright (C) 2019, by Matvey Cherevko (blackmatov@gmail.com) + ******************************************************************************/ + +#pragma once + +#include "is_transparent.hpp" + +namespace flat_hpp::detail +{ + template < typename Pair, typename Compare > + class pair_compare : public Compare { + public: + pair_compare() = default; + + pair_compare(const Compare& compare) + : Compare(compare) {} + + bool operator()( + const typename Pair::first_type& l, + const typename Pair::first_type& r) const + { + return Compare::operator()(l, r); + } + + bool operator()(const Pair& l, const Pair& r) const { + return Compare::operator()(l.first, r.first); + } + + bool operator()( + const typename Pair::first_type& l, + const Pair& r) const + { + return Compare::operator()(l, r.first); + } + + bool operator()( + const Pair& l, + const typename Pair::first_type& r) const + { + return Compare::operator()(l.first, r); + } + + template < typename K > + std::enable_if_t< + is_transparent_v, + bool> + operator()(const K& l, const Pair& r) const { + return Compare::operator()(l, r.first); + } + + template < typename K > + std::enable_if_t< + is_transparent_v, + bool> + operator()(const Pair& l, const K& r) const { + return Compare::operator()(l.first, r); + } + }; +} diff --git a/headers/flat.hpp/flat_map.hpp b/headers/flat.hpp/flat_map.hpp index 54baa50..c2c3f66 100644 --- a/headers/flat.hpp/flat_map.hpp +++ b/headers/flat.hpp/flat_map.hpp @@ -15,55 +15,21 @@ #include #include +#include "detail/pair_compare.hpp" +#include "detail/is_transparent.hpp" + namespace flat_hpp { - namespace detail - { - template < typename Value, typename Compare > - class flat_map_compare : public Compare { - public: - flat_map_compare() = default; - - flat_map_compare(const Compare& compare) - : Compare(compare) {} - - bool operator()( - const typename Value::first_type& l, - const typename Value::first_type& r) const - { - return Compare::operator()(l, r); - } - - bool operator()( - const typename Value::first_type& l, - const Value& r) const - { - return Compare::operator()(l, r.first); - } - - bool operator()( - const Value& l, - const typename Value::first_type& r) const - { - return Compare::operator()(l.first, r); - } - - bool operator()(const Value& l, const Value& r) const { - return Compare::operator()(l.first, r.first); - } - }; - } - template < typename Key , typename Value , typename Compare = std::less , typename Container = std::vector> > class flat_map - : private detail::flat_map_compare< + : private detail::pair_compare< typename Container::value_type, Compare> { - using base_type = detail::flat_map_compare< + using base_type = detail::pair_compare< typename Container::value_type, Compare>; public: @@ -386,14 +352,36 @@ namespace flat_hpp iterator find(const key_type& key) { const iterator iter = lower_bound(key); - return iter != end() && !this->operator()(key, iter->first) + return iter != end() && !this->operator()(key, *iter) ? iter : end(); } const_iterator find(const key_type& key) const { const const_iterator iter = lower_bound(key); - return iter != end() && !this->operator()(key, iter->first) + return iter != end() && !this->operator()(key, *iter) + ? iter + : end(); + } + + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + iterator> + find(const K& key) { + const iterator iter = lower_bound(key); + return iter != end() && !this->operator()(key, *iter) + ? iter + : end(); + } + + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + const_iterator> + find(const K& key) const { + const const_iterator iter = lower_bound(key); + return iter != end() && !this->operator()(key, *iter) ? iter : end(); } @@ -418,6 +406,24 @@ namespace flat_hpp return std::lower_bound(begin(), end(), key, comp); } + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + iterator> + lower_bound(const K& key) { + const base_type& comp = *this; + return std::lower_bound(begin(), end(), key, comp); + } + + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + const_iterator> + lower_bound(const K& key) const { + const base_type& comp = *this; + return std::lower_bound(begin(), end(), key, comp); + } + iterator upper_bound(const key_type& key) { const base_type& comp = *this; return std::upper_bound(begin(), end(), key, comp); @@ -428,6 +434,24 @@ namespace flat_hpp return std::upper_bound(begin(), end(), key, comp); } + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + iterator> + upper_bound(const K& key) { + const base_type& comp = *this; + return std::upper_bound(begin(), end(), key, comp); + } + + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + const_iterator> + upper_bound(const K& key) const { + const base_type& comp = *this; + return std::upper_bound(begin(), end(), key, comp); + } + key_compare key_comp() const { return *this; } diff --git a/headers/flat.hpp/flat_multimap.hpp b/headers/flat.hpp/flat_multimap.hpp index c20d395..3cd2d5a 100644 --- a/headers/flat.hpp/flat_multimap.hpp +++ b/headers/flat.hpp/flat_multimap.hpp @@ -15,55 +15,21 @@ #include #include +#include "detail/pair_compare.hpp" +#include "detail/is_transparent.hpp" + namespace flat_hpp { - namespace detail - { - template < typename Value, typename Compare > - class flat_multimap_compare : public Compare { - public: - flat_multimap_compare() = default; - - flat_multimap_compare(const Compare& compare) - : Compare(compare) {} - - bool operator()( - const typename Value::first_type& l, - const typename Value::first_type& r) const - { - return Compare::operator()(l, r); - } - - bool operator()( - const typename Value::first_type& l, - const Value& r) const - { - return Compare::operator()(l, r.first); - } - - bool operator()( - const Value& l, - const typename Value::first_type& r) const - { - return Compare::operator()(l.first, r); - } - - bool operator()(const Value& l, const Value& r) const { - return Compare::operator()(l.first, r.first); - } - }; - } - template < typename Key , typename Value , typename Compare = std::less , typename Container = std::vector> > class flat_multimap - : private detail::flat_multimap_compare< + : private detail::pair_compare< typename Container::value_type, Compare> { - using base_type = detail::flat_multimap_compare< + using base_type = detail::pair_compare< typename Container::value_type, Compare>; public: @@ -382,14 +348,36 @@ namespace flat_hpp iterator find(const key_type& key) { const iterator iter = lower_bound(key); - return iter != end() && !this->operator()(key, iter->first) + return iter != end() && !this->operator()(key, *iter) ? iter : end(); } const_iterator find(const key_type& key) const { const const_iterator iter = lower_bound(key); - return iter != end() && !this->operator()(key, iter->first) + return iter != end() && !this->operator()(key, *iter) + ? iter + : end(); + } + + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + iterator> + find(const K& key) { + const iterator iter = lower_bound(key); + return iter != end() && !this->operator()(key, *iter) + ? iter + : end(); + } + + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + const_iterator> + find(const K& key) const { + const const_iterator iter = lower_bound(key); + return iter != end() && !this->operator()(key, *iter) ? iter : end(); } @@ -414,6 +402,24 @@ namespace flat_hpp return std::lower_bound(begin(), end(), key, comp); } + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + iterator> + lower_bound(const K& key) { + const base_type& comp = *this; + return std::lower_bound(begin(), end(), key, comp); + } + + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + const_iterator> + lower_bound(const K& key) const { + const base_type& comp = *this; + return std::lower_bound(begin(), end(), key, comp); + } + iterator upper_bound(const key_type& key) { const base_type& comp = *this; return std::upper_bound(begin(), end(), key, comp); @@ -424,6 +430,24 @@ namespace flat_hpp return std::upper_bound(begin(), end(), key, comp); } + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + iterator> + upper_bound(const K& key) { + const base_type& comp = *this; + return std::upper_bound(begin(), end(), key, comp); + } + + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + const_iterator> + upper_bound(const K& key) const { + const base_type& comp = *this; + return std::upper_bound(begin(), end(), key, comp); + } + key_compare key_comp() const { return *this; } diff --git a/headers/flat.hpp/flat_multiset.hpp b/headers/flat.hpp/flat_multiset.hpp index e6e9111..d361844 100644 --- a/headers/flat.hpp/flat_multiset.hpp +++ b/headers/flat.hpp/flat_multiset.hpp @@ -15,6 +15,8 @@ #include #include +#include "detail/is_transparent.hpp" + namespace flat_hpp { template < typename Key @@ -309,6 +311,28 @@ namespace flat_hpp : end(); } + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + iterator> + find(const K& key) { + const iterator iter = lower_bound(key); + return iter != end() && !this->operator()(key, *iter) + ? iter + : end(); + } + + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + const_iterator> + find(const K& key) const { + const const_iterator iter = lower_bound(key); + return iter != end() && !this->operator()(key, *iter) + ? iter + : end(); + } + std::pair equal_range(const key_type& key) { return std::equal_range(begin(), end(), key, key_comp()); } @@ -325,6 +349,22 @@ namespace flat_hpp return std::lower_bound(begin(), end(), key, key_comp()); } + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + iterator> + lower_bound(const K& key) { + return std::lower_bound(begin(), end(), key, key_comp()); + } + + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + const_iterator> + lower_bound(const K& key) const { + return std::lower_bound(begin(), end(), key, key_comp()); + } + iterator upper_bound(const key_type& key) { return std::upper_bound(begin(), end(), key, key_comp()); } @@ -333,6 +373,22 @@ namespace flat_hpp return std::upper_bound(begin(), end(), key, key_comp()); } + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + iterator> + upper_bound(const K& key) { + return std::upper_bound(begin(), end(), key, key_comp()); + } + + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + const_iterator> + upper_bound(const K& key) const { + return std::upper_bound(begin(), end(), key, key_comp()); + } + key_compare key_comp() const { return *this; } diff --git a/headers/flat.hpp/flat_set.hpp b/headers/flat.hpp/flat_set.hpp index d5cf454..3cdb994 100644 --- a/headers/flat.hpp/flat_set.hpp +++ b/headers/flat.hpp/flat_set.hpp @@ -15,6 +15,8 @@ #include #include +#include "detail/is_transparent.hpp" + namespace flat_hpp { template < typename Key @@ -313,6 +315,28 @@ namespace flat_hpp : end(); } + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + iterator> + find(const K& key) { + const iterator iter = lower_bound(key); + return iter != end() && !this->operator()(key, *iter) + ? iter + : end(); + } + + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + const_iterator> + find(const K& key) const { + const const_iterator iter = lower_bound(key); + return iter != end() && !this->operator()(key, *iter) + ? iter + : end(); + } + std::pair equal_range(const key_type& key) { return std::equal_range(begin(), end(), key, key_comp()); } @@ -329,6 +353,22 @@ namespace flat_hpp return std::lower_bound(begin(), end(), key, key_comp()); } + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + iterator> + lower_bound(const K& key) { + return std::lower_bound(begin(), end(), key, key_comp()); + } + + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + const_iterator> + lower_bound(const K& key) const { + return std::lower_bound(begin(), end(), key, key_comp()); + } + iterator upper_bound(const key_type& key) { return std::upper_bound(begin(), end(), key, key_comp()); } @@ -337,6 +377,22 @@ namespace flat_hpp return std::upper_bound(begin(), end(), key, key_comp()); } + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + iterator> + upper_bound(const K& key) { + return std::upper_bound(begin(), end(), key, key_comp()); + } + + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + const_iterator> + upper_bound(const K& key) const { + return std::upper_bound(begin(), end(), key, key_comp()); + } + key_compare key_comp() const { return *this; } diff --git a/untests/flat_map_tests.cpp b/untests/flat_map_tests.cpp index ced86ce..935b90b 100644 --- a/untests/flat_map_tests.cpp +++ b/untests/flat_map_tests.cpp @@ -9,6 +9,9 @@ #include +#include +#include + #include using namespace flat_hpp; @@ -54,6 +57,10 @@ namespace } TEST_CASE("flat_map") { + SECTION("detail") { + STATIC_REQUIRE(detail::is_transparent, int>::value); + STATIC_REQUIRE_FALSE(detail::is_transparent, int>::value); + } SECTION("sizeof") { REQUIRE(sizeof(flat_map) == sizeof(std::vector>)); @@ -403,6 +410,13 @@ TEST_CASE("flat_map") { REQUIRE(my_as_const(s0).lower_bound(-1) == s0.cbegin()); REQUIRE(my_as_const(s0).lower_bound(7) == s0.cbegin() + 3); } + { + flat_map> s0{{"hello", 42}, {"world", 84}}; + REQUIRE(s0.find(std::string_view("hello")) == s0.begin()); + REQUIRE(my_as_const(s0).find(std::string_view("world")) == s0.begin() + 1); + REQUIRE(s0.find(std::string_view("42")) == s0.end()); + REQUIRE(my_as_const(s0).find(std::string_view("42")) == s0.cend()); + } } SECTION("observers") { struct my_less { diff --git a/untests/flat_multimap_tests.cpp b/untests/flat_multimap_tests.cpp index ccaf5bd..cd97dfa 100644 --- a/untests/flat_multimap_tests.cpp +++ b/untests/flat_multimap_tests.cpp @@ -9,6 +9,9 @@ #include +#include +#include + #include using namespace flat_hpp; @@ -54,6 +57,10 @@ namespace } TEST_CASE("flat_multimap") { + SECTION("detail") { + STATIC_REQUIRE(detail::is_transparent, int>::value); + STATIC_REQUIRE_FALSE(detail::is_transparent, int>::value); + } SECTION("sizeof") { REQUIRE(sizeof(flat_multimap) == sizeof(std::vector>)); @@ -405,6 +412,13 @@ TEST_CASE("flat_multimap") { REQUIRE(my_as_const(s0).lower_bound(-1) == s0.cbegin()); REQUIRE(my_as_const(s0).lower_bound(7) == s0.cbegin() + 4); } + { + flat_multimap> s0{{"hello", 42}, {"world", 84}}; + REQUIRE(s0.find(std::string_view("hello")) == s0.begin()); + REQUIRE(my_as_const(s0).find(std::string_view("world")) == s0.begin() + 1); + REQUIRE(s0.find(std::string_view("42")) == s0.end()); + REQUIRE(my_as_const(s0).find(std::string_view("42")) == s0.cend()); + } } SECTION("observers") { struct my_less { diff --git a/untests/flat_multiset_tests.cpp b/untests/flat_multiset_tests.cpp index 669d799..a5ba1fb 100644 --- a/untests/flat_multiset_tests.cpp +++ b/untests/flat_multiset_tests.cpp @@ -9,6 +9,9 @@ #include +#include +#include + #include using namespace flat_hpp; @@ -54,6 +57,10 @@ namespace } TEST_CASE("flat_multiset") { + SECTION("detail") { + STATIC_REQUIRE(detail::is_transparent, int>::value); + STATIC_REQUIRE_FALSE(detail::is_transparent, int>::value); + } SECTION("sizeof") { REQUIRE(sizeof(flat_multiset) == sizeof(std::vector)); @@ -381,6 +388,13 @@ TEST_CASE("flat_multiset") { REQUIRE(my_as_const(s0).lower_bound(-1) == s0.cbegin()); REQUIRE(my_as_const(s0).lower_bound(7) == s0.cbegin() + 4); } + { + flat_multiset> s0{"hello", "world"}; + REQUIRE(s0.find(std::string_view("hello")) == s0.begin()); + REQUIRE(my_as_const(s0).find(std::string_view("world")) == s0.begin() + 1); + REQUIRE(s0.find(std::string_view("42")) == s0.end()); + REQUIRE(my_as_const(s0).find(std::string_view("42")) == s0.cend()); + } } SECTION("observers") { struct my_less { diff --git a/untests/flat_set_tests.cpp b/untests/flat_set_tests.cpp index 6029598..60f2c52 100644 --- a/untests/flat_set_tests.cpp +++ b/untests/flat_set_tests.cpp @@ -9,6 +9,9 @@ #include +#include +#include + #include using namespace flat_hpp; @@ -54,6 +57,10 @@ namespace } TEST_CASE("flat_set") { + SECTION("detail") { + STATIC_REQUIRE(detail::is_transparent, int>::value); + STATIC_REQUIRE_FALSE(detail::is_transparent, int>::value); + } SECTION("sizeof") { REQUIRE(sizeof(flat_set) == sizeof(std::vector)); @@ -379,6 +386,13 @@ TEST_CASE("flat_set") { REQUIRE(my_as_const(s0).lower_bound(-1) == s0.cbegin()); REQUIRE(my_as_const(s0).lower_bound(7) == s0.cbegin() + 3); } + { + flat_set> s0{"hello", "world"}; + REQUIRE(s0.find(std::string_view("hello")) == s0.begin()); + REQUIRE(my_as_const(s0).find(std::string_view("world")) == s0.begin() + 1); + REQUIRE(s0.find(std::string_view("42")) == s0.end()); + REQUIRE(my_as_const(s0).find(std::string_view("42")) == s0.cend()); + } } SECTION("observers") { struct my_less { From 6eaae5784f2dbf6ee6384dcc88e4fc9e2ec4b9eb Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Mon, 27 May 2019 18:27:26 +0700 Subject: [PATCH 2/3] heterogeneous at, erase, count and equal_range --- headers/flat.hpp/flat_map.hpp | 64 +++++++++++++++++++++++++++++- headers/flat.hpp/flat_multimap.hpp | 62 +++++++++++++++++++++++++++++ headers/flat.hpp/flat_multiset.hpp | 36 +++++++++++++++++ headers/flat.hpp/flat_set.hpp | 38 +++++++++++++++++- untests/flat_map_tests.cpp | 24 +++++++---- untests/flat_multimap_tests.cpp | 24 +++++++---- untests/flat_multiset_tests.cpp | 22 ++++++---- untests/flat_set_tests.cpp | 22 ++++++---- 8 files changed, 262 insertions(+), 30 deletions(-) diff --git a/headers/flat.hpp/flat_map.hpp b/headers/flat.hpp/flat_map.hpp index c2c3f66..a6ddb38 100644 --- a/headers/flat.hpp/flat_map.hpp +++ b/headers/flat.hpp/flat_map.hpp @@ -265,6 +265,30 @@ namespace flat_hpp throw std::out_of_range("flat_map::at: key not found"); } + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + mapped_type&> + at(const K& key) { + const iterator iter = find(key); + if ( iter != end() ) { + return iter->second; + } + throw std::out_of_range("flat_map::at: key not found"); + } + + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + const mapped_type&> + at(const K& key) const { + const const_iterator iter = find(key); + if ( iter != end() ) { + return iter->second; + } + throw std::out_of_range("flat_map::at: key not found"); + } + std::pair insert(value_type&& value) { const iterator iter = lower_bound(value.first); return iter == end() || this->operator()(value, *iter) @@ -328,7 +352,18 @@ namespace flat_hpp } size_type erase(const key_type& key) { - const iterator iter = find(key); + const const_iterator iter = find(key); + return iter != end() + ? (erase(iter), 1) + : 0; + } + + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + size_type> + erase(const K& key) { + const const_iterator iter = find(key); return iter != end() ? (erase(iter), 1) : 0; @@ -350,6 +385,15 @@ namespace flat_hpp return iter != end() ? 1 : 0; } + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + size_type> + count(const K& key) const { + const const_iterator iter = find(key); + return iter != end() ? 1 : 0; + } + iterator find(const key_type& key) { const iterator iter = lower_bound(key); return iter != end() && !this->operator()(key, *iter) @@ -396,6 +440,24 @@ namespace flat_hpp return std::equal_range(begin(), end(), key, comp); } + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + std::pair> + equal_range(const K& key) { + const base_type& comp = *this; + return std::equal_range(begin(), end(), key, comp); + } + + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + std::pair> + equal_range(const K& key) const { + const base_type& comp = *this; + return std::equal_range(begin(), end(), key, comp); + } + iterator lower_bound(const key_type& key) { const base_type& comp = *this; return std::lower_bound(begin(), end(), key, comp); diff --git a/headers/flat.hpp/flat_multimap.hpp b/headers/flat.hpp/flat_multimap.hpp index 3cd2d5a..aeccbbf 100644 --- a/headers/flat.hpp/flat_multimap.hpp +++ b/headers/flat.hpp/flat_multimap.hpp @@ -265,6 +265,30 @@ namespace flat_hpp throw std::out_of_range("flat_multimap::at: key not found"); } + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + mapped_type&> + at(const K& key) { + const iterator iter = find(key); + if ( iter != end() ) { + return iter->second; + } + throw std::out_of_range("flat_multimap::at: key not found"); + } + + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + const mapped_type&> + at(const K& key) const { + const const_iterator iter = find(key); + if ( iter != end() ) { + return iter->second; + } + throw std::out_of_range("flat_multimap::at: key not found"); + } + iterator insert(value_type&& value) { const iterator iter = upper_bound(value.first); return data_.insert(iter, std::move(value)); @@ -330,6 +354,17 @@ namespace flat_hpp return r; } + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + size_type> + erase(const K& key) { + const auto p = equal_range(key); + size_type r = std::distance(p.first, p.second); + erase(p.first, p.second); + return r; + } + void swap(flat_multimap& other) noexcept(std::is_nothrow_swappable_v && std::is_nothrow_swappable_v) @@ -346,6 +381,15 @@ namespace flat_hpp return std::distance(p.first, p.second); } + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + size_type> + count(const K& key) const { + const auto p = equal_range(key); + return std::distance(p.first, p.second); + } + iterator find(const key_type& key) { const iterator iter = lower_bound(key); return iter != end() && !this->operator()(key, *iter) @@ -392,6 +436,24 @@ namespace flat_hpp return std::equal_range(begin(), end(), key, comp); } + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + std::pair> + equal_range(const K& key) { + const base_type& comp = *this; + return std::equal_range(begin(), end(), key, comp); + } + + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + std::pair> + equal_range(const K& key) const { + const base_type& comp = *this; + return std::equal_range(begin(), end(), key, comp); + } + iterator lower_bound(const key_type& key) { const base_type& comp = *this; return std::lower_bound(begin(), end(), key, comp); diff --git a/headers/flat.hpp/flat_multiset.hpp b/headers/flat.hpp/flat_multiset.hpp index d361844..6fdd395 100644 --- a/headers/flat.hpp/flat_multiset.hpp +++ b/headers/flat.hpp/flat_multiset.hpp @@ -281,6 +281,17 @@ namespace flat_hpp return r; } + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + size_type> + erase(const K& key) { + const auto p = equal_range(key); + size_type r = std::distance(p.first, p.second); + erase(p.first, p.second); + return r; + } + void swap(flat_multiset& other) noexcept(std::is_nothrow_swappable_v && std::is_nothrow_swappable_v) @@ -297,6 +308,15 @@ namespace flat_hpp return std::distance(p.first, p.second); } + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + size_type> + count(const K& key) const { + const auto p = equal_range(key); + return std::distance(p.first, p.second); + } + iterator find(const key_type& key) { const iterator iter = lower_bound(key); return iter != end() && !this->operator()(key, *iter) @@ -341,6 +361,22 @@ namespace flat_hpp return std::equal_range(begin(), end(), key, key_comp()); } + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + std::pair> + equal_range(const K& key) { + return std::equal_range(begin(), end(), key, key_comp()); + } + + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + std::pair> + equal_range(const K& key) const { + return std::equal_range(begin(), end(), key, key_comp()); + } + iterator lower_bound(const key_type& key) { return std::lower_bound(begin(), end(), key, key_comp()); } diff --git a/headers/flat.hpp/flat_set.hpp b/headers/flat.hpp/flat_set.hpp index 3cdb994..21e06ab 100644 --- a/headers/flat.hpp/flat_set.hpp +++ b/headers/flat.hpp/flat_set.hpp @@ -279,7 +279,18 @@ namespace flat_hpp } size_type erase(const key_type& key) { - const iterator iter = find(key); + const const_iterator iter = find(key); + return iter != end() + ? (erase(iter), 1) + : 0; + } + + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + size_type> + erase(const K& key) { + const const_iterator iter = find(key); return iter != end() ? (erase(iter), 1) : 0; @@ -301,6 +312,15 @@ namespace flat_hpp return iter != end() ? 1 : 0; } + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + size_type> + count(const K& key) const { + const const_iterator iter = find(key); + return iter != end() ? 1 : 0; + } + iterator find(const key_type& key) { const iterator iter = lower_bound(key); return iter != end() && !this->operator()(key, *iter) @@ -345,6 +365,22 @@ namespace flat_hpp return std::equal_range(begin(), end(), key, key_comp()); } + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + std::pair> + equal_range(const K& key) { + return std::equal_range(begin(), end(), key, key_comp()); + } + + template < typename K > + std::enable_if_t< + detail::is_transparent_v, + std::pair> + equal_range(const K& key) const { + return std::equal_range(begin(), end(), key, key_comp()); + } + iterator lower_bound(const key_type& key) { return std::lower_bound(begin(), end(), key, key_comp()); } diff --git a/untests/flat_map_tests.cpp b/untests/flat_map_tests.cpp index 935b90b..45fbd38 100644 --- a/untests/flat_map_tests.cpp +++ b/untests/flat_map_tests.cpp @@ -410,13 +410,23 @@ TEST_CASE("flat_map") { REQUIRE(my_as_const(s0).lower_bound(-1) == s0.cbegin()); REQUIRE(my_as_const(s0).lower_bound(7) == s0.cbegin() + 3); } - { - flat_map> s0{{"hello", 42}, {"world", 84}}; - REQUIRE(s0.find(std::string_view("hello")) == s0.begin()); - REQUIRE(my_as_const(s0).find(std::string_view("world")) == s0.begin() + 1); - REQUIRE(s0.find(std::string_view("42")) == s0.end()); - REQUIRE(my_as_const(s0).find(std::string_view("42")) == s0.cend()); - } + } + SECTION("heterogeneous") { + flat_map> s0{{"hello", 42}, {"world", 84}}; + REQUIRE(s0.find(std::string_view("hello")) == s0.begin()); + REQUIRE(my_as_const(s0).find(std::string_view("world")) == s0.begin() + 1); + REQUIRE(s0.find(std::string_view("42")) == s0.end()); + REQUIRE(my_as_const(s0).find(std::string_view("42")) == s0.cend()); + + REQUIRE(my_as_const(s0).count(std::string_view("hello")) == 1); + REQUIRE(my_as_const(s0).count(std::string_view("hello_42")) == 0); + + REQUIRE(s0.upper_bound(std::string_view("hello")) == s0.begin() + 1); + REQUIRE(my_as_const(s0).upper_bound(std::string_view("hello")) == s0.begin() + 1); + + REQUIRE(s0.erase(std::string_view("hello")) == 1); + REQUIRE(s0.at(std::string_view("world")) == 84); + REQUIRE(my_as_const(s0).at(std::string_view("world")) == 84); } SECTION("observers") { struct my_less { diff --git a/untests/flat_multimap_tests.cpp b/untests/flat_multimap_tests.cpp index cd97dfa..0c9953a 100644 --- a/untests/flat_multimap_tests.cpp +++ b/untests/flat_multimap_tests.cpp @@ -412,13 +412,23 @@ TEST_CASE("flat_multimap") { REQUIRE(my_as_const(s0).lower_bound(-1) == s0.cbegin()); REQUIRE(my_as_const(s0).lower_bound(7) == s0.cbegin() + 4); } - { - flat_multimap> s0{{"hello", 42}, {"world", 84}}; - REQUIRE(s0.find(std::string_view("hello")) == s0.begin()); - REQUIRE(my_as_const(s0).find(std::string_view("world")) == s0.begin() + 1); - REQUIRE(s0.find(std::string_view("42")) == s0.end()); - REQUIRE(my_as_const(s0).find(std::string_view("42")) == s0.cend()); - } + } + SECTION("heterogeneous") { + flat_multimap> s0{{"hello", 42}, {"world", 84}}; + REQUIRE(s0.find(std::string_view("hello")) == s0.begin()); + REQUIRE(my_as_const(s0).find(std::string_view("world")) == s0.begin() + 1); + REQUIRE(s0.find(std::string_view("42")) == s0.end()); + REQUIRE(my_as_const(s0).find(std::string_view("42")) == s0.cend()); + + REQUIRE(my_as_const(s0).count(std::string_view("hello")) == 1); + REQUIRE(my_as_const(s0).count(std::string_view("hello_42")) == 0); + + REQUIRE(s0.upper_bound(std::string_view("hello")) == s0.begin() + 1); + REQUIRE(my_as_const(s0).upper_bound(std::string_view("hello")) == s0.begin() + 1); + + REQUIRE(s0.erase(std::string_view("hello")) == 1); + REQUIRE(s0.at(std::string_view("world")) == 84); + REQUIRE(my_as_const(s0).at(std::string_view("world")) == 84); } SECTION("observers") { struct my_less { diff --git a/untests/flat_multiset_tests.cpp b/untests/flat_multiset_tests.cpp index a5ba1fb..9e7833f 100644 --- a/untests/flat_multiset_tests.cpp +++ b/untests/flat_multiset_tests.cpp @@ -388,13 +388,21 @@ TEST_CASE("flat_multiset") { REQUIRE(my_as_const(s0).lower_bound(-1) == s0.cbegin()); REQUIRE(my_as_const(s0).lower_bound(7) == s0.cbegin() + 4); } - { - flat_multiset> s0{"hello", "world"}; - REQUIRE(s0.find(std::string_view("hello")) == s0.begin()); - REQUIRE(my_as_const(s0).find(std::string_view("world")) == s0.begin() + 1); - REQUIRE(s0.find(std::string_view("42")) == s0.end()); - REQUIRE(my_as_const(s0).find(std::string_view("42")) == s0.cend()); - } + } + SECTION("heterogeneous") { + flat_multiset> s0{"hello", "world"}; + REQUIRE(s0.find(std::string_view("hello")) == s0.begin()); + REQUIRE(my_as_const(s0).find(std::string_view("world")) == s0.begin() + 1); + REQUIRE(s0.find(std::string_view("42")) == s0.end()); + REQUIRE(my_as_const(s0).find(std::string_view("42")) == s0.cend()); + + REQUIRE(my_as_const(s0).count(std::string_view("hello")) == 1); + REQUIRE(my_as_const(s0).count(std::string_view("hello_42")) == 0); + + REQUIRE(s0.upper_bound(std::string_view("hello")) == s0.begin() + 1); + REQUIRE(my_as_const(s0).upper_bound(std::string_view("hello")) == s0.begin() + 1); + + REQUIRE(s0.erase(std::string_view("hello")) == 1); } SECTION("observers") { struct my_less { diff --git a/untests/flat_set_tests.cpp b/untests/flat_set_tests.cpp index 60f2c52..83dbd23 100644 --- a/untests/flat_set_tests.cpp +++ b/untests/flat_set_tests.cpp @@ -386,13 +386,21 @@ TEST_CASE("flat_set") { REQUIRE(my_as_const(s0).lower_bound(-1) == s0.cbegin()); REQUIRE(my_as_const(s0).lower_bound(7) == s0.cbegin() + 3); } - { - flat_set> s0{"hello", "world"}; - REQUIRE(s0.find(std::string_view("hello")) == s0.begin()); - REQUIRE(my_as_const(s0).find(std::string_view("world")) == s0.begin() + 1); - REQUIRE(s0.find(std::string_view("42")) == s0.end()); - REQUIRE(my_as_const(s0).find(std::string_view("42")) == s0.cend()); - } + } + SECTION("heterogeneous") { + flat_set> s0{"hello", "world"}; + REQUIRE(s0.find(std::string_view("hello")) == s0.begin()); + REQUIRE(my_as_const(s0).find(std::string_view("world")) == s0.begin() + 1); + REQUIRE(s0.find(std::string_view("42")) == s0.end()); + REQUIRE(my_as_const(s0).find(std::string_view("42")) == s0.cend()); + + REQUIRE(my_as_const(s0).count(std::string_view("hello")) == 1); + REQUIRE(my_as_const(s0).count(std::string_view("hello_42")) == 0); + + REQUIRE(s0.upper_bound(std::string_view("hello")) == s0.begin() + 1); + REQUIRE(my_as_const(s0).upper_bound(std::string_view("hello")) == s0.begin() + 1); + + REQUIRE(s0.erase(std::string_view("hello")) == 1); } SECTION("observers") { struct my_less { From 911a790f7d1a922904ea57b23da004d6a8d03d21 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Mon, 27 May 2019 19:55:23 +0700 Subject: [PATCH 3/3] drop old compilers, update README --- .appveyor.yml | 1 - .travis.yml | 8 -------- README.md | 26 ++++++++++++++++++++++++++ 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 27089cb..4f3132d 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,7 +1,6 @@ version: "{build}" shallow_clone: true image: - - Visual Studio 2015 - Visual Studio 2017 - Visual Studio 2019 Preview platform: diff --git a/.travis.yml b/.travis.yml index 1a7301c..739cd3b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,14 +9,6 @@ matrix: dist: trusty addons: { apt: { sources: ubuntu-toolchain-r-test, packages: ["xorg-dev", "g++-8"] } } env: MATRIX_EVAL="CC=gcc-8 && CXX=g++-8" - - os: linux - dist: trusty - addons: { apt: { sources: ["ubuntu-toolchain-r-test", "llvm-toolchain-trusty-5.0"], packages: ["xorg-dev", "clang-5.0", "g++-7"] } } - env: MATRIX_EVAL="CC=clang-5.0 && CXX=clang++-5.0" - - os: linux - dist: trusty - addons: { apt: { sources: ["ubuntu-toolchain-r-test", "llvm-toolchain-trusty-6.0"], packages: ["xorg-dev", "clang-6.0", "g++-7"] } } - env: MATRIX_EVAL="CC=clang-6.0 && CXX=clang++-6.0" - os: linux dist: trusty addons: { apt: { sources: ["ubuntu-toolchain-r-test", "llvm-toolchain-trusty-7"], packages: ["xorg-dev", "clang-7", "g++-7"] } } diff --git a/README.md b/README.md index 95f119c..eddf500 100644 --- a/README.md +++ b/README.md @@ -183,6 +183,7 @@ void clear(); iterator erase(const_iterator iter); iterator erase(const_iterator first, const_iterator last); size_type erase(const key_type& key); +template < typename K > size_type erase(const K& key); void swap(flat_set& other); ``` @@ -191,6 +192,7 @@ void swap(flat_set& other); ```cpp size_type count(const key_type& key) const; +template < typename K > size_type count(const K& key) const; iterator find(const key_type& key); const_iterator find(const key_type& key) const; @@ -201,6 +203,9 @@ template < typename K > const_iterator find(const K& key) const; std::pair equal_range(const key_type& key); std::pair equal_range(const key_type& key) const; +template < typename K > std::pair equal_range(const K& key); +template < typename K > std::pair equal_range(const K& key) const; + iterator lower_bound(const key_type& key); const_iterator lower_bound(const key_type& key) const; @@ -399,6 +404,9 @@ mapped_type& operator[](const key_type& key); mapped_type& at(const key_type& key); const mapped_type& at(const key_type& key) const; + +template < typename K > mapped_type& at(const K& key); +template < typename K > const mapped_type& at(const K& key) const; ``` ### Modifiers @@ -423,6 +431,7 @@ void clear(); iterator erase(const_iterator iter); iterator erase(const_iterator first, const_iterator last); size_type erase(const key_type& key); +template < typename K > size_type erase(const K& key); void swap(flat_map& other) ``` @@ -431,6 +440,7 @@ void swap(flat_map& other) ```cpp size_type count(const key_type& key) const; +template < typename K > size_type count(const K& key) const; iterator find(const key_type& key); const_iterator find(const key_type& key) const; @@ -441,6 +451,9 @@ template < typename K > const_iterator find(const K& key) const; std::pair equal_range(const key_type& key); std::pair equal_range(const key_type& key) const; +template < typename K > std::pair equal_range(const K& key); +template < typename K > std::pair equal_range(const K& key) const; + iterator lower_bound(const key_type& key); const_iterator lower_bound(const key_type& key) const; @@ -653,6 +666,7 @@ void clear(); iterator erase(const_iterator iter); iterator erase(const_iterator first, const_iterator last); size_type erase(const key_type& key); +template < typename K > size_type erase(const K& key); void swap(flat_multiset& other); ``` @@ -661,6 +675,7 @@ void swap(flat_multiset& other); ```cpp size_type count(const key_type& key) const; +template < typename K > size_type count(const K& key) const; iterator find(const key_type& key); const_iterator find(const key_type& key) const; @@ -671,6 +686,9 @@ template < typename K > const_iterator find(const K& key) const; std::pair equal_range(const key_type& key); std::pair equal_range(const key_type& key) const; +template < typename K > std::pair equal_range(const K& key); +template < typename K > std::pair equal_range(const K& key) const; + iterator lower_bound(const key_type& key); const_iterator lower_bound(const key_type& key) const; @@ -869,6 +887,9 @@ mapped_type& operator[](const key_type& key); mapped_type& at(const key_type& key); const mapped_type& at(const key_type& key) const; + +template < typename K > mapped_type& at(const K& key); +template < typename K > const mapped_type& at(const K& key) const; ``` ### Modifiers @@ -893,6 +914,7 @@ void clear(); iterator erase(const_iterator iter); iterator erase(const_iterator first, const_iterator last); size_type erase(const key_type& key); +template < typename K > size_type erase(const K& key); void swap(flat_multimap& other) ``` @@ -901,6 +923,7 @@ void swap(flat_multimap& other) ```cpp size_type count(const key_type& key) const; +template < typename K > size_type count(const K& key) const; iterator find(const key_type& key); const_iterator find(const key_type& key) const; @@ -911,6 +934,9 @@ template < typename K > const_iterator find(const K& key) const; std::pair equal_range(const key_type& key); std::pair equal_range(const key_type& key) const; +template < typename K > std::pair equal_range(const K& key); +template < typename K > std::pair equal_range(const K& key) const; + iterator lower_bound(const key_type& key); const_iterator lower_bound(const key_type& key) const;