mirror of
https://github.com/BlackMATov/flat.hpp.git
synced 2025-12-13 01:36:27 +07:00
403
README.md
403
README.md
@@ -28,12 +28,407 @@
|
||||
[flat.hpp][flat] is a header only library. All you need to do is copy the header files (`flat_set.hpp` and `flat_map.hpp`) into your project and include them:
|
||||
|
||||
```cpp
|
||||
#include "flat_set.hpp" // for flat_set<K>
|
||||
#include "flat_map.hpp" // for flat_map<K,V>
|
||||
#include "flat_set.hpp"
|
||||
#include "flat_map.hpp"
|
||||
```
|
||||
|
||||
## API
|
||||
## flat_set
|
||||
|
||||
> coming soon!
|
||||
```cpp
|
||||
template < typename Key
|
||||
, typename Compare = std::less<Key>
|
||||
, typename Allocator = std::allocator<Key>
|
||||
, typename Container = std::vector<Key, Allocator> >
|
||||
class flat_set;
|
||||
```
|
||||
|
||||
### Member types
|
||||
|
||||
| Member type | Definition |
|
||||
|--------------------------|-------------------------------------|
|
||||
| `key_type` | `Key` |
|
||||
| `value_type` | `Key` |
|
||||
| `size_type` | `Container::size_type` |
|
||||
| `difference_type` | `Container::difference_type` |
|
||||
| `key_compare` | `Compare` |
|
||||
| `value_compare` | `Compare` |
|
||||
| `allocator_type` | `Allocator` |
|
||||
| `container_type` | `Container` |
|
||||
| `reference` | `Container::reference` |
|
||||
| `const_reference` | `Container::const_reference` |
|
||||
| `pointer` | `Container::pointer` |
|
||||
| `const_pointer` | `Container::const_pointer` |
|
||||
| `iterator` | `Container::iterator` |
|
||||
| `const_iterator` | `Container::const_iterator` |
|
||||
| `reverse_iterator` | `Container::reverse_iterator` |
|
||||
| `const_reverse_iterator` | `Container::const_reverse_iterator` |
|
||||
|
||||
### Member functions
|
||||
|
||||
```cpp
|
||||
explicit flat_set(
|
||||
const Allocator& a);
|
||||
|
||||
explicit flat_set(
|
||||
const Compare& c = Compare(),
|
||||
const Allocator& a = Allocator());
|
||||
|
||||
template < typename InputIter >
|
||||
flat_set(
|
||||
InputIter first,
|
||||
InputIter last,
|
||||
const Allocator& a);
|
||||
|
||||
template < typename InputIter >
|
||||
flat_set(
|
||||
InputIter first,
|
||||
InputIter last,
|
||||
const Compare& c = Compare(),
|
||||
const Allocator& a = Allocator());
|
||||
|
||||
flat_set(
|
||||
std::initializer_list<value_type> ilist,
|
||||
const Allocator& a);
|
||||
|
||||
flat_set(
|
||||
std::initializer_list<value_type> ilist,
|
||||
const Compare& c = Compare(),
|
||||
const Allocator& a = Allocator());
|
||||
|
||||
flat_set(flat_set&& other);
|
||||
flat_set(const flat_set& other)
|
||||
|
||||
flat_set& operator=(flat_set&& other);
|
||||
flat_set& operator=(const flat_set& other);
|
||||
flat_set& operator=(std::initializer_list<value_type> ilist);
|
||||
|
||||
allocator_type get_allocator() const;
|
||||
```
|
||||
|
||||
### Iterators
|
||||
|
||||
```cpp
|
||||
iterator begin() noexcept;
|
||||
const_iterator begin() const noexcept;
|
||||
const_iterator cbegin() const noexcept;
|
||||
|
||||
iterator end() noexcept;
|
||||
const_iterator end() const noexcept;
|
||||
const_iterator cend() const noexcept;
|
||||
|
||||
reverse_iterator rbegin() noexcept;
|
||||
const_reverse_iterator rbegin() const noexcept;
|
||||
const_reverse_iterator crbegin() const noexcept;
|
||||
|
||||
reverse_iterator rend() noexcept;
|
||||
const_reverse_iterator rend() const noexcept;
|
||||
const_reverse_iterator crend() const noexcept;
|
||||
```
|
||||
|
||||
### Capacity
|
||||
|
||||
```cpp
|
||||
bool empty() const noexcept;
|
||||
size_type size() const noexcept;
|
||||
size_type max_size() const noexcept;
|
||||
```
|
||||
|
||||
### Modifiers
|
||||
|
||||
```cpp
|
||||
std::pair<iterator, bool> insert(value_type&& value);
|
||||
std::pair<iterator, bool> insert(const value_type& value);
|
||||
|
||||
iterator insert(const_iterator hint, value_type&& value);
|
||||
iterator insert(const_iterator hint, const value_type& value);
|
||||
|
||||
template < typename InputIter >
|
||||
void insert(InputIter first, InputIter last);
|
||||
void insert(std::initializer_list<value_type> ilist);
|
||||
|
||||
template < typename... Args >
|
||||
std::pair<iterator, bool> emplace(Args&&... args);
|
||||
template < typename... Args >
|
||||
iterator emplace_hint(const_iterator hint, Args&&... args);
|
||||
|
||||
void clear() noexcept;
|
||||
iterator erase(const_iterator iter);
|
||||
iterator erase(const_iterator first, const_iterator last);
|
||||
size_type erase(const key_type& key);
|
||||
|
||||
void swap(flat_set& other);
|
||||
```
|
||||
|
||||
### Lookup
|
||||
|
||||
```cpp
|
||||
size_type count(const key_type& key) const;
|
||||
|
||||
iterator find(const key_type& key);
|
||||
const_iterator find(const key_type& key) const;
|
||||
|
||||
std::pair<iterator, iterator> equal_range(const key_type& key);
|
||||
std::pair<const_iterator, const_iterator> equal_range(const key_type& key) const;
|
||||
|
||||
iterator lower_bound(const key_type& key);
|
||||
const_iterator lower_bound(const key_type& key) const;
|
||||
|
||||
iterator upper_bound(const key_type& key);
|
||||
const_iterator upper_bound(const key_type& key) const;
|
||||
```
|
||||
|
||||
### Observers
|
||||
|
||||
```cpp
|
||||
key_compare key_comp() const;
|
||||
value_compare value_comp() const;
|
||||
```
|
||||
|
||||
### Non-member functions
|
||||
|
||||
```cpp
|
||||
template < typename K, typename C, typename A >
|
||||
void swap(
|
||||
flat_set<K, C, A>& l,
|
||||
flat_set<K, C, A>& r);
|
||||
|
||||
template < typename K, typename C, typename A >
|
||||
bool operator==(
|
||||
const flat_set<K, C, A>& l,
|
||||
const flat_set<K, C, A>& r);
|
||||
|
||||
template < typename K, typename C, typename A >
|
||||
bool operator!=(
|
||||
const flat_set<K, C, A>& l,
|
||||
const flat_set<K, C, A>& r);
|
||||
|
||||
template < typename K, typename C, typename A >
|
||||
bool operator<(
|
||||
const flat_set<K, C, A>& l,
|
||||
const flat_set<K, C, A>& r);
|
||||
|
||||
template < typename K, typename C, typename A >
|
||||
bool operator>(
|
||||
const flat_set<K, C, A>& l,
|
||||
const flat_set<K, C, A>& r);
|
||||
|
||||
template < typename K, typename C, typename A >
|
||||
bool operator<=(
|
||||
const flat_set<K, C, A>& l,
|
||||
const flat_set<K, C, A>& r);
|
||||
|
||||
template < typename K, typename C, typename A >
|
||||
bool operator>=(
|
||||
const flat_set<K, C, A>& l,
|
||||
const flat_set<K, C, A>& r);
|
||||
```
|
||||
|
||||
## flat_map
|
||||
|
||||
```cpp
|
||||
template < typename Key
|
||||
, typename Value
|
||||
, typename Compare = std::less<Key>
|
||||
, typename Allocator = std::allocator<std::pair<Key, Value>>
|
||||
, typename Container = std::vector<std::pair<Key, Value>, Allocator> >
|
||||
class flat_map;
|
||||
```
|
||||
|
||||
### Member types
|
||||
|
||||
| Member type | Definition |
|
||||
|--------------------------|-------------------------------------|
|
||||
| `key_type` | `Key` |
|
||||
| `mapped_type` | `Value` |
|
||||
| `value_type` | `Container::value_type` |
|
||||
| `size_type` | `Container::size_type` |
|
||||
| `difference_type` | `Container::difference_type` |
|
||||
| `key_compare` | `Compare` |
|
||||
| `allocator_type` | `Allocator` |
|
||||
| `container_type` | `Container` |
|
||||
| `reference` | `Container::reference` |
|
||||
| `const_reference` | `Container::const_reference` |
|
||||
| `pointer` | `Container::pointer` |
|
||||
| `const_pointer` | `Container::const_pointer` |
|
||||
| `iterator` | `Container::iterator` |
|
||||
| `const_iterator` | `Container::const_iterator` |
|
||||
| `reverse_iterator` | `Container::reverse_iterator` |
|
||||
| `const_reverse_iterator` | `Container::const_reverse_iterator` |
|
||||
|
||||
### Member classes
|
||||
|
||||
```cpp
|
||||
class value_compare;
|
||||
```
|
||||
|
||||
### Member functions
|
||||
|
||||
```cpp
|
||||
explicit flat_map(
|
||||
const Allocator& a);
|
||||
|
||||
explicit flat_map(
|
||||
const Compare& c = Compare(),
|
||||
const Allocator& a = Allocator());
|
||||
|
||||
template < typename InputIter >
|
||||
flat_map(
|
||||
InputIter first,
|
||||
InputIter last,
|
||||
const Allocator& a);
|
||||
|
||||
template < typename InputIter >
|
||||
flat_map(
|
||||
InputIter first,
|
||||
InputIter last,
|
||||
const Compare& c = Compare(),
|
||||
const Allocator& a = Allocator());
|
||||
|
||||
flat_map(
|
||||
std::initializer_list<value_type> ilist,
|
||||
const Allocator& a);
|
||||
|
||||
flat_map(
|
||||
std::initializer_list<value_type> ilist,
|
||||
const Compare& c = Compare(),
|
||||
const Allocator& a = Allocator());
|
||||
|
||||
flat_map(flat_map&& other);
|
||||
flat_map(const flat_map& other);
|
||||
|
||||
flat_map& operator=(flat_map&& other);
|
||||
flat_map& operator=(const flat_map& other);
|
||||
flat_map& operator=(std::initializer_list<value_type> ilist);
|
||||
|
||||
allocator_type get_allocator() const;
|
||||
```
|
||||
|
||||
### Iterators
|
||||
|
||||
```cpp
|
||||
iterator begin() noexcept;
|
||||
const_iterator begin() const noexcept;
|
||||
const_iterator cbegin() const noexcept;
|
||||
|
||||
iterator end() noexcept;
|
||||
const_iterator end() const noexcept;
|
||||
const_iterator cend() const noexcept;
|
||||
|
||||
reverse_iterator rbegin() noexcept;
|
||||
const_reverse_iterator rbegin() const noexcept;
|
||||
const_reverse_iterator crbegin() const noexcept;
|
||||
|
||||
reverse_iterator rend() noexcept;
|
||||
const_reverse_iterator rend() const noexcept;
|
||||
const_reverse_iterator crend() const noexcept;
|
||||
```
|
||||
|
||||
### Capacity
|
||||
|
||||
```cpp
|
||||
bool empty() const noexcept;
|
||||
size_type size() const noexcept;
|
||||
size_type max_size() const noexcept;
|
||||
```
|
||||
|
||||
### Element access
|
||||
|
||||
```cpp
|
||||
mapped_type& operator[](key_type&& key);
|
||||
mapped_type& operator[](const key_type& key);
|
||||
|
||||
mapped_type& at(const key_type& key);
|
||||
const mapped_type& at(const key_type& key) const;
|
||||
```
|
||||
|
||||
### Modifiers
|
||||
|
||||
```cpp
|
||||
std::pair<iterator, bool> insert(value_type&& value);
|
||||
std::pair<iterator, bool> insert(const value_type& value);
|
||||
|
||||
iterator insert(const_iterator hint, value_type&& value);
|
||||
iterator insert(const_iterator hint, const value_type& value);
|
||||
|
||||
template < typename InputIter >
|
||||
void insert(InputIter first, InputIter last);
|
||||
void insert(std::initializer_list<value_type> ilist);
|
||||
|
||||
template < typename... Args >
|
||||
std::pair<iterator, bool> emplace(Args&&... args);
|
||||
template < typename... Args >
|
||||
iterator emplace_hint(const_iterator hint, Args&&... args);
|
||||
|
||||
void clear() noexcept;
|
||||
iterator erase(const_iterator iter);
|
||||
iterator erase(const_iterator first, const_iterator last);
|
||||
size_type erase(const key_type& key);
|
||||
|
||||
void swap(flat_map& other)
|
||||
```
|
||||
|
||||
### Lookup
|
||||
|
||||
```cpp
|
||||
size_type count(const key_type& key) const;
|
||||
|
||||
iterator find(const key_type& key);
|
||||
const_iterator find(const key_type& key) const;
|
||||
|
||||
std::pair<iterator, iterator> equal_range(const key_type& key);
|
||||
std::pair<const_iterator, const_iterator> equal_range(const key_type& key) const;
|
||||
|
||||
iterator lower_bound(const key_type& key);
|
||||
const_iterator lower_bound(const key_type& key) const;
|
||||
|
||||
iterator upper_bound(const key_type& key);
|
||||
const_iterator upper_bound(const key_type& key) const;
|
||||
```
|
||||
|
||||
### Observers
|
||||
|
||||
```cpp
|
||||
key_compare key_comp() const;
|
||||
value_compare value_comp() const;
|
||||
```
|
||||
|
||||
### Non-member functions
|
||||
|
||||
```cpp
|
||||
template < typename K, typename V, typename C, typename A >
|
||||
void swap(
|
||||
flat_map<K, V, C, A>& l,
|
||||
flat_map<K, V, C, A>& r);
|
||||
|
||||
template < typename K, typename V, typename C, typename A >
|
||||
bool operator==(
|
||||
const flat_map<K, V, C, A>& l,
|
||||
const flat_map<K, V, C, A>& r);
|
||||
|
||||
template < typename K, typename V, typename C, typename A >
|
||||
bool operator!=(
|
||||
const flat_map<K, V, C, A>& l,
|
||||
const flat_map<K, V, C, A>& r);
|
||||
|
||||
template < typename K, typename V, typename C, typename A >
|
||||
bool operator<(
|
||||
const flat_map<K, V, C, A>& l,
|
||||
const flat_map<K, V, C, A>& r);
|
||||
|
||||
template < typename K, typename V, typename C, typename A >
|
||||
bool operator>(
|
||||
const flat_map<K, V, C, A>& l,
|
||||
const flat_map<K, V, C, A>& r);
|
||||
|
||||
template < typename K, typename V, typename C, typename A >
|
||||
bool operator<=(
|
||||
const flat_map<K, V, C, A>& l,
|
||||
const flat_map<K, V, C, A>& r);
|
||||
|
||||
template < typename K, typename V, typename C, typename A >
|
||||
bool operator>=(
|
||||
const flat_map<K, V, C, A>& l,
|
||||
const flat_map<K, V, C, A>& r);
|
||||
```
|
||||
|
||||
## [License (MIT)](./LICENSE.md)
|
||||
|
||||
107
flat_map.hpp
107
flat_map.hpp
@@ -20,12 +20,9 @@ namespace flat_hpp
|
||||
template < typename Key
|
||||
, typename Value
|
||||
, typename Compare = std::less<Key>
|
||||
, typename Allocator = std::allocator<std::pair<Key, Value>> >
|
||||
, typename Allocator = std::allocator<std::pair<Key, Value>>
|
||||
, typename Container = std::vector<std::pair<Key, Value>, Allocator> >
|
||||
class flat_map final {
|
||||
using data_type = std::vector<
|
||||
std::pair<Key, Value>,
|
||||
Allocator>;
|
||||
|
||||
class uber_comparer_type : public Compare {
|
||||
public:
|
||||
uber_comparer_type() = default;
|
||||
@@ -35,36 +32,37 @@ namespace flat_hpp
|
||||
return Compare::operator()(l, r);
|
||||
}
|
||||
|
||||
bool operator()(const Key& l, typename data_type::const_reference r) const {
|
||||
bool operator()(const Key& l, typename Container::const_reference r) const {
|
||||
return Compare::operator()(l, r.first);
|
||||
}
|
||||
|
||||
bool operator()(typename data_type::const_reference l, const Key& r) const {
|
||||
bool operator()(typename Container::const_reference l, const Key& r) const {
|
||||
return Compare::operator()(l.first, r);
|
||||
}
|
||||
};
|
||||
public:
|
||||
using key_type = Key;
|
||||
using mapped_type = Value;
|
||||
using value_type = typename data_type::value_type;
|
||||
using value_type = typename Container::value_type;
|
||||
|
||||
using size_type = typename data_type::size_type;
|
||||
using difference_type = typename data_type::difference_type;
|
||||
using size_type = typename Container::size_type;
|
||||
using difference_type = typename Container::difference_type;
|
||||
|
||||
using key_compare = Compare;
|
||||
using allocator_type = Allocator;
|
||||
using container_type = Container;
|
||||
|
||||
using reference = typename data_type::reference;
|
||||
using const_reference = typename data_type::const_reference;
|
||||
using pointer = typename data_type::pointer;
|
||||
using const_pointer = typename data_type::const_pointer;
|
||||
using reference = typename Container::reference;
|
||||
using const_reference = typename Container::const_reference;
|
||||
using pointer = typename Container::pointer;
|
||||
using const_pointer = typename Container::const_pointer;
|
||||
|
||||
using iterator = typename data_type::iterator;
|
||||
using const_iterator = typename data_type::const_iterator;
|
||||
using reverse_iterator = typename data_type::reverse_iterator;
|
||||
using const_reverse_iterator = typename data_type::const_reverse_iterator;
|
||||
using iterator = typename Container::iterator;
|
||||
using const_iterator = typename Container::const_iterator;
|
||||
using reverse_iterator = typename Container::reverse_iterator;
|
||||
using const_reverse_iterator = typename Container::const_reverse_iterator;
|
||||
|
||||
class value_compare final {
|
||||
class value_compare {
|
||||
public:
|
||||
bool operator()(const value_type& l, const value_type& r) const {
|
||||
return compare_(l.first, r.first);
|
||||
@@ -80,6 +78,14 @@ namespace flat_hpp
|
||||
static_assert(
|
||||
std::is_same<typename allocator_type::value_type, value_type>::value,
|
||||
"Allocator::value_type must be same type as value_type");
|
||||
|
||||
static_assert(
|
||||
std::is_same<typename container_type::value_type, value_type>::value,
|
||||
"Container::value_type must be same type as value_type");
|
||||
|
||||
static_assert(
|
||||
std::is_same<typename container_type::allocator_type, allocator_type>::value,
|
||||
"Container::allocator_type must be same type as allocator_type");
|
||||
public:
|
||||
explicit flat_map(
|
||||
const Allocator& a)
|
||||
@@ -127,6 +133,37 @@ namespace flat_hpp
|
||||
insert(ilist);
|
||||
}
|
||||
|
||||
flat_map(flat_map&& other)
|
||||
: data_(std::move(other.data_))
|
||||
, compare_(std::move(other.compare_)) {}
|
||||
|
||||
flat_map(const flat_map& other)
|
||||
: data_(other.data_)
|
||||
, compare_(other.compare_) {}
|
||||
|
||||
flat_map& operator=(flat_map&& other) {
|
||||
if ( this != &other ) {
|
||||
flat_map(std::move(other)).swap(*this);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
flat_map& operator=(const flat_map& other) {
|
||||
if ( this != &other ) {
|
||||
flat_map(other).swap(*this);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
flat_map& operator=(std::initializer_list<value_type> ilist) {
|
||||
flat_map(ilist).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
allocator_type get_allocator() const {
|
||||
return data_.get_allocator();
|
||||
}
|
||||
|
||||
iterator begin() noexcept { return data_.begin(); }
|
||||
const_iterator begin() const noexcept { return data_.begin(); }
|
||||
const_iterator cbegin() const noexcept { return data_.cbegin(); }
|
||||
@@ -156,15 +193,21 @@ namespace flat_hpp
|
||||
}
|
||||
|
||||
mapped_type& operator[](key_type&& key) {
|
||||
return insert(value_type(std::move(key), mapped_type())).first->second;
|
||||
const iterator iter = find(key);
|
||||
return iter != end()
|
||||
? iter->second
|
||||
: emplace(std::move(key), mapped_type()).first->second;
|
||||
}
|
||||
|
||||
mapped_type& operator[](const key_type& key) {
|
||||
return insert(value_type(key, mapped_type())).first->second;
|
||||
const iterator iter = find(key);
|
||||
return iter != end()
|
||||
? iter->second
|
||||
: emplace(key, mapped_type()).first->second;
|
||||
}
|
||||
|
||||
mapped_type& at(const key_type& key) {
|
||||
const auto iter = find(key);
|
||||
const iterator iter = find(key);
|
||||
if ( iter != end() ) {
|
||||
return iter->second;
|
||||
}
|
||||
@@ -172,13 +215,20 @@ namespace flat_hpp
|
||||
}
|
||||
|
||||
const mapped_type& at(const key_type& key) const {
|
||||
const auto iter = find(key);
|
||||
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<iterator, bool> insert(value_type&& value) {
|
||||
const iterator iter = lower_bound(value.first);
|
||||
return iter == end() || compare_(value.first, iter->first)
|
||||
? 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.first, iter->first)
|
||||
@@ -186,13 +236,20 @@ namespace flat_hpp
|
||||
: std::make_pair(iter, false);
|
||||
}
|
||||
|
||||
iterator insert(const_iterator hint, const value_type& value) {
|
||||
iterator insert(const_iterator hint, value_type&& value) {
|
||||
return (hint == begin() || compare_((hint - 1)->first, value.first))
|
||||
&& (hint == end() || compare_(value.first, hint->first))
|
||||
? data_.insert(hint, std::move(value))
|
||||
: insert(std::move(value)).first;
|
||||
}
|
||||
|
||||
iterator insert(const_iterator hint, const value_type& value) {
|
||||
return (hint == begin() || compare_((hint - 1)->first, value.first))
|
||||
&& (hint == end() || compare_(value.first, hint->first))
|
||||
? data_.insert(hint, value)
|
||||
: insert(value).first;
|
||||
}
|
||||
|
||||
template < typename InputIter >
|
||||
void insert(InputIter first, InputIter last) {
|
||||
while ( first != last ) {
|
||||
@@ -290,7 +347,7 @@ namespace flat_hpp
|
||||
return value_compare(compare_);
|
||||
}
|
||||
private:
|
||||
data_type data_;
|
||||
container_type data_;
|
||||
uber_comparer_type compare_;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -18,9 +18,11 @@ namespace
|
||||
using value_type = T;
|
||||
|
||||
dummy_allocator() = default;
|
||||
dummy_allocator(int i) : i(i) {}
|
||||
|
||||
template < typename U >
|
||||
dummy_allocator(const dummy_allocator<U>&) noexcept {
|
||||
dummy_allocator(const dummy_allocator<U>& o) noexcept {
|
||||
i = o.i;
|
||||
}
|
||||
|
||||
T* allocate(std::size_t n) noexcept {
|
||||
@@ -31,6 +33,8 @@ namespace
|
||||
(void)n;
|
||||
std::free(p);
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
};
|
||||
|
||||
template < typename T, typename U >
|
||||
@@ -100,6 +104,9 @@ TEST_CASE("flat_map") {
|
||||
std::greater<int>,
|
||||
alloc_t>;
|
||||
|
||||
using vec_t = std::vector<
|
||||
std::pair<int,unsigned>>;
|
||||
|
||||
{
|
||||
auto s0 = map_t();
|
||||
auto s1 = map2_t(alloc_t());
|
||||
@@ -108,8 +115,6 @@ TEST_CASE("flat_map") {
|
||||
}
|
||||
|
||||
{
|
||||
using vec_t = std::vector<std::pair<int,unsigned>>;
|
||||
|
||||
vec_t v{{1,30},{2,20},{3,10}};
|
||||
auto s0 = map_t(v.cbegin(), v.cend());
|
||||
auto s1 = map2_t(v.cbegin(), v.cend(), alloc_t());
|
||||
@@ -127,6 +132,44 @@ TEST_CASE("flat_map") {
|
||||
auto s1 = map_t({{0,1}, {1,2}}, alloc_t());
|
||||
auto s2 = map_t({{0,1}, {1,2}}, std::less<int>());
|
||||
auto s3 = map_t({{0,1}, {1,2}}, std::less<int>(), alloc_t());
|
||||
|
||||
REQUIRE(vec_t(s0.begin(), s0.end()) == vec_t({{0,1},{1,2}}));
|
||||
REQUIRE(vec_t(s1.begin(), s1.end()) == vec_t({{0,1},{1,2}}));
|
||||
REQUIRE(vec_t(s2.begin(), s2.end()) == vec_t({{0,1},{1,2}}));
|
||||
REQUIRE(vec_t(s3.begin(), s3.end()) == vec_t({{0,1},{1,2}}));
|
||||
}
|
||||
|
||||
{
|
||||
auto s0 = map_t();
|
||||
auto s1 = map_t(alloc_t(42));
|
||||
REQUIRE(s0.get_allocator().i == 0);
|
||||
REQUIRE(s1.get_allocator().i == 42);
|
||||
}
|
||||
|
||||
{
|
||||
auto s0 = map_t{{0,1}, {1,2}};
|
||||
auto s1 = s0;
|
||||
REQUIRE(s0 == map_t{{0,1}, {1,2}});
|
||||
REQUIRE(s1 == map_t{{0,1}, {1,2}});
|
||||
auto s2 = std::move(s1);
|
||||
REQUIRE(s1.empty());
|
||||
REQUIRE(s2 == map_t{{0,1}, {1,2}});
|
||||
}
|
||||
|
||||
{
|
||||
auto s0 = map_t{{0,1}, {1,2}};
|
||||
map_t s1;
|
||||
s1 = s0;
|
||||
REQUIRE(s0 == map_t{{0,1}, {1,2}});
|
||||
REQUIRE(s1 == map_t{{0,1}, {1,2}});
|
||||
map_t s2;
|
||||
s2 = std::move(s1);
|
||||
REQUIRE(s0 == map_t{{0,1}, {1,2}});
|
||||
REQUIRE(s1.empty());
|
||||
REQUIRE(s2 == map_t{{0,1}, {1,2}});
|
||||
map_t s3;
|
||||
s3 = {{0,1}, {1,2}};
|
||||
REQUIRE(s3 == map_t{{0,1}, {1,2}});
|
||||
}
|
||||
}
|
||||
SECTION("capacity") {
|
||||
@@ -156,15 +199,34 @@ TEST_CASE("flat_map") {
|
||||
REQUIRE(s0.max_size() == std::allocator<std::pair<int,unsigned>>().max_size());
|
||||
}
|
||||
SECTION("access") {
|
||||
using map_t = flat_map<int, unsigned>;
|
||||
struct obj_t {
|
||||
obj_t(int i) : i(i) {}
|
||||
int i;
|
||||
|
||||
bool operator<(const obj_t& o) const {
|
||||
return i < o.i;
|
||||
}
|
||||
|
||||
bool operator==(const obj_t& o) const {
|
||||
return i == o.i;
|
||||
}
|
||||
};
|
||||
|
||||
using map_t = flat_map<obj_t, unsigned>;
|
||||
map_t s0;
|
||||
s0[1] = 42;
|
||||
|
||||
obj_t k1(1);
|
||||
|
||||
s0[k1] = 42;
|
||||
REQUIRE(s0[k1] == 42);
|
||||
REQUIRE(s0 == map_t{{1,42}});
|
||||
|
||||
s0[1] = 84;
|
||||
REQUIRE(s0[1] == 84);
|
||||
REQUIRE(s0 == map_t{{1,84}});
|
||||
|
||||
REQUIRE(s0.at(1) == 84);
|
||||
REQUIRE(my_as_const(s0).at(1) == 84);
|
||||
REQUIRE(my_as_const(s0).at(k1) == 84);
|
||||
REQUIRE_THROWS_AS(s0.at(0), std::out_of_range);
|
||||
REQUIRE_THROWS_AS(my_as_const(s0).at(0), std::out_of_range);
|
||||
}
|
||||
@@ -182,12 +244,15 @@ TEST_CASE("flat_map") {
|
||||
}
|
||||
};
|
||||
|
||||
using map_t = flat_map<int, obj_t>;
|
||||
using map_t = flat_map<obj_t, obj_t>;
|
||||
|
||||
{
|
||||
map_t s0;
|
||||
|
||||
auto i0 = s0.insert(std::make_pair(1, 42));
|
||||
auto k1_42 = std::make_pair(1, 42);
|
||||
auto k3_84 = std::make_pair(3, 84);
|
||||
|
||||
auto i0 = s0.insert(k1_42);
|
||||
REQUIRE(s0 == map_t{{1,42}});
|
||||
REQUIRE(i0 == std::make_pair(s0.begin(), true));
|
||||
|
||||
@@ -199,7 +264,7 @@ TEST_CASE("flat_map") {
|
||||
REQUIRE(s0 == map_t{{1,42},{2,42}});
|
||||
REQUIRE(i2 == std::make_pair(s0.begin() + 1, true));
|
||||
|
||||
auto i3 = s0.insert(s0.cend(), std::make_pair(3, 84));
|
||||
auto i3 = s0.insert(s0.cend(), k3_84);
|
||||
REQUIRE(i3 == s0.begin() + 2);
|
||||
|
||||
s0.insert(s0.cend(), std::make_pair(4, obj_t(84)));
|
||||
|
||||
77
flat_set.hpp
77
flat_set.hpp
@@ -19,33 +19,51 @@ namespace flat_hpp
|
||||
{
|
||||
template < typename Key
|
||||
, typename Compare = std::less<Key>
|
||||
, typename Allocator = std::allocator<Key> >
|
||||
, typename Allocator = std::allocator<Key>
|
||||
, typename Container = std::vector<Key, Allocator> >
|
||||
class flat_set final {
|
||||
using data_type = std::vector<Key, Allocator>;
|
||||
class uber_comparer_type : public Compare {
|
||||
public:
|
||||
uber_comparer_type() = default;
|
||||
uber_comparer_type(const Compare& c) : Compare(c) {}
|
||||
|
||||
bool operator()(const Key& l, const Key& r) const {
|
||||
return Compare::operator()(l, r);
|
||||
}
|
||||
};
|
||||
public:
|
||||
using key_type = Key;
|
||||
using value_type = Key;
|
||||
|
||||
using size_type = typename data_type::size_type;
|
||||
using difference_type = typename data_type::difference_type;
|
||||
using size_type = typename Container::size_type;
|
||||
using difference_type = typename Container::difference_type;
|
||||
|
||||
using key_compare = Compare;
|
||||
using value_compare = Compare;
|
||||
using allocator_type = Allocator;
|
||||
using container_type = Container;
|
||||
|
||||
using reference = typename data_type::reference;
|
||||
using const_reference = typename data_type::const_reference;
|
||||
using pointer = typename data_type::pointer;
|
||||
using const_pointer = typename data_type::const_pointer;
|
||||
using reference = typename Container::reference;
|
||||
using const_reference = typename Container::const_reference;
|
||||
using pointer = typename Container::pointer;
|
||||
using const_pointer = typename Container::const_pointer;
|
||||
|
||||
using iterator = typename data_type::iterator;
|
||||
using const_iterator = typename data_type::const_iterator;
|
||||
using reverse_iterator = typename data_type::reverse_iterator;
|
||||
using const_reverse_iterator = typename data_type::const_reverse_iterator;
|
||||
using iterator = typename Container::iterator;
|
||||
using const_iterator = typename Container::const_iterator;
|
||||
using reverse_iterator = typename Container::reverse_iterator;
|
||||
using const_reverse_iterator = typename Container::const_reverse_iterator;
|
||||
|
||||
static_assert(
|
||||
std::is_same<typename allocator_type::value_type, value_type>::value,
|
||||
"Allocator::value_type must be same type as value_type");
|
||||
|
||||
static_assert(
|
||||
std::is_same<typename container_type::value_type, value_type>::value,
|
||||
"Container::value_type must be same type as value_type");
|
||||
|
||||
static_assert(
|
||||
std::is_same<typename container_type::allocator_type, allocator_type>::value,
|
||||
"Container::allocator_type must be same type as allocator_type");
|
||||
public:
|
||||
explicit flat_set(
|
||||
const Allocator& a)
|
||||
@@ -93,6 +111,37 @@ namespace flat_hpp
|
||||
insert(ilist);
|
||||
}
|
||||
|
||||
flat_set(flat_set&& other)
|
||||
: data_(std::move(other.data_))
|
||||
, compare_(std::move(other.compare_)) {}
|
||||
|
||||
flat_set(const flat_set& other)
|
||||
: data_(other.data_)
|
||||
, compare_(other.compare_) {}
|
||||
|
||||
flat_set& operator=(flat_set&& other) {
|
||||
if ( this != &other ) {
|
||||
flat_set(std::move(other)).swap(*this);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
flat_set& operator=(const flat_set& other) {
|
||||
if ( this != &other ) {
|
||||
flat_set(other).swap(*this);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
flat_set& operator=(std::initializer_list<value_type> ilist) {
|
||||
flat_set(ilist).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
allocator_type get_allocator() const {
|
||||
return data_.get_allocator();
|
||||
}
|
||||
|
||||
iterator begin() noexcept { return data_.begin(); }
|
||||
const_iterator begin() const noexcept { return data_.begin(); }
|
||||
const_iterator cbegin() const noexcept { return data_.cbegin(); }
|
||||
@@ -246,8 +295,8 @@ namespace flat_hpp
|
||||
return value_compare(compare_);
|
||||
}
|
||||
private:
|
||||
data_type data_;
|
||||
key_compare compare_;
|
||||
container_type data_;
|
||||
uber_comparer_type compare_;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -18,9 +18,11 @@ namespace
|
||||
using value_type = T;
|
||||
|
||||
dummy_allocator() = default;
|
||||
dummy_allocator(int i) : i(i) {}
|
||||
|
||||
template < typename U >
|
||||
dummy_allocator(const dummy_allocator<U>&) noexcept {
|
||||
dummy_allocator(const dummy_allocator<U>& o) noexcept {
|
||||
i = o.i;
|
||||
}
|
||||
|
||||
T* allocate(std::size_t n) noexcept {
|
||||
@@ -31,6 +33,8 @@ namespace
|
||||
(void)n;
|
||||
std::free(p);
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
};
|
||||
|
||||
template < typename T, typename U >
|
||||
@@ -85,6 +89,7 @@ TEST_CASE("flat_set") {
|
||||
using alloc_t = dummy_allocator<int>;
|
||||
using set_t = flat_set<int, std::less<int>, alloc_t>;
|
||||
using set2_t = flat_set<int, std::greater<int>, alloc_t>;
|
||||
using vec_t = std::vector<int>;
|
||||
|
||||
{
|
||||
auto s0 = set_t();
|
||||
@@ -94,16 +99,16 @@ TEST_CASE("flat_set") {
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<int> v{1,2,3};
|
||||
vec_t v{1,2,3};
|
||||
auto s0 = set_t(v.cbegin(), v.cend());
|
||||
auto s1 = set2_t(v.cbegin(), v.cend(), alloc_t());
|
||||
auto s2 = set_t(v.cbegin(), v.cend(), std::less<int>());
|
||||
auto s3 = set2_t(v.cbegin(), v.cend(), std::greater<int>(), alloc_t());
|
||||
|
||||
REQUIRE(std::vector<int>(s0.begin(), s0.end()) == std::vector<int>({1,2,3}));
|
||||
REQUIRE(std::vector<int>(s1.begin(), s1.end()) == std::vector<int>({3,2,1}));
|
||||
REQUIRE(std::vector<int>(s2.begin(), s2.end()) == std::vector<int>({1,2,3}));
|
||||
REQUIRE(std::vector<int>(s3.begin(), s3.end()) == std::vector<int>({3,2,1}));
|
||||
REQUIRE(vec_t(s0.begin(), s0.end()) == vec_t({1,2,3}));
|
||||
REQUIRE(vec_t(s1.begin(), s1.end()) == vec_t({3,2,1}));
|
||||
REQUIRE(vec_t(s2.begin(), s2.end()) == vec_t({1,2,3}));
|
||||
REQUIRE(vec_t(s3.begin(), s3.end()) == vec_t({3,2,1}));
|
||||
}
|
||||
|
||||
{
|
||||
@@ -112,10 +117,43 @@ TEST_CASE("flat_set") {
|
||||
auto s2 = set_t({0,1,2}, std::less<int>());
|
||||
auto s3 = set2_t({0,1,2}, std::greater<int>(), alloc_t());
|
||||
|
||||
REQUIRE(std::vector<int>(s0.begin(), s0.end()) == std::vector<int>({0,1,2}));
|
||||
REQUIRE(std::vector<int>(s1.begin(), s1.end()) == std::vector<int>({2,1,0}));
|
||||
REQUIRE(std::vector<int>(s2.begin(), s2.end()) == std::vector<int>({0,1,2}));
|
||||
REQUIRE(std::vector<int>(s3.begin(), s3.end()) == std::vector<int>({2,1,0}));
|
||||
REQUIRE(vec_t(s0.begin(), s0.end()) == vec_t({0,1,2}));
|
||||
REQUIRE(vec_t(s1.begin(), s1.end()) == vec_t({2,1,0}));
|
||||
REQUIRE(vec_t(s2.begin(), s2.end()) == vec_t({0,1,2}));
|
||||
REQUIRE(vec_t(s3.begin(), s3.end()) == vec_t({2,1,0}));
|
||||
}
|
||||
|
||||
{
|
||||
auto s0 = set_t();
|
||||
auto s1 = set_t(alloc_t(42));
|
||||
REQUIRE(s0.get_allocator().i == 0);
|
||||
REQUIRE(s1.get_allocator().i == 42);
|
||||
}
|
||||
|
||||
{
|
||||
auto s0 = set_t{0,1,2};
|
||||
auto s1 = s0;
|
||||
REQUIRE(s0 == set_t{0,1,2});
|
||||
REQUIRE(s1 == set_t{0,1,2});
|
||||
auto s2 = std::move(s1);
|
||||
REQUIRE(s1.empty());
|
||||
REQUIRE(s2 == set_t{0,1,2});
|
||||
}
|
||||
|
||||
{
|
||||
auto s0 = set_t{0,1,2};
|
||||
set_t s1;
|
||||
s1 = s0;
|
||||
REQUIRE(s0 == set_t{0,1,2});
|
||||
REQUIRE(s1 == set_t{0,1,2});
|
||||
set_t s2;
|
||||
s2 = std::move(s1);
|
||||
REQUIRE(s0 == set_t{0,1,2});
|
||||
REQUIRE(s1.empty());
|
||||
REQUIRE(s2 == set_t{0,1,2});
|
||||
set_t s3;
|
||||
s3 = {1,2,3};
|
||||
REQUIRE(s3 == set_t{1,2,3});
|
||||
}
|
||||
}
|
||||
SECTION("capacity") {
|
||||
|
||||
Reference in New Issue
Block a user