mirror of
https://github.com/BlackMATov/flat.hpp.git
synced 2025-12-13 09:45:38 +07:00
@@ -17,32 +17,55 @@
|
||||
|
||||
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<Key>
|
||||
, typename Container = std::vector<std::pair<Key, Value>> >
|
||||
class flat_map final {
|
||||
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 Container::const_reference r) const {
|
||||
return Compare::operator()(l, r.first);
|
||||
}
|
||||
|
||||
bool operator()(typename Container::const_reference l, const Key& r) const {
|
||||
return Compare::operator()(l.first, r);
|
||||
}
|
||||
|
||||
bool operator()(typename Container::const_reference l, typename Container::const_reference r) const {
|
||||
return Compare::operator()(l.first, r.first);
|
||||
}
|
||||
};
|
||||
class flat_map
|
||||
: private detail::flat_map_compare<
|
||||
typename Container::value_type,
|
||||
Compare>
|
||||
{
|
||||
using base_type = detail::flat_map_compare<
|
||||
typename Container::value_type,
|
||||
Compare>;
|
||||
public:
|
||||
using key_type = Key;
|
||||
using mapped_type = Value;
|
||||
@@ -64,23 +87,23 @@ namespace flat_hpp
|
||||
using reverse_iterator = typename Container::reverse_iterator;
|
||||
using const_reverse_iterator = typename Container::const_reverse_iterator;
|
||||
|
||||
class value_compare {
|
||||
class value_compare : private key_compare {
|
||||
public:
|
||||
bool operator()(const value_type& l, const value_type& r) const {
|
||||
return compare_(l.first, r.first);
|
||||
return key_compare::operator()(l.first, r.first);
|
||||
}
|
||||
protected:
|
||||
friend class flat_map;
|
||||
explicit value_compare(key_compare compare)
|
||||
: compare_(std::move(compare)) {}
|
||||
private:
|
||||
key_compare compare_;
|
||||
: key_compare(std::move(compare)) {}
|
||||
};
|
||||
public:
|
||||
flat_map() {}
|
||||
flat_map()
|
||||
noexcept(std::is_nothrow_default_constructible<base_type>::value
|
||||
&& std::is_nothrow_default_constructible<container_type>::value) {}
|
||||
|
||||
explicit flat_map(const Compare& c)
|
||||
: compare_(c) {}
|
||||
: base_type(c) {}
|
||||
|
||||
template < typename Allocator >
|
||||
explicit flat_map(const Allocator& a)
|
||||
@@ -88,8 +111,8 @@ namespace flat_hpp
|
||||
|
||||
template < typename Allocator >
|
||||
flat_map(const Compare& c, const Allocator& a)
|
||||
: data_(a)
|
||||
, compare_(c) {}
|
||||
: base_type(c)
|
||||
, data_(a) {}
|
||||
|
||||
template < typename InputIter >
|
||||
flat_map(InputIter first, InputIter last) {
|
||||
@@ -98,7 +121,7 @@ namespace flat_hpp
|
||||
|
||||
template < typename InputIter >
|
||||
flat_map(InputIter first, InputIter last, const Compare& c)
|
||||
: compare_(c) {
|
||||
: base_type(c) {
|
||||
insert(first, last);
|
||||
}
|
||||
|
||||
@@ -110,8 +133,8 @@ namespace flat_hpp
|
||||
|
||||
template < typename InputIter , typename Allocator >
|
||||
flat_map(InputIter first, InputIter last, const Compare& c, const Allocator& a)
|
||||
: data_(a)
|
||||
, compare_(c) {
|
||||
: base_type(c)
|
||||
, data_(a) {
|
||||
insert(first, last);
|
||||
}
|
||||
|
||||
@@ -120,7 +143,7 @@ namespace flat_hpp
|
||||
}
|
||||
|
||||
flat_map(std::initializer_list<value_type> ilist, const Compare& c)
|
||||
: compare_(c) {
|
||||
: base_type(c) {
|
||||
insert(ilist);
|
||||
}
|
||||
|
||||
@@ -132,20 +155,20 @@ namespace flat_hpp
|
||||
|
||||
template < typename Allocator >
|
||||
flat_map(std::initializer_list<value_type> ilist, const Compare& c, const Allocator& a)
|
||||
: data_(a)
|
||||
, compare_(c) {
|
||||
: base_type(c)
|
||||
, data_(a) {
|
||||
insert(ilist);
|
||||
}
|
||||
|
||||
template < typename Allocator >
|
||||
flat_map(flat_map&& other, const Allocator& a)
|
||||
: data_(std::move(other.data_), a)
|
||||
, compare_(std::move(other.compare_)) {}
|
||||
: base_type(static_cast<base_type&&>(other))
|
||||
, data_(std::move(other.data_), a) {}
|
||||
|
||||
template < typename Allocator >
|
||||
flat_map(const flat_map& other, const Allocator& a)
|
||||
: data_(other.data_, a)
|
||||
, compare_(other.compare_) {}
|
||||
: base_type(static_cast<const base_type&>(other))
|
||||
, data_(other.data_, a) {}
|
||||
|
||||
flat_map(flat_map&& other) = default;
|
||||
flat_map(const flat_map& other) = default;
|
||||
@@ -230,28 +253,28 @@ namespace flat_hpp
|
||||
|
||||
std::pair<iterator, bool> insert(value_type&& value) {
|
||||
const iterator iter = lower_bound(value.first);
|
||||
return iter == end() || compare_(value, *iter)
|
||||
return iter == end() || this->operator()(value, *iter)
|
||||
? std::make_pair(data_.insert(iter, std::move(value)), true)
|
||||
: std::make_pair(iter, false);
|
||||
}
|
||||
|
||||
std::pair<iterator, bool> insert(const value_type& value) {
|
||||
const iterator iter = lower_bound(value.first);
|
||||
return iter == end() || compare_(value, *iter)
|
||||
return iter == end() || this->operator()(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))
|
||||
return (hint == begin() || this->operator()(*(hint - 1), value))
|
||||
&& (hint == end() || this->operator()(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))
|
||||
return (hint == begin() || this->operator()(*(hint - 1), value))
|
||||
&& (hint == end() || this->operator()(value, *hint))
|
||||
? data_.insert(hint, value)
|
||||
: insert(value).first;
|
||||
}
|
||||
@@ -298,8 +321,10 @@ namespace flat_hpp
|
||||
|
||||
void swap(flat_map& other) {
|
||||
using std::swap;
|
||||
swap(
|
||||
static_cast<base_type&>(*this),
|
||||
static_cast<base_type&>(other));
|
||||
swap(data_, other.data_);
|
||||
swap(compare_, other.compare_);
|
||||
}
|
||||
|
||||
size_type count(const key_type& key) const {
|
||||
@@ -309,52 +334,57 @@ namespace flat_hpp
|
||||
|
||||
iterator find(const key_type& key) {
|
||||
const iterator iter = lower_bound(key);
|
||||
return iter != end() && !compare_(key, iter->first)
|
||||
return iter != end() && !this->operator()(key, iter->first)
|
||||
? iter
|
||||
: end();
|
||||
}
|
||||
|
||||
const_iterator find(const key_type& key) const {
|
||||
const const_iterator iter = lower_bound(key);
|
||||
return iter != end() && !compare_(key, iter->first)
|
||||
return iter != end() && !this->operator()(key, iter->first)
|
||||
? iter
|
||||
: end();
|
||||
}
|
||||
|
||||
std::pair<iterator, iterator> equal_range(const key_type& key) {
|
||||
return std::equal_range(begin(), end(), key, compare_);
|
||||
const base_type& comp = *this;
|
||||
return std::equal_range(begin(), end(), key, comp);
|
||||
}
|
||||
|
||||
std::pair<const_iterator, const_iterator> equal_range(const key_type& key) const {
|
||||
return std::equal_range(begin(), end(), key, compare_);
|
||||
const base_type& comp = *this;
|
||||
return std::equal_range(begin(), end(), key, comp);
|
||||
}
|
||||
|
||||
iterator lower_bound(const key_type& key) {
|
||||
return std::lower_bound(begin(), end(), key, compare_);
|
||||
const base_type& comp = *this;
|
||||
return std::lower_bound(begin(), end(), key, comp);
|
||||
}
|
||||
|
||||
const_iterator lower_bound(const key_type& key) const {
|
||||
return std::lower_bound(begin(), end(), key, compare_);
|
||||
const base_type& comp = *this;
|
||||
return std::lower_bound(begin(), end(), key, comp);
|
||||
}
|
||||
|
||||
iterator upper_bound(const key_type& key) {
|
||||
return std::upper_bound(begin(), end(), key, compare_);
|
||||
const base_type& comp = *this;
|
||||
return std::upper_bound(begin(), end(), key, comp);
|
||||
}
|
||||
|
||||
const_iterator upper_bound(const key_type& key) const {
|
||||
return std::upper_bound(begin(), end(), key, compare_);
|
||||
const base_type& comp = *this;
|
||||
return std::upper_bound(begin(), end(), key, comp);
|
||||
}
|
||||
|
||||
key_compare key_comp() const {
|
||||
return compare_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
value_compare value_comp() const {
|
||||
return value_compare(compare_);
|
||||
return value_compare(key_comp());
|
||||
}
|
||||
private:
|
||||
container_type data_;
|
||||
uber_comparer_type compare_;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -17,32 +17,55 @@
|
||||
|
||||
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<Key>
|
||||
, typename Container = std::vector<std::pair<Key, Value>> >
|
||||
class flat_multimap final {
|
||||
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 Container::const_reference r) const {
|
||||
return Compare::operator()(l, r.first);
|
||||
}
|
||||
|
||||
bool operator()(typename Container::const_reference l, const Key& r) const {
|
||||
return Compare::operator()(l.first, r);
|
||||
}
|
||||
|
||||
bool operator()(typename Container::const_reference l, typename Container::const_reference r) const {
|
||||
return Compare::operator()(l.first, r.first);
|
||||
}
|
||||
};
|
||||
class flat_multimap
|
||||
: private detail::flat_multimap_compare<
|
||||
typename Container::value_type,
|
||||
Compare>
|
||||
{
|
||||
using base_type = detail::flat_multimap_compare<
|
||||
typename Container::value_type,
|
||||
Compare>;
|
||||
public:
|
||||
using key_type = Key;
|
||||
using mapped_type = Value;
|
||||
@@ -64,23 +87,23 @@ namespace flat_hpp
|
||||
using reverse_iterator = typename Container::reverse_iterator;
|
||||
using const_reverse_iterator = typename Container::const_reverse_iterator;
|
||||
|
||||
class value_compare {
|
||||
class value_compare : private key_compare {
|
||||
public:
|
||||
bool operator()(const value_type& l, const value_type& r) const {
|
||||
return compare_(l.first, r.first);
|
||||
return key_compare::operator()(l.first, r.first);
|
||||
}
|
||||
protected:
|
||||
friend class flat_multimap;
|
||||
explicit value_compare(key_compare compare)
|
||||
: compare_(std::move(compare)) {}
|
||||
private:
|
||||
key_compare compare_;
|
||||
: key_compare(std::move(compare)) {}
|
||||
};
|
||||
public:
|
||||
flat_multimap() {}
|
||||
flat_multimap()
|
||||
noexcept(std::is_nothrow_default_constructible<base_type>::value
|
||||
&& std::is_nothrow_default_constructible<container_type>::value) {}
|
||||
|
||||
explicit flat_multimap(const Compare& c)
|
||||
: compare_(c) {}
|
||||
: base_type(c) {}
|
||||
|
||||
template < typename Allocator >
|
||||
explicit flat_multimap(const Allocator& a)
|
||||
@@ -88,8 +111,8 @@ namespace flat_hpp
|
||||
|
||||
template < typename Allocator >
|
||||
flat_multimap(const Compare& c, const Allocator& a)
|
||||
: data_(a)
|
||||
, compare_(c) {}
|
||||
: base_type(c)
|
||||
, data_(a) {}
|
||||
|
||||
template < typename InputIter >
|
||||
flat_multimap(InputIter first, InputIter last) {
|
||||
@@ -98,7 +121,7 @@ namespace flat_hpp
|
||||
|
||||
template < typename InputIter >
|
||||
flat_multimap(InputIter first, InputIter last, const Compare& c)
|
||||
: compare_(c) {
|
||||
: base_type(c) {
|
||||
insert(first, last);
|
||||
}
|
||||
|
||||
@@ -110,8 +133,8 @@ namespace flat_hpp
|
||||
|
||||
template < typename InputIter , typename Allocator >
|
||||
flat_multimap(InputIter first, InputIter last, const Compare& c, const Allocator& a)
|
||||
: data_(a)
|
||||
, compare_(c) {
|
||||
: base_type(c)
|
||||
, data_(a) {
|
||||
insert(first, last);
|
||||
}
|
||||
|
||||
@@ -120,7 +143,7 @@ namespace flat_hpp
|
||||
}
|
||||
|
||||
flat_multimap(std::initializer_list<value_type> ilist, const Compare& c)
|
||||
: compare_(c) {
|
||||
: base_type(c) {
|
||||
insert(ilist);
|
||||
}
|
||||
|
||||
@@ -132,20 +155,20 @@ namespace flat_hpp
|
||||
|
||||
template < typename Allocator >
|
||||
flat_multimap(std::initializer_list<value_type> ilist, const Compare& c, const Allocator& a)
|
||||
: data_(a)
|
||||
, compare_(c) {
|
||||
: base_type(c)
|
||||
, data_(a) {
|
||||
insert(ilist);
|
||||
}
|
||||
|
||||
template < typename Allocator >
|
||||
flat_multimap(flat_multimap&& other, const Allocator& a)
|
||||
: data_(std::move(other.data_), a)
|
||||
, compare_(std::move(other.compare_)) {}
|
||||
: base_type(static_cast<base_type&&>(other))
|
||||
, data_(std::move(other.data_), a) {}
|
||||
|
||||
template < typename Allocator >
|
||||
flat_multimap(const flat_multimap& other, const Allocator& a)
|
||||
: data_(other.data_, a)
|
||||
, compare_(other.compare_) {}
|
||||
: base_type(static_cast<const base_type&>(other))
|
||||
, data_(other.data_, a) {}
|
||||
|
||||
flat_multimap(flat_multimap&& other) = default;
|
||||
flat_multimap(const flat_multimap& other) = default;
|
||||
@@ -239,15 +262,15 @@ namespace flat_hpp
|
||||
}
|
||||
|
||||
iterator insert(const_iterator hint, value_type&& value) {
|
||||
return (hint == begin() || !compare_(value, *(hint - 1)))
|
||||
&& (hint == end() || !compare_(*hint, value))
|
||||
return (hint == begin() || !this->operator()(value, *(hint - 1)))
|
||||
&& (hint == end() || !this->operator()(*hint, value))
|
||||
? data_.insert(hint, std::move(value))
|
||||
: insert(std::move(value));
|
||||
}
|
||||
|
||||
iterator insert(const_iterator hint, const value_type& value) {
|
||||
return (hint == begin() || !compare_(value, *(hint - 1)))
|
||||
&& (hint == end() || !compare_(*hint, value))
|
||||
return (hint == begin() || !this->operator()(value, *(hint - 1)))
|
||||
&& (hint == end() || !this->operator()(*hint, value))
|
||||
? data_.insert(hint, value)
|
||||
: insert(value);
|
||||
}
|
||||
@@ -294,8 +317,10 @@ namespace flat_hpp
|
||||
|
||||
void swap(flat_multimap& other) {
|
||||
using std::swap;
|
||||
swap(
|
||||
static_cast<base_type&>(*this),
|
||||
static_cast<base_type&>(other));
|
||||
swap(data_, other.data_);
|
||||
swap(compare_, other.compare_);
|
||||
}
|
||||
|
||||
size_type count(const key_type& key) const {
|
||||
@@ -305,52 +330,57 @@ namespace flat_hpp
|
||||
|
||||
iterator find(const key_type& key) {
|
||||
const iterator iter = lower_bound(key);
|
||||
return iter != end() && !compare_(key, iter->first)
|
||||
return iter != end() && !this->operator()(key, iter->first)
|
||||
? iter
|
||||
: end();
|
||||
}
|
||||
|
||||
const_iterator find(const key_type& key) const {
|
||||
const const_iterator iter = lower_bound(key);
|
||||
return iter != end() && !compare_(key, iter->first)
|
||||
return iter != end() && !this->operator()(key, iter->first)
|
||||
? iter
|
||||
: end();
|
||||
}
|
||||
|
||||
std::pair<iterator, iterator> equal_range(const key_type& key) {
|
||||
return std::equal_range(begin(), end(), key, compare_);
|
||||
const base_type& comp = *this;
|
||||
return std::equal_range(begin(), end(), key, comp);
|
||||
}
|
||||
|
||||
std::pair<const_iterator, const_iterator> equal_range(const key_type& key) const {
|
||||
return std::equal_range(begin(), end(), key, compare_);
|
||||
const base_type& comp = *this;
|
||||
return std::equal_range(begin(), end(), key, comp);
|
||||
}
|
||||
|
||||
iterator lower_bound(const key_type& key) {
|
||||
return std::lower_bound(begin(), end(), key, compare_);
|
||||
const base_type& comp = *this;
|
||||
return std::lower_bound(begin(), end(), key, comp);
|
||||
}
|
||||
|
||||
const_iterator lower_bound(const key_type& key) const {
|
||||
return std::lower_bound(begin(), end(), key, compare_);
|
||||
const base_type& comp = *this;
|
||||
return std::lower_bound(begin(), end(), key, comp);
|
||||
}
|
||||
|
||||
iterator upper_bound(const key_type& key) {
|
||||
return std::upper_bound(begin(), end(), key, compare_);
|
||||
const base_type& comp = *this;
|
||||
return std::upper_bound(begin(), end(), key, comp);
|
||||
}
|
||||
|
||||
const_iterator upper_bound(const key_type& key) const {
|
||||
return std::upper_bound(begin(), end(), key, compare_);
|
||||
const base_type& comp = *this;
|
||||
return std::upper_bound(begin(), end(), key, comp);
|
||||
}
|
||||
|
||||
key_compare key_comp() const {
|
||||
return compare_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
value_compare value_comp() const {
|
||||
return value_compare(compare_);
|
||||
return value_compare(key_comp());
|
||||
}
|
||||
private:
|
||||
container_type data_;
|
||||
uber_comparer_type compare_;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,8 @@ namespace flat_hpp
|
||||
template < typename Key
|
||||
, typename Compare = std::less<Key>
|
||||
, typename Container = std::vector<Key> >
|
||||
class flat_multiset final {
|
||||
class flat_multiset : private Compare {
|
||||
using base_type = Compare;
|
||||
public:
|
||||
using key_type = Key;
|
||||
using value_type = Key;
|
||||
@@ -42,10 +43,12 @@ namespace flat_hpp
|
||||
using reverse_iterator = typename Container::const_reverse_iterator;
|
||||
using const_reverse_iterator = typename Container::const_reverse_iterator;
|
||||
public:
|
||||
flat_multiset() {}
|
||||
flat_multiset()
|
||||
noexcept(std::is_nothrow_default_constructible<base_type>::value
|
||||
&& std::is_nothrow_default_constructible<container_type>::value) {}
|
||||
|
||||
explicit flat_multiset(const Compare& c)
|
||||
: compare_(c) {}
|
||||
: base_type(c) {}
|
||||
|
||||
template < typename Allocator >
|
||||
explicit flat_multiset(const Allocator& a)
|
||||
@@ -53,8 +56,8 @@ namespace flat_hpp
|
||||
|
||||
template < typename Allocator >
|
||||
flat_multiset(const Compare& c, const Allocator& a)
|
||||
: data_(a)
|
||||
, compare_(c) {}
|
||||
: base_type(c)
|
||||
, data_(a) {}
|
||||
|
||||
template < typename InputIter >
|
||||
flat_multiset(InputIter first, InputIter last) {
|
||||
@@ -63,7 +66,7 @@ namespace flat_hpp
|
||||
|
||||
template < typename InputIter >
|
||||
flat_multiset(InputIter first, InputIter last, const Compare& c)
|
||||
: compare_(c) {
|
||||
: base_type(c) {
|
||||
insert(first, last);
|
||||
}
|
||||
|
||||
@@ -75,8 +78,8 @@ namespace flat_hpp
|
||||
|
||||
template < typename InputIter, typename Allocator >
|
||||
flat_multiset(InputIter first, InputIter last, const Compare& c, const Allocator& a)
|
||||
: data_(a)
|
||||
, compare_(c) {
|
||||
: base_type(c)
|
||||
, data_(a) {
|
||||
insert(first, last);
|
||||
}
|
||||
|
||||
@@ -85,7 +88,7 @@ namespace flat_hpp
|
||||
}
|
||||
|
||||
flat_multiset(std::initializer_list<value_type> ilist, const Compare& c)
|
||||
: compare_(c) {
|
||||
: base_type(c) {
|
||||
insert(ilist);
|
||||
}
|
||||
|
||||
@@ -97,20 +100,20 @@ namespace flat_hpp
|
||||
|
||||
template < typename Allocator >
|
||||
flat_multiset(std::initializer_list<value_type> ilist, const Compare& c, const Allocator& a)
|
||||
: data_(a)
|
||||
, compare_(c) {
|
||||
: base_type(c)
|
||||
, data_(a) {
|
||||
insert(ilist);
|
||||
}
|
||||
|
||||
template < typename Allocator >
|
||||
flat_multiset(flat_multiset&& other, const Allocator& a)
|
||||
: data_(std::move(other.data_), a)
|
||||
, compare_(std::move(other.compare_)) {}
|
||||
: base_type(static_cast<base_type&&>(other))
|
||||
, data_(std::move(other.data_), a) {}
|
||||
|
||||
template < typename Allocator >
|
||||
flat_multiset(const flat_multiset& other, const Allocator& a)
|
||||
: data_(other.data_, a)
|
||||
, compare_(other.compare_) {}
|
||||
: base_type(static_cast<const base_type&>(other))
|
||||
, data_(other.data_, a) {}
|
||||
|
||||
flat_multiset(flat_multiset&& other) = default;
|
||||
flat_multiset(const flat_multiset& other) = default;
|
||||
@@ -174,15 +177,15 @@ namespace flat_hpp
|
||||
}
|
||||
|
||||
iterator insert(const_iterator hint, value_type&& value) {
|
||||
return (hint == begin() || !compare_(value, *(hint - 1)))
|
||||
&& (hint == end() || !compare_(*hint, value))
|
||||
return (hint == begin() || !this->operator()(value, *(hint - 1)))
|
||||
&& (hint == end() || !this->operator()(*hint, value))
|
||||
? data_.insert(hint, std::move(value))
|
||||
: insert(std::move(value));
|
||||
}
|
||||
|
||||
iterator insert(const_iterator hint, const value_type& value) {
|
||||
return (hint == begin() || !compare_(value, *(hint - 1)))
|
||||
&& (hint == end() || !compare_(*hint, value))
|
||||
return (hint == begin() || !this->operator()(value, *(hint - 1)))
|
||||
&& (hint == end() || !this->operator()(*hint, value))
|
||||
? data_.insert(hint, value)
|
||||
: insert(value);
|
||||
}
|
||||
@@ -229,8 +232,10 @@ namespace flat_hpp
|
||||
|
||||
void swap(flat_multiset& other) {
|
||||
using std::swap;
|
||||
swap(
|
||||
static_cast<base_type&>(*this),
|
||||
static_cast<base_type&>(other));
|
||||
swap(data_, other.data_);
|
||||
swap(compare_, other.compare_);
|
||||
}
|
||||
|
||||
size_type count(const key_type& key) const {
|
||||
@@ -240,52 +245,51 @@ namespace flat_hpp
|
||||
|
||||
iterator find(const key_type& key) {
|
||||
const iterator iter = lower_bound(key);
|
||||
return iter != end() && !compare_(key, *iter)
|
||||
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() && !compare_(key, *iter)
|
||||
return iter != end() && !this->operator()(key, *iter)
|
||||
? iter
|
||||
: end();
|
||||
}
|
||||
|
||||
std::pair<iterator, iterator> equal_range(const key_type& key) {
|
||||
return std::equal_range(begin(), end(), key, compare_);
|
||||
return std::equal_range(begin(), end(), key, key_comp());
|
||||
}
|
||||
|
||||
std::pair<const_iterator, const_iterator> equal_range(const key_type& key) const {
|
||||
return std::equal_range(begin(), end(), key, compare_);
|
||||
return std::equal_range(begin(), end(), key, key_comp());
|
||||
}
|
||||
|
||||
iterator lower_bound(const key_type& key) {
|
||||
return std::lower_bound(begin(), end(), key, compare_);
|
||||
return std::lower_bound(begin(), end(), key, key_comp());
|
||||
}
|
||||
|
||||
const_iterator lower_bound(const key_type& key) const {
|
||||
return std::lower_bound(begin(), end(), key, compare_);
|
||||
return std::lower_bound(begin(), end(), key, key_comp());
|
||||
}
|
||||
|
||||
iterator upper_bound(const key_type& key) {
|
||||
return std::upper_bound(begin(), end(), key, compare_);
|
||||
return std::upper_bound(begin(), end(), key, key_comp());
|
||||
}
|
||||
|
||||
const_iterator upper_bound(const key_type& key) const {
|
||||
return std::upper_bound(begin(), end(), key, compare_);
|
||||
return std::upper_bound(begin(), end(), key, key_comp());
|
||||
}
|
||||
|
||||
key_compare key_comp() const {
|
||||
return compare_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
value_compare value_comp() const {
|
||||
return value_compare(compare_);
|
||||
return value_compare(key_comp());
|
||||
}
|
||||
private:
|
||||
container_type data_;
|
||||
Compare compare_;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,8 @@ namespace flat_hpp
|
||||
template < typename Key
|
||||
, typename Compare = std::less<Key>
|
||||
, typename Container = std::vector<Key> >
|
||||
class flat_set final {
|
||||
class flat_set : private Compare {
|
||||
using base_type = Compare;
|
||||
public:
|
||||
using key_type = Key;
|
||||
using value_type = Key;
|
||||
@@ -42,10 +43,12 @@ namespace flat_hpp
|
||||
using reverse_iterator = typename Container::const_reverse_iterator;
|
||||
using const_reverse_iterator = typename Container::const_reverse_iterator;
|
||||
public:
|
||||
flat_set() {}
|
||||
flat_set()
|
||||
noexcept(std::is_nothrow_default_constructible<base_type>::value
|
||||
&& std::is_nothrow_default_constructible<container_type>::value) {}
|
||||
|
||||
explicit flat_set(const Compare& c)
|
||||
: compare_(c) {}
|
||||
: base_type(c) {}
|
||||
|
||||
template < typename Allocator >
|
||||
explicit flat_set(const Allocator& a)
|
||||
@@ -53,8 +56,8 @@ namespace flat_hpp
|
||||
|
||||
template < typename Allocator >
|
||||
flat_set(const Compare& c, const Allocator& a)
|
||||
: data_(a)
|
||||
, compare_(c) {}
|
||||
: base_type(c)
|
||||
, data_(a) {}
|
||||
|
||||
template < typename InputIter >
|
||||
flat_set(InputIter first, InputIter last) {
|
||||
@@ -63,7 +66,7 @@ namespace flat_hpp
|
||||
|
||||
template < typename InputIter >
|
||||
flat_set(InputIter first, InputIter last, const Compare& c)
|
||||
: compare_(c) {
|
||||
: base_type(c) {
|
||||
insert(first, last);
|
||||
}
|
||||
|
||||
@@ -75,8 +78,8 @@ namespace flat_hpp
|
||||
|
||||
template < typename InputIter, typename Allocator >
|
||||
flat_set(InputIter first, InputIter last, const Compare& c, const Allocator& a)
|
||||
: data_(a)
|
||||
, compare_(c) {
|
||||
: base_type(c)
|
||||
, data_(a) {
|
||||
insert(first, last);
|
||||
}
|
||||
|
||||
@@ -85,7 +88,7 @@ namespace flat_hpp
|
||||
}
|
||||
|
||||
flat_set(std::initializer_list<value_type> ilist, const Compare& c)
|
||||
: compare_(c) {
|
||||
: base_type(c) {
|
||||
insert(ilist);
|
||||
}
|
||||
|
||||
@@ -97,20 +100,20 @@ namespace flat_hpp
|
||||
|
||||
template < typename Allocator >
|
||||
flat_set(std::initializer_list<value_type> ilist, const Compare& c, const Allocator& a)
|
||||
: data_(a)
|
||||
, compare_(c) {
|
||||
: base_type(c)
|
||||
, data_(a) {
|
||||
insert(ilist);
|
||||
}
|
||||
|
||||
template < typename Allocator >
|
||||
flat_set(flat_set&& other, const Allocator& a)
|
||||
: data_(std::move(other.data_), a)
|
||||
, compare_(std::move(other.compare_)) {}
|
||||
: base_type(static_cast<base_type&&>(other))
|
||||
, data_(std::move(other.data_), a) {}
|
||||
|
||||
template < typename Allocator >
|
||||
flat_set(const flat_set& other, const Allocator& a)
|
||||
: data_(other.data_, a)
|
||||
, compare_(other.compare_) {}
|
||||
: base_type(static_cast<const base_type&>(other))
|
||||
, data_(other.data_, a) {}
|
||||
|
||||
flat_set(flat_set&& other) = default;
|
||||
flat_set(const flat_set& other) = default;
|
||||
@@ -165,28 +168,28 @@ namespace flat_hpp
|
||||
|
||||
std::pair<iterator, bool> insert(value_type&& value) {
|
||||
const iterator iter = lower_bound(value);
|
||||
return iter == end() || compare_(value, *iter)
|
||||
return iter == end() || this->operator()(value, *iter)
|
||||
? std::make_pair(data_.insert(iter, std::move(value)), true)
|
||||
: std::make_pair(iter, false);
|
||||
}
|
||||
|
||||
std::pair<iterator, bool> insert(const value_type& value) {
|
||||
const iterator iter = lower_bound(value);
|
||||
return iter == end() || compare_(value, *iter)
|
||||
return iter == end() || this->operator()(value, *iter)
|
||||
? std::make_pair(data_.insert(iter, value), true)
|
||||
: std::make_pair(iter, false);
|
||||
}
|
||||
|
||||
iterator insert(const_iterator hint, value_type&& value) {
|
||||
return (hint == begin() || compare_(*(hint - 1), value))
|
||||
&& (hint == end() || compare_(value, *hint))
|
||||
return (hint == begin() || this->operator()(*(hint - 1), value))
|
||||
&& (hint == end() || this->operator()(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))
|
||||
return (hint == begin() || this->operator()(*(hint - 1), value))
|
||||
&& (hint == end() || this->operator()(value, *hint))
|
||||
? data_.insert(hint, value)
|
||||
: insert(value).first;
|
||||
}
|
||||
@@ -233,8 +236,10 @@ namespace flat_hpp
|
||||
|
||||
void swap(flat_set& other) {
|
||||
using std::swap;
|
||||
swap(
|
||||
static_cast<base_type&>(*this),
|
||||
static_cast<base_type&>(other));
|
||||
swap(data_, other.data_);
|
||||
swap(compare_, other.compare_);
|
||||
}
|
||||
|
||||
size_type count(const key_type& key) const {
|
||||
@@ -244,52 +249,51 @@ namespace flat_hpp
|
||||
|
||||
iterator find(const key_type& key) {
|
||||
const iterator iter = lower_bound(key);
|
||||
return iter != end() && !compare_(key, *iter)
|
||||
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() && !compare_(key, *iter)
|
||||
return iter != end() && !this->operator()(key, *iter)
|
||||
? iter
|
||||
: end();
|
||||
}
|
||||
|
||||
std::pair<iterator, iterator> equal_range(const key_type& key) {
|
||||
return std::equal_range(begin(), end(), key, compare_);
|
||||
return std::equal_range(begin(), end(), key, key_comp());
|
||||
}
|
||||
|
||||
std::pair<const_iterator, const_iterator> equal_range(const key_type& key) const {
|
||||
return std::equal_range(begin(), end(), key, compare_);
|
||||
return std::equal_range(begin(), end(), key, key_comp());
|
||||
}
|
||||
|
||||
iterator lower_bound(const key_type& key) {
|
||||
return std::lower_bound(begin(), end(), key, compare_);
|
||||
return std::lower_bound(begin(), end(), key, key_comp());
|
||||
}
|
||||
|
||||
const_iterator lower_bound(const key_type& key) const {
|
||||
return std::lower_bound(begin(), end(), key, compare_);
|
||||
return std::lower_bound(begin(), end(), key, key_comp());
|
||||
}
|
||||
|
||||
iterator upper_bound(const key_type& key) {
|
||||
return std::upper_bound(begin(), end(), key, compare_);
|
||||
return std::upper_bound(begin(), end(), key, key_comp());
|
||||
}
|
||||
|
||||
const_iterator upper_bound(const key_type& key) const {
|
||||
return std::upper_bound(begin(), end(), key, compare_);
|
||||
return std::upper_bound(begin(), end(), key, key_comp());
|
||||
}
|
||||
|
||||
key_compare key_comp() const {
|
||||
return compare_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
value_compare value_comp() const {
|
||||
return value_compare(compare_);
|
||||
return value_compare(key_comp());
|
||||
}
|
||||
private:
|
||||
container_type data_;
|
||||
Compare compare_;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -70,6 +70,17 @@ namespace
|
||||
return !(l == r);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
class dummy_less {
|
||||
public:
|
||||
dummy_less() = default;
|
||||
dummy_less(int i) noexcept : i(i) {}
|
||||
bool operator()(const T& l, const T& r) const {
|
||||
return l < r;
|
||||
}
|
||||
int i = 0;
|
||||
};
|
||||
|
||||
template < typename T >
|
||||
constexpr std::add_const_t<T>& my_as_const(T& t) noexcept {
|
||||
return t;
|
||||
@@ -77,6 +88,28 @@ namespace
|
||||
}
|
||||
|
||||
TEST_CASE("flat_map") {
|
||||
SECTION("sizeof") {
|
||||
REQUIRE(sizeof(flat_map<int, unsigned>) == sizeof(std::vector<std::pair<int, unsigned>>));
|
||||
|
||||
struct vc : flat_map<int, unsigned>::value_compare {
|
||||
int i;
|
||||
};
|
||||
REQUIRE(sizeof(vc) == sizeof(int));
|
||||
}
|
||||
SECTION("noexcept") {
|
||||
using alloc_t = dummy_allocator<std::pair<int,unsigned>>;
|
||||
using map_t = flat_map<int, unsigned, dummy_less<int>, std::vector<std::pair<int,unsigned>, alloc_t>>;
|
||||
|
||||
static_assert(
|
||||
std::is_nothrow_default_constructible<map_t>::value,
|
||||
"unit test static error");
|
||||
static_assert(
|
||||
std::is_nothrow_move_constructible<map_t>::value,
|
||||
"unit test static error");
|
||||
static_assert(
|
||||
std::is_nothrow_move_assignable<map_t>::value,
|
||||
"unit test static error");
|
||||
}
|
||||
SECTION("types") {
|
||||
using map_t = flat_map<int, unsigned>;
|
||||
|
||||
@@ -416,6 +449,16 @@ TEST_CASE("flat_map") {
|
||||
REQUIRE(my_as_const(s0).key_comp().i == 42);
|
||||
REQUIRE(my_as_const(s0).value_comp()({2,50},{4,20}));
|
||||
}
|
||||
SECTION("custom_less") {
|
||||
using map_t = flat_map<int, unsigned, dummy_less<int>>;
|
||||
auto s0 = map_t(dummy_less<int>(42));
|
||||
auto s1 = map_t(dummy_less<int>(21));
|
||||
REQUIRE(s0.key_comp().i == 42);
|
||||
REQUIRE(s1.key_comp().i == 21);
|
||||
s0.swap(s1);
|
||||
REQUIRE(s0.key_comp().i == 21);
|
||||
REQUIRE(s1.key_comp().i == 42);
|
||||
}
|
||||
SECTION("operators") {
|
||||
using map_t = flat_map<int, unsigned>;
|
||||
|
||||
|
||||
@@ -70,6 +70,17 @@ namespace
|
||||
return !(l == r);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
class dummy_less {
|
||||
public:
|
||||
dummy_less() = default;
|
||||
dummy_less(int i) noexcept : i(i) {}
|
||||
bool operator()(const T& l, const T& r) const {
|
||||
return l < r;
|
||||
}
|
||||
int i = 0;
|
||||
};
|
||||
|
||||
template < typename T >
|
||||
constexpr std::add_const_t<T>& my_as_const(T& t) noexcept {
|
||||
return t;
|
||||
@@ -77,6 +88,28 @@ namespace
|
||||
}
|
||||
|
||||
TEST_CASE("flat_multimap") {
|
||||
SECTION("sizeof") {
|
||||
REQUIRE(sizeof(flat_multimap<int, unsigned>) == sizeof(std::vector<std::pair<int, unsigned>>));
|
||||
|
||||
struct vc : flat_multimap<int, unsigned>::value_compare {
|
||||
int i;
|
||||
};
|
||||
REQUIRE(sizeof(vc) == sizeof(int));
|
||||
}
|
||||
SECTION("noexcept") {
|
||||
using alloc_t = dummy_allocator<std::pair<int,unsigned>>;
|
||||
using map_t = flat_multimap<int, unsigned, dummy_less<int>, std::vector<std::pair<int,unsigned>, alloc_t>>;
|
||||
|
||||
static_assert(
|
||||
std::is_nothrow_default_constructible<map_t>::value,
|
||||
"unit test static error");
|
||||
static_assert(
|
||||
std::is_nothrow_move_constructible<map_t>::value,
|
||||
"unit test static error");
|
||||
static_assert(
|
||||
std::is_nothrow_move_assignable<map_t>::value,
|
||||
"unit test static error");
|
||||
}
|
||||
SECTION("types") {
|
||||
using map_t = flat_multimap<int, unsigned>;
|
||||
|
||||
@@ -418,6 +451,16 @@ TEST_CASE("flat_multimap") {
|
||||
REQUIRE(my_as_const(s0).key_comp().i == 42);
|
||||
REQUIRE(my_as_const(s0).value_comp()({2,50},{4,20}));
|
||||
}
|
||||
SECTION("custom_less") {
|
||||
using map_t = flat_multimap<int, unsigned, dummy_less<int>>;
|
||||
auto s0 = map_t(dummy_less<int>(42));
|
||||
auto s1 = map_t(dummy_less<int>(21));
|
||||
REQUIRE(s0.key_comp().i == 42);
|
||||
REQUIRE(s1.key_comp().i == 21);
|
||||
s0.swap(s1);
|
||||
REQUIRE(s0.key_comp().i == 21);
|
||||
REQUIRE(s1.key_comp().i == 42);
|
||||
}
|
||||
SECTION("operators") {
|
||||
using map_t = flat_multimap<int, unsigned>;
|
||||
|
||||
|
||||
@@ -70,6 +70,17 @@ namespace
|
||||
return !(l == r);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
class dummy_less {
|
||||
public:
|
||||
dummy_less() = default;
|
||||
dummy_less(int i) noexcept : i(i) {}
|
||||
bool operator()(const T& l, const T& r) const {
|
||||
return l < r;
|
||||
}
|
||||
int i = 0;
|
||||
};
|
||||
|
||||
template < typename T >
|
||||
constexpr std::add_const_t<T>& my_as_const(T& t) noexcept {
|
||||
return t;
|
||||
@@ -77,6 +88,28 @@ namespace
|
||||
}
|
||||
|
||||
TEST_CASE("flat_multiset") {
|
||||
SECTION("sizeof") {
|
||||
REQUIRE(sizeof(flat_multiset<int>) == sizeof(std::vector<int>));
|
||||
|
||||
struct vc : flat_multiset<int>::value_compare {
|
||||
int i;
|
||||
};
|
||||
REQUIRE(sizeof(vc) == sizeof(int));
|
||||
}
|
||||
SECTION("noexcept") {
|
||||
using alloc_t = dummy_allocator<int>;
|
||||
using set_t = flat_multiset<int, dummy_less<int>, std::vector<int, alloc_t>>;
|
||||
|
||||
static_assert(
|
||||
std::is_nothrow_default_constructible<set_t>::value,
|
||||
"unit test static error");
|
||||
static_assert(
|
||||
std::is_nothrow_move_constructible<set_t>::value,
|
||||
"unit test static error");
|
||||
static_assert(
|
||||
std::is_nothrow_move_assignable<set_t>::value,
|
||||
"unit test static error");
|
||||
}
|
||||
SECTION("types") {
|
||||
using set_t = flat_multiset<int>;
|
||||
|
||||
@@ -392,6 +425,16 @@ TEST_CASE("flat_multiset") {
|
||||
REQUIRE(my_as_const(s0).key_comp().i == 42);
|
||||
REQUIRE(my_as_const(s0).value_comp().i == 42);
|
||||
}
|
||||
SECTION("custom_less") {
|
||||
using set_t = flat_multiset<int, dummy_less<int>>;
|
||||
auto s0 = set_t(dummy_less<int>(42));
|
||||
auto s1 = set_t(dummy_less<int>(21));
|
||||
REQUIRE(s0.key_comp().i == 42);
|
||||
REQUIRE(s1.key_comp().i == 21);
|
||||
s0.swap(s1);
|
||||
REQUIRE(s0.key_comp().i == 21);
|
||||
REQUIRE(s1.key_comp().i == 42);
|
||||
}
|
||||
SECTION("operators") {
|
||||
using set_t = flat_multiset<int>;
|
||||
|
||||
|
||||
@@ -70,6 +70,17 @@ namespace
|
||||
return !(l == r);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
class dummy_less {
|
||||
public:
|
||||
dummy_less() = default;
|
||||
dummy_less(int i) noexcept : i(i) {}
|
||||
bool operator()(const T& l, const T& r) const {
|
||||
return l < r;
|
||||
}
|
||||
int i = 0;
|
||||
};
|
||||
|
||||
template < typename T >
|
||||
constexpr std::add_const_t<T>& my_as_const(T& t) noexcept {
|
||||
return t;
|
||||
@@ -77,6 +88,28 @@ namespace
|
||||
}
|
||||
|
||||
TEST_CASE("flat_set") {
|
||||
SECTION("sizeof") {
|
||||
REQUIRE(sizeof(flat_set<int>) == sizeof(std::vector<int>));
|
||||
|
||||
struct vc : flat_set<int>::value_compare {
|
||||
int i;
|
||||
};
|
||||
REQUIRE(sizeof(vc) == sizeof(int));
|
||||
}
|
||||
SECTION("noexcept") {
|
||||
using alloc_t = dummy_allocator<int>;
|
||||
using set_t = flat_set<int, dummy_less<int>, std::vector<int, alloc_t>>;
|
||||
|
||||
static_assert(
|
||||
std::is_nothrow_default_constructible<set_t>::value,
|
||||
"unit test static error");
|
||||
static_assert(
|
||||
std::is_nothrow_move_constructible<set_t>::value,
|
||||
"unit test static error");
|
||||
static_assert(
|
||||
std::is_nothrow_move_assignable<set_t>::value,
|
||||
"unit test static error");
|
||||
}
|
||||
SECTION("types") {
|
||||
using set_t = flat_set<int>;
|
||||
|
||||
@@ -390,6 +423,16 @@ TEST_CASE("flat_set") {
|
||||
REQUIRE(my_as_const(s0).key_comp().i == 42);
|
||||
REQUIRE(my_as_const(s0).value_comp().i == 42);
|
||||
}
|
||||
SECTION("custom_less") {
|
||||
using set_t = flat_set<int, dummy_less<int>>;
|
||||
auto s0 = set_t(dummy_less<int>(42));
|
||||
auto s1 = set_t(dummy_less<int>(21));
|
||||
REQUIRE(s0.key_comp().i == 42);
|
||||
REQUIRE(s1.key_comp().i == 21);
|
||||
s0.swap(s1);
|
||||
REQUIRE(s0.key_comp().i == 21);
|
||||
REQUIRE(s1.key_comp().i == 42);
|
||||
}
|
||||
SECTION("operators") {
|
||||
using set_t = flat_set<int>;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user