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 8f3cc8b..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"] } } @@ -35,7 +27,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..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,18 +192,31 @@ 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; +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; +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; +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 @@ -390,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 @@ -414,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) ``` @@ -422,18 +440,31 @@ 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; +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; +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; +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 @@ -635,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); ``` @@ -643,18 +675,31 @@ 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; +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; +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; +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 @@ -842,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 @@ -866,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) ``` @@ -874,18 +923,31 @@ 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; +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; +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; +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..a6ddb38 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: @@ -299,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) @@ -362,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; @@ -384,16 +385,47 @@ 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->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(); } @@ -408,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); @@ -418,6 +468,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 +496,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..aeccbbf 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: @@ -299,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)); @@ -364,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) @@ -380,16 +381,47 @@ 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->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(); } @@ -404,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); @@ -414,6 +464,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 +492,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..6fdd395 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 @@ -279,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) @@ -295,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) @@ -309,6 +331,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()); } @@ -317,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()); } @@ -325,6 +385,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 +409,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..21e06ab 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 @@ -277,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; @@ -299,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) @@ -313,6 +335,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()); } @@ -321,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()); } @@ -329,6 +389,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 +413,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..45fbd38 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>)); @@ -404,6 +411,23 @@ TEST_CASE("flat_map") { REQUIRE(my_as_const(s0).lower_bound(7) == s0.cbegin() + 3); } } + 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 { int i; diff --git a/untests/flat_multimap_tests.cpp b/untests/flat_multimap_tests.cpp index ccaf5bd..0c9953a 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>)); @@ -406,6 +413,23 @@ TEST_CASE("flat_multimap") { REQUIRE(my_as_const(s0).lower_bound(7) == s0.cbegin() + 4); } } + 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 { int i; diff --git a/untests/flat_multiset_tests.cpp b/untests/flat_multiset_tests.cpp index 669d799..9e7833f 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)); @@ -382,6 +389,21 @@ TEST_CASE("flat_multiset") { REQUIRE(my_as_const(s0).lower_bound(7) == s0.cbegin() + 4); } } + 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 { int i; diff --git a/untests/flat_set_tests.cpp b/untests/flat_set_tests.cpp index 6029598..83dbd23 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)); @@ -380,6 +387,21 @@ TEST_CASE("flat_set") { REQUIRE(my_as_const(s0).lower_bound(7) == s0.cbegin() + 3); } } + 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 { int i;