mirror of
https://github.com/BlackMATov/flat.hpp.git
synced 2025-12-13 17:48:14 +07:00
add flat_multimap and flat_multiset containers #4
This commit is contained in:
436
headers/flat_hpp/flat_multimap.hpp
Normal file
436
headers/flat_hpp/flat_multimap.hpp
Normal file
@@ -0,0 +1,436 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* 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 <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include <utility>
|
||||||
|
#include <iterator>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <functional>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <initializer_list>
|
||||||
|
|
||||||
|
namespace flat_hpp
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
public:
|
||||||
|
using key_type = Key;
|
||||||
|
using mapped_type = Value;
|
||||||
|
using value_type = typename Container::value_type;
|
||||||
|
|
||||||
|
using size_type = typename Container::size_type;
|
||||||
|
using difference_type = typename Container::difference_type;
|
||||||
|
|
||||||
|
using key_compare = Compare;
|
||||||
|
using container_type = Container;
|
||||||
|
|
||||||
|
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 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 {
|
||||||
|
public:
|
||||||
|
bool operator()(const value_type& l, const value_type& r) const {
|
||||||
|
return compare_(l.first, r.first);
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
friend class flat_multimap;
|
||||||
|
explicit value_compare(key_compare compare)
|
||||||
|
: compare_(std::move(compare)) {}
|
||||||
|
private:
|
||||||
|
key_compare compare_;
|
||||||
|
};
|
||||||
|
public:
|
||||||
|
flat_multimap() {}
|
||||||
|
|
||||||
|
explicit flat_multimap(const Compare& c)
|
||||||
|
: compare_(c) {}
|
||||||
|
|
||||||
|
template < typename Allocator >
|
||||||
|
explicit flat_multimap(const Allocator& a)
|
||||||
|
: data_(a) {}
|
||||||
|
|
||||||
|
template < typename Allocator >
|
||||||
|
flat_multimap(const Compare& c, const Allocator& a)
|
||||||
|
: data_(a)
|
||||||
|
, compare_(c) {}
|
||||||
|
|
||||||
|
template < typename InputIter >
|
||||||
|
flat_multimap(InputIter first, InputIter last) {
|
||||||
|
insert(first, last);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename InputIter >
|
||||||
|
flat_multimap(InputIter first, InputIter last, const Compare& c)
|
||||||
|
: compare_(c) {
|
||||||
|
insert(first, last);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename InputIter, typename Allocator >
|
||||||
|
flat_multimap(InputIter first, InputIter last, const Allocator& a)
|
||||||
|
: data_(a) {
|
||||||
|
insert(first, last);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename InputIter , typename Allocator >
|
||||||
|
flat_multimap(InputIter first, InputIter last, const Compare& c, const Allocator& a)
|
||||||
|
: data_(a)
|
||||||
|
, compare_(c) {
|
||||||
|
insert(first, last);
|
||||||
|
}
|
||||||
|
|
||||||
|
flat_multimap(std::initializer_list<value_type> ilist) {
|
||||||
|
insert(ilist);
|
||||||
|
}
|
||||||
|
|
||||||
|
flat_multimap(std::initializer_list<value_type> ilist, const Compare& c)
|
||||||
|
: compare_(c) {
|
||||||
|
insert(ilist);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename Allocator >
|
||||||
|
flat_multimap(std::initializer_list<value_type> ilist, const Allocator& a)
|
||||||
|
: data_(a) {
|
||||||
|
insert(ilist);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename Allocator >
|
||||||
|
flat_multimap(std::initializer_list<value_type> ilist, const Compare& c, const Allocator& a)
|
||||||
|
: data_(a)
|
||||||
|
, compare_(c) {
|
||||||
|
insert(ilist);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename Allocator >
|
||||||
|
flat_multimap(flat_multimap&& other, const Allocator& a)
|
||||||
|
: data_(std::move(other.data_), a)
|
||||||
|
, compare_(std::move(other.compare_)) {}
|
||||||
|
|
||||||
|
template < typename Allocator >
|
||||||
|
flat_multimap(const flat_multimap& other, const Allocator& a)
|
||||||
|
: data_(other.data_, a)
|
||||||
|
, compare_(other.compare_) {}
|
||||||
|
|
||||||
|
flat_multimap(flat_multimap&& other) = default;
|
||||||
|
flat_multimap(const flat_multimap& other) = default;
|
||||||
|
|
||||||
|
flat_multimap& operator=(flat_multimap&& other) = default;
|
||||||
|
flat_multimap& operator=(const flat_multimap& other) = default;
|
||||||
|
|
||||||
|
flat_multimap& operator=(std::initializer_list<value_type> ilist) {
|
||||||
|
flat_multimap(ilist).swap(*this);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator begin() noexcept { return data_.begin(); }
|
||||||
|
const_iterator begin() const noexcept { return data_.begin(); }
|
||||||
|
const_iterator cbegin() const noexcept { return data_.cbegin(); }
|
||||||
|
|
||||||
|
iterator end() noexcept { return data_.end(); }
|
||||||
|
const_iterator end() const noexcept { return data_.end(); }
|
||||||
|
const_iterator cend() const noexcept { return data_.cend(); }
|
||||||
|
|
||||||
|
reverse_iterator rbegin() noexcept { return data_.rbegin(); }
|
||||||
|
const_reverse_iterator rbegin() const noexcept { return data_.rbegin(); }
|
||||||
|
const_reverse_iterator crbegin() const noexcept { return data_.crbegin(); }
|
||||||
|
|
||||||
|
reverse_iterator rend() noexcept { return data_.rend(); }
|
||||||
|
const_reverse_iterator rend() const noexcept { return data_.rend(); }
|
||||||
|
const_reverse_iterator crend() const noexcept { return data_.crend(); }
|
||||||
|
|
||||||
|
bool empty() const noexcept {
|
||||||
|
return data_.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_type size() const noexcept {
|
||||||
|
return data_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_type max_size() const noexcept {
|
||||||
|
return data_.max_size();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_type capacity() const noexcept {
|
||||||
|
return data_.capacity();
|
||||||
|
}
|
||||||
|
|
||||||
|
void reserve(size_type ncapacity) {
|
||||||
|
data_.reserve(ncapacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
void shrink_to_fit() {
|
||||||
|
data_.shrink_to_fit();
|
||||||
|
}
|
||||||
|
|
||||||
|
mapped_type& operator[](key_type&& key) {
|
||||||
|
const iterator iter = find(key);
|
||||||
|
return iter != end()
|
||||||
|
? iter->second
|
||||||
|
: emplace(std::move(key), mapped_type())->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
mapped_type& operator[](const key_type& key) {
|
||||||
|
const iterator iter = find(key);
|
||||||
|
return iter != end()
|
||||||
|
? iter->second
|
||||||
|
: emplace(key, mapped_type())->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
mapped_type& at(const key_type& key) {
|
||||||
|
const iterator iter = find(key);
|
||||||
|
if ( iter != end() ) {
|
||||||
|
return iter->second;
|
||||||
|
}
|
||||||
|
throw std::out_of_range("flat_multimap::at: key not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapped_type& at(const key_type& 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator insert(const value_type& value) {
|
||||||
|
const iterator iter = upper_bound(value.first);
|
||||||
|
return data_.insert(iter, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator insert(const_iterator hint, value_type&& value) {
|
||||||
|
return (hint == begin() || !compare_(value, *(hint - 1)))
|
||||||
|
&& (hint == end() || !compare_(*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))
|
||||||
|
? data_.insert(hint, value)
|
||||||
|
: insert(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename InputIter >
|
||||||
|
void insert(InputIter first, InputIter last) {
|
||||||
|
while ( first != last ) {
|
||||||
|
insert(*first++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void insert(std::initializer_list<value_type> ilist) {
|
||||||
|
insert(ilist.begin(), ilist.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename... Args >
|
||||||
|
iterator emplace(Args&&... args) {
|
||||||
|
return insert(value_type(std::forward<Args>(args)...));
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename... Args >
|
||||||
|
iterator emplace_hint(const_iterator hint, Args&&... args) {
|
||||||
|
return insert(hint, value_type(std::forward<Args>(args)...));
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() noexcept {
|
||||||
|
data_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator erase(const_iterator iter) {
|
||||||
|
return data_.erase(iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator erase(const_iterator first, const_iterator last) {
|
||||||
|
return data_.erase(first, last);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_type erase(const key_type& 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) {
|
||||||
|
using std::swap;
|
||||||
|
swap(data_, other.data_);
|
||||||
|
swap(compare_, other.compare_);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_type count(const key_type& 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() && !compare_(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)
|
||||||
|
? iter
|
||||||
|
: end();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<iterator, iterator> equal_range(const key_type& key) {
|
||||||
|
return std::equal_range(begin(), end(), key, compare_);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<const_iterator, const_iterator> equal_range(const key_type& key) const {
|
||||||
|
return std::equal_range(begin(), end(), key, compare_);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator lower_bound(const key_type& key) {
|
||||||
|
return std::lower_bound(begin(), end(), key, compare_);
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator lower_bound(const key_type& key) const {
|
||||||
|
return std::lower_bound(begin(), end(), key, compare_);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator upper_bound(const key_type& key) {
|
||||||
|
return std::upper_bound(begin(), end(), key, compare_);
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator upper_bound(const key_type& key) const {
|
||||||
|
return std::upper_bound(begin(), end(), key, compare_);
|
||||||
|
}
|
||||||
|
|
||||||
|
key_compare key_comp() const {
|
||||||
|
return compare_;
|
||||||
|
}
|
||||||
|
|
||||||
|
value_compare value_comp() const {
|
||||||
|
return value_compare(compare_);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
container_type data_;
|
||||||
|
uber_comparer_type compare_;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace flat_hpp
|
||||||
|
{
|
||||||
|
template < typename Key
|
||||||
|
, typename Value
|
||||||
|
, typename Compare
|
||||||
|
, typename Container >
|
||||||
|
void swap(
|
||||||
|
flat_multimap<Key, Value, Compare, Container>& l,
|
||||||
|
flat_multimap<Key, Value, Compare, Container>& r)
|
||||||
|
{
|
||||||
|
l.swap(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename Key
|
||||||
|
, typename Value
|
||||||
|
, typename Compare
|
||||||
|
, typename Container >
|
||||||
|
bool operator==(
|
||||||
|
const flat_multimap<Key, Value, Compare, Container>& l,
|
||||||
|
const flat_multimap<Key, Value, Compare, Container>& r)
|
||||||
|
{
|
||||||
|
return l.size() == r.size()
|
||||||
|
&& std::equal(l.begin(), l.end(), r.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename Key
|
||||||
|
, typename Value
|
||||||
|
, typename Compare
|
||||||
|
, typename Container >
|
||||||
|
bool operator!=(
|
||||||
|
const flat_multimap<Key, Value, Compare, Container>& l,
|
||||||
|
const flat_multimap<Key, Value, Compare, Container>& r)
|
||||||
|
{
|
||||||
|
return !(l == r);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename Key
|
||||||
|
, typename Value
|
||||||
|
, typename Compare
|
||||||
|
, typename Container >
|
||||||
|
bool operator<(
|
||||||
|
const flat_multimap<Key, Value, Compare, Container>& l,
|
||||||
|
const flat_multimap<Key, Value, Compare, Container>& r)
|
||||||
|
{
|
||||||
|
return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename Key
|
||||||
|
, typename Value
|
||||||
|
, typename Compare
|
||||||
|
, typename Container >
|
||||||
|
bool operator>(
|
||||||
|
const flat_multimap<Key, Value, Compare, Container>& l,
|
||||||
|
const flat_multimap<Key, Value, Compare, Container>& r)
|
||||||
|
{
|
||||||
|
return r < l;
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename Key
|
||||||
|
, typename Value
|
||||||
|
, typename Compare
|
||||||
|
, typename Container >
|
||||||
|
bool operator<=(
|
||||||
|
const flat_multimap<Key, Value, Compare, Container>& l,
|
||||||
|
const flat_multimap<Key, Value, Compare, Container>& r)
|
||||||
|
{
|
||||||
|
return !(r < l);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename Key
|
||||||
|
, typename Value
|
||||||
|
, typename Compare
|
||||||
|
, typename Container >
|
||||||
|
bool operator>=(
|
||||||
|
const flat_multimap<Key, Value, Compare, Container>& l,
|
||||||
|
const flat_multimap<Key, Value, Compare, Container>& r)
|
||||||
|
{
|
||||||
|
return !(l < r);
|
||||||
|
}
|
||||||
|
}
|
||||||
364
headers/flat_hpp/flat_multiset.hpp
Normal file
364
headers/flat_hpp/flat_multiset.hpp
Normal file
@@ -0,0 +1,364 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* 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 <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include <utility>
|
||||||
|
#include <iterator>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <functional>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <initializer_list>
|
||||||
|
|
||||||
|
namespace flat_hpp
|
||||||
|
{
|
||||||
|
template < typename Key
|
||||||
|
, typename Compare = std::less<Key>
|
||||||
|
, typename Container = std::vector<Key> >
|
||||||
|
class flat_multiset final {
|
||||||
|
public:
|
||||||
|
using key_type = Key;
|
||||||
|
using value_type = Key;
|
||||||
|
|
||||||
|
using size_type = typename Container::size_type;
|
||||||
|
using difference_type = typename Container::difference_type;
|
||||||
|
|
||||||
|
using key_compare = Compare;
|
||||||
|
using value_compare = Compare;
|
||||||
|
using container_type = Container;
|
||||||
|
|
||||||
|
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 Container::const_iterator;
|
||||||
|
using const_iterator = typename Container::const_iterator;
|
||||||
|
using reverse_iterator = typename Container::const_reverse_iterator;
|
||||||
|
using const_reverse_iterator = typename Container::const_reverse_iterator;
|
||||||
|
public:
|
||||||
|
flat_multiset() {}
|
||||||
|
|
||||||
|
explicit flat_multiset(const Compare& c)
|
||||||
|
: compare_(c) {}
|
||||||
|
|
||||||
|
template < typename Allocator >
|
||||||
|
explicit flat_multiset(const Allocator& a)
|
||||||
|
: data_(a) {}
|
||||||
|
|
||||||
|
template < typename Allocator >
|
||||||
|
flat_multiset(const Compare& c, const Allocator& a)
|
||||||
|
: data_(a)
|
||||||
|
, compare_(c) {}
|
||||||
|
|
||||||
|
template < typename InputIter >
|
||||||
|
flat_multiset(InputIter first, InputIter last) {
|
||||||
|
insert(first, last);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename InputIter >
|
||||||
|
flat_multiset(InputIter first, InputIter last, const Compare& c)
|
||||||
|
: compare_(c) {
|
||||||
|
insert(first, last);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename InputIter, typename Allocator >
|
||||||
|
flat_multiset(InputIter first, InputIter last, const Allocator& a)
|
||||||
|
: data_(a) {
|
||||||
|
insert(first, last);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename InputIter, typename Allocator >
|
||||||
|
flat_multiset(InputIter first, InputIter last, const Compare& c, const Allocator& a)
|
||||||
|
: data_(a)
|
||||||
|
, compare_(c) {
|
||||||
|
insert(first, last);
|
||||||
|
}
|
||||||
|
|
||||||
|
flat_multiset(std::initializer_list<value_type> ilist) {
|
||||||
|
insert(ilist);
|
||||||
|
}
|
||||||
|
|
||||||
|
flat_multiset(std::initializer_list<value_type> ilist, const Compare& c)
|
||||||
|
: compare_(c) {
|
||||||
|
insert(ilist);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename Allocator >
|
||||||
|
flat_multiset(std::initializer_list<value_type> ilist, const Allocator& a)
|
||||||
|
: data_(a) {
|
||||||
|
insert(ilist);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename Allocator >
|
||||||
|
flat_multiset(std::initializer_list<value_type> ilist, const Compare& c, const Allocator& a)
|
||||||
|
: data_(a)
|
||||||
|
, compare_(c) {
|
||||||
|
insert(ilist);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename Allocator >
|
||||||
|
flat_multiset(flat_multiset&& other, const Allocator& a)
|
||||||
|
: data_(std::move(other.data_), a)
|
||||||
|
, compare_(std::move(other.compare_)) {}
|
||||||
|
|
||||||
|
template < typename Allocator >
|
||||||
|
flat_multiset(const flat_multiset& other, const Allocator& a)
|
||||||
|
: data_(other.data_, a)
|
||||||
|
, compare_(other.compare_) {}
|
||||||
|
|
||||||
|
flat_multiset(flat_multiset&& other) = default;
|
||||||
|
flat_multiset(const flat_multiset& other) = default;
|
||||||
|
|
||||||
|
flat_multiset& operator=(flat_multiset&& other) = default;
|
||||||
|
flat_multiset& operator=(const flat_multiset& other) = default;
|
||||||
|
|
||||||
|
flat_multiset& operator=(std::initializer_list<value_type> ilist) {
|
||||||
|
flat_multiset(ilist).swap(*this);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator begin() noexcept { return data_.begin(); }
|
||||||
|
const_iterator begin() const noexcept { return data_.begin(); }
|
||||||
|
const_iterator cbegin() const noexcept { return data_.cbegin(); }
|
||||||
|
|
||||||
|
iterator end() noexcept { return data_.end(); }
|
||||||
|
const_iterator end() const noexcept { return data_.end(); }
|
||||||
|
const_iterator cend() const noexcept { return data_.cend(); }
|
||||||
|
|
||||||
|
reverse_iterator rbegin() noexcept { return data_.rbegin(); }
|
||||||
|
const_reverse_iterator rbegin() const noexcept { return data_.rbegin(); }
|
||||||
|
const_reverse_iterator crbegin() const noexcept { return data_.crbegin(); }
|
||||||
|
|
||||||
|
reverse_iterator rend() noexcept { return data_.rend(); }
|
||||||
|
const_reverse_iterator rend() const noexcept { return data_.rend(); }
|
||||||
|
const_reverse_iterator crend() const noexcept { return data_.crend(); }
|
||||||
|
|
||||||
|
bool empty() const noexcept {
|
||||||
|
return data_.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_type size() const noexcept {
|
||||||
|
return data_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_type max_size() const noexcept {
|
||||||
|
return data_.max_size();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_type capacity() const noexcept {
|
||||||
|
return data_.capacity();
|
||||||
|
}
|
||||||
|
|
||||||
|
void reserve(size_type ncapacity) {
|
||||||
|
data_.reserve(ncapacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
void shrink_to_fit() {
|
||||||
|
data_.shrink_to_fit();
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator insert(value_type&& value) {
|
||||||
|
const iterator iter = upper_bound(value);
|
||||||
|
return data_.insert(iter, std::move(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator insert(const value_type& value) {
|
||||||
|
const iterator iter = upper_bound(value);
|
||||||
|
return data_.insert(iter, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator insert(const_iterator hint, value_type&& value) {
|
||||||
|
return (hint == begin() || !compare_(value, *(hint - 1)))
|
||||||
|
&& (hint == end() || !compare_(*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))
|
||||||
|
? data_.insert(hint, value)
|
||||||
|
: insert(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename InputIter >
|
||||||
|
void insert(InputIter first, InputIter last) {
|
||||||
|
while ( first != last ) {
|
||||||
|
insert(*first++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void insert(std::initializer_list<value_type> ilist) {
|
||||||
|
insert(ilist.begin(), ilist.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename... Args >
|
||||||
|
iterator emplace(Args&&... args) {
|
||||||
|
return insert(value_type(std::forward<Args>(args)...));
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename... Args >
|
||||||
|
iterator emplace_hint(const_iterator hint, Args&&... args) {
|
||||||
|
return insert(hint, value_type(std::forward<Args>(args)...));
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() noexcept {
|
||||||
|
data_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator erase(const_iterator iter) {
|
||||||
|
return data_.erase(iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator erase(const_iterator first, const_iterator last) {
|
||||||
|
return data_.erase(first, last);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_type erase(const key_type& 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) {
|
||||||
|
using std::swap;
|
||||||
|
swap(data_, other.data_);
|
||||||
|
swap(compare_, other.compare_);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_type count(const key_type& 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() && !compare_(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)
|
||||||
|
? iter
|
||||||
|
: end();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<iterator, iterator> equal_range(const key_type& key) {
|
||||||
|
return std::equal_range(begin(), end(), key, compare_);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<const_iterator, const_iterator> equal_range(const key_type& key) const {
|
||||||
|
return std::equal_range(begin(), end(), key, compare_);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator lower_bound(const key_type& key) {
|
||||||
|
return std::lower_bound(begin(), end(), key, compare_);
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator lower_bound(const key_type& key) const {
|
||||||
|
return std::lower_bound(begin(), end(), key, compare_);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator upper_bound(const key_type& key) {
|
||||||
|
return std::upper_bound(begin(), end(), key, compare_);
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator upper_bound(const key_type& key) const {
|
||||||
|
return std::upper_bound(begin(), end(), key, compare_);
|
||||||
|
}
|
||||||
|
|
||||||
|
key_compare key_comp() const {
|
||||||
|
return compare_;
|
||||||
|
}
|
||||||
|
|
||||||
|
value_compare value_comp() const {
|
||||||
|
return value_compare(compare_);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
container_type data_;
|
||||||
|
Compare compare_;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace flat_hpp
|
||||||
|
{
|
||||||
|
template < typename Key
|
||||||
|
, typename Compare
|
||||||
|
, typename Container >
|
||||||
|
void swap(
|
||||||
|
flat_multiset<Key, Compare, Container>& l,
|
||||||
|
flat_multiset<Key, Compare, Container>& r)
|
||||||
|
{
|
||||||
|
l.swap(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename Key
|
||||||
|
, typename Compare
|
||||||
|
, typename Container >
|
||||||
|
bool operator==(
|
||||||
|
const flat_multiset<Key, Compare, Container>& l,
|
||||||
|
const flat_multiset<Key, Compare, Container>& r)
|
||||||
|
{
|
||||||
|
return l.size() == r.size()
|
||||||
|
&& std::equal(l.begin(), l.end(), r.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename Key
|
||||||
|
, typename Compare
|
||||||
|
, typename Container >
|
||||||
|
bool operator!=(
|
||||||
|
const flat_multiset<Key, Compare, Container>& l,
|
||||||
|
const flat_multiset<Key, Compare, Container>& r)
|
||||||
|
{
|
||||||
|
return !(l == r);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename Key
|
||||||
|
, typename Compare
|
||||||
|
, typename Container >
|
||||||
|
bool operator<(
|
||||||
|
const flat_multiset<Key, Compare, Container>& l,
|
||||||
|
const flat_multiset<Key, Compare, Container>& r)
|
||||||
|
{
|
||||||
|
return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename Key
|
||||||
|
, typename Compare
|
||||||
|
, typename Container >
|
||||||
|
bool operator>(
|
||||||
|
const flat_multiset<Key, Compare, Container>& l,
|
||||||
|
const flat_multiset<Key, Compare, Container>& r)
|
||||||
|
{
|
||||||
|
return r < l;
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename Key
|
||||||
|
, typename Compare
|
||||||
|
, typename Container >
|
||||||
|
bool operator<=(
|
||||||
|
const flat_multiset<Key, Compare, Container>& l,
|
||||||
|
const flat_multiset<Key, Compare, Container>& r)
|
||||||
|
{
|
||||||
|
return !(r < l);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename Key
|
||||||
|
, typename Compare
|
||||||
|
, typename Container >
|
||||||
|
bool operator>=(
|
||||||
|
const flat_multiset<Key, Compare, Container>& l,
|
||||||
|
const flat_multiset<Key, Compare, Container>& r)
|
||||||
|
{
|
||||||
|
return !(l < r);
|
||||||
|
}
|
||||||
|
}
|
||||||
463
untests/flat_multimap_tests.cpp
Normal file
463
untests/flat_multimap_tests.cpp
Normal file
@@ -0,0 +1,463 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* 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)
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#define CATCH_CONFIG_FAST_COMPILE
|
||||||
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
|
#include <flat_hpp/flat_multimap.hpp>
|
||||||
|
using namespace flat_hpp;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
template < typename T >
|
||||||
|
class dummy_allocator {
|
||||||
|
public:
|
||||||
|
using size_type = std::size_t;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using pointer = T*;
|
||||||
|
using const_pointer = const T*;
|
||||||
|
using reference = T&;
|
||||||
|
using const_reference = const T&;
|
||||||
|
using value_type = T;
|
||||||
|
|
||||||
|
using propagate_on_container_move_assignment = std::true_type;
|
||||||
|
using is_always_equal = std::true_type;
|
||||||
|
|
||||||
|
template < typename U >
|
||||||
|
struct rebind { using other = dummy_allocator<U>; };
|
||||||
|
|
||||||
|
dummy_allocator() = default;
|
||||||
|
dummy_allocator(int i) : i(i) {}
|
||||||
|
|
||||||
|
template < typename U >
|
||||||
|
dummy_allocator(const dummy_allocator<U>& o) noexcept {
|
||||||
|
i = o.i;
|
||||||
|
}
|
||||||
|
|
||||||
|
T* allocate(std::size_t n) noexcept {
|
||||||
|
return static_cast<T*>(std::malloc(sizeof(T) * n));
|
||||||
|
}
|
||||||
|
|
||||||
|
void deallocate(T* p, std::size_t n) noexcept {
|
||||||
|
(void)n;
|
||||||
|
std::free(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename U, typename... Args >
|
||||||
|
void construct(U* p, Args&&... args) {
|
||||||
|
::new((void*)p) U(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy(pointer p) {
|
||||||
|
p->~T();
|
||||||
|
}
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template < typename T, typename U >
|
||||||
|
bool operator==(const dummy_allocator<T>&, const dummy_allocator<U>&) noexcept {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T, typename U >
|
||||||
|
bool operator!=(const dummy_allocator<T>& l, const dummy_allocator<U>& r) noexcept {
|
||||||
|
return !(l == r);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
constexpr std::add_const_t<T>& my_as_const(T& t) noexcept {
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("flat_multimap") {
|
||||||
|
SECTION("types") {
|
||||||
|
using map_t = flat_multimap<int, unsigned>;
|
||||||
|
|
||||||
|
static_assert(
|
||||||
|
std::is_same<map_t::key_type, int>::value,
|
||||||
|
"unit test static error");
|
||||||
|
static_assert(
|
||||||
|
std::is_same<map_t::mapped_type, unsigned>::value,
|
||||||
|
"unit test static error");
|
||||||
|
static_assert(
|
||||||
|
std::is_same<map_t::value_type, std::pair<int, unsigned>>::value,
|
||||||
|
"unit test static error");
|
||||||
|
|
||||||
|
static_assert(
|
||||||
|
std::is_same<map_t::size_type, std::size_t>::value,
|
||||||
|
"unit test static error");
|
||||||
|
static_assert(
|
||||||
|
std::is_same<map_t::difference_type, std::ptrdiff_t>::value,
|
||||||
|
"unit test static error");
|
||||||
|
|
||||||
|
static_assert(
|
||||||
|
std::is_same<map_t::reference, std::pair<int, unsigned>&>::value,
|
||||||
|
"unit test static error");
|
||||||
|
static_assert(
|
||||||
|
std::is_same<map_t::const_reference, const std::pair<int, unsigned>&>::value,
|
||||||
|
"unit test static error");
|
||||||
|
|
||||||
|
static_assert(
|
||||||
|
std::is_same<map_t::pointer, std::pair<int, unsigned>*>::value,
|
||||||
|
"unit test static error");
|
||||||
|
static_assert(
|
||||||
|
std::is_same<map_t::const_pointer, const std::pair<int, unsigned>*>::value,
|
||||||
|
"unit test static error");
|
||||||
|
}
|
||||||
|
SECTION("ctors") {
|
||||||
|
using alloc_t = dummy_allocator<
|
||||||
|
std::pair<int,unsigned>>;
|
||||||
|
|
||||||
|
using map_t = flat_multimap<
|
||||||
|
int,
|
||||||
|
unsigned,
|
||||||
|
std::less<int>,
|
||||||
|
std::vector<std::pair<int,unsigned>, alloc_t>>;
|
||||||
|
|
||||||
|
using map2_t = flat_multimap<
|
||||||
|
int,
|
||||||
|
unsigned,
|
||||||
|
std::greater<int>,
|
||||||
|
std::vector<std::pair<int,unsigned>, alloc_t>>;
|
||||||
|
|
||||||
|
using vec_t = std::vector<
|
||||||
|
std::pair<int,unsigned>, alloc_t>;
|
||||||
|
|
||||||
|
{
|
||||||
|
auto s0 = map_t();
|
||||||
|
auto s1 = map2_t(alloc_t());
|
||||||
|
auto s2 = map_t(std::less<int>());
|
||||||
|
auto s3 = map2_t(std::greater<int>(), alloc_t());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
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());
|
||||||
|
auto s2 = map_t(v.cbegin(), v.cend(), std::less<int>());
|
||||||
|
auto s3 = map2_t(v.cbegin(), v.cend(), std::greater<int>(), alloc_t());
|
||||||
|
|
||||||
|
REQUIRE(vec_t(s0.begin(), s0.end()) == vec_t({{1,30},{2,20},{3,10}}));
|
||||||
|
REQUIRE(vec_t(s1.begin(), s1.end()) == vec_t({{3,10},{2,20},{1,30}}));
|
||||||
|
REQUIRE(vec_t(s2.begin(), s2.end()) == vec_t({{1,30},{2,20},{3,10}}));
|
||||||
|
REQUIRE(vec_t(s3.begin(), s3.end()) == vec_t({{3,10},{2,20},{1,30}}));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto s0 = map_t({{0,1}, {1,2}});
|
||||||
|
auto s1 = map_t({{0,1}, {1,2}}, alloc_t());
|
||||||
|
auto s2 = map_t({{0,1}, {1,2}}, std::less<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{{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 s3 = map_t(s2, alloc_t(42));
|
||||||
|
REQUIRE(s2 == s3);
|
||||||
|
auto s4 = map_t(std::move(s3), alloc_t(21));
|
||||||
|
REQUIRE(s3.empty());
|
||||||
|
REQUIRE(s4 == 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") {
|
||||||
|
using map_t = flat_multimap<int, unsigned>;
|
||||||
|
|
||||||
|
{
|
||||||
|
map_t s0;
|
||||||
|
|
||||||
|
REQUIRE(s0.empty());
|
||||||
|
REQUIRE_FALSE(s0.size());
|
||||||
|
REQUIRE(s0.max_size() == std::allocator<std::pair<int,unsigned>>().max_size());
|
||||||
|
|
||||||
|
s0.insert({2,42});
|
||||||
|
|
||||||
|
REQUIRE_FALSE(s0.empty());
|
||||||
|
REQUIRE(s0.size() == 1u);
|
||||||
|
REQUIRE(s0.max_size() == std::allocator<std::pair<int,unsigned>>().max_size());
|
||||||
|
|
||||||
|
s0.insert({2,84});
|
||||||
|
REQUIRE(s0.size() == 2u);
|
||||||
|
|
||||||
|
s0.insert({3,84});
|
||||||
|
REQUIRE(s0.size() == 3u);
|
||||||
|
|
||||||
|
s0.clear();
|
||||||
|
|
||||||
|
REQUIRE(s0.empty());
|
||||||
|
REQUIRE_FALSE(s0.size());
|
||||||
|
REQUIRE(s0.max_size() == std::allocator<std::pair<int,unsigned>>().max_size());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
map_t s0;
|
||||||
|
|
||||||
|
REQUIRE(s0.capacity() == 0);
|
||||||
|
s0.reserve(42);
|
||||||
|
REQUIRE(s0.capacity() == 42);
|
||||||
|
s0.insert({{1,2},{2,3},{3,4}});
|
||||||
|
REQUIRE(s0.capacity() == 42);
|
||||||
|
s0.shrink_to_fit();
|
||||||
|
REQUIRE(s0.size() == 3);
|
||||||
|
REQUIRE(s0.capacity() == 3);
|
||||||
|
REQUIRE(s0 == map_t{{1,2},{2,3},{3,4}});
|
||||||
|
|
||||||
|
using alloc2_t = dummy_allocator<
|
||||||
|
std::pair<int, unsigned>>;
|
||||||
|
|
||||||
|
using map2_t = flat_multimap<
|
||||||
|
int,
|
||||||
|
unsigned,
|
||||||
|
std::less<int>,
|
||||||
|
std::deque<std::pair<int, unsigned>, alloc2_t>>;
|
||||||
|
|
||||||
|
map2_t s1;
|
||||||
|
s1.insert({{1,2},{2,3},{3,4}});
|
||||||
|
REQUIRE(s1 == map2_t{{1,2},{2,3},{3,4}});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SECTION("access") {
|
||||||
|
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_multimap<obj_t, unsigned>;
|
||||||
|
map_t s0;
|
||||||
|
|
||||||
|
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}});
|
||||||
|
|
||||||
|
s0[2] = 21;
|
||||||
|
REQUIRE(s0[2] == 21);
|
||||||
|
REQUIRE(s0 == map_t{{1,84},{2,21}});
|
||||||
|
|
||||||
|
REQUIRE(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);
|
||||||
|
}
|
||||||
|
SECTION("inserts") {
|
||||||
|
struct obj_t {
|
||||||
|
obj_t(int i) : i(i) {}
|
||||||
|
int i;
|
||||||
|
|
||||||
|
bool operator<(const obj_t& o) const {
|
||||||
|
return i < o.i;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const obj_t& o) const {
|
||||||
|
return i == o.i;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using map_t = flat_multimap<obj_t, obj_t>;
|
||||||
|
|
||||||
|
{
|
||||||
|
map_t s0;
|
||||||
|
|
||||||
|
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 == s0.begin());
|
||||||
|
|
||||||
|
auto i1 = s0.insert(std::make_pair(1, obj_t(21)));
|
||||||
|
REQUIRE(s0 == map_t{{1,42},{1,21}});
|
||||||
|
REQUIRE(i1 == s0.begin() + 1);
|
||||||
|
|
||||||
|
auto i2 = s0.insert(std::make_pair(2, obj_t(42)));
|
||||||
|
REQUIRE(s0 == map_t{{1,42},{1,21},{2,42}});
|
||||||
|
REQUIRE(i2 == s0.begin() + 2);
|
||||||
|
|
||||||
|
auto i3 = s0.insert(s0.cend(), k3_84);
|
||||||
|
REQUIRE(i3 == s0.begin() + 3);
|
||||||
|
|
||||||
|
s0.insert(s0.cend(), std::make_pair(4, obj_t(84)));
|
||||||
|
auto i4 = s0.insert(s0.cend(), std::make_pair(0, obj_t(21)));
|
||||||
|
REQUIRE(i4 == s0.begin());
|
||||||
|
|
||||||
|
auto i5 = s0.emplace(5, 100500);
|
||||||
|
REQUIRE(i5 == s0.end() - 1);
|
||||||
|
REQUIRE(s0 == map_t{{0,21},{1,42},{1,21},{2,42},{3,84},{4,84},{5,100500}});
|
||||||
|
|
||||||
|
auto i6 = s0.emplace_hint(s0.cend(), 6, 100500);
|
||||||
|
REQUIRE(i6 == s0.end() - 1);
|
||||||
|
REQUIRE(s0 == map_t{{0,21},{1,42},{1,21},{2,42},{3,84},{4,84},{5,100500},{6,100500}});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SECTION("erasers") {
|
||||||
|
using map_t = flat_multimap<int, unsigned>;
|
||||||
|
{
|
||||||
|
map_t s0{{1,2},{2,3},{3,4}};
|
||||||
|
s0.clear();
|
||||||
|
REQUIRE(s0.empty());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
map_t s0{{1,2},{2,3},{3,4}};
|
||||||
|
auto i = s0.erase(s0.find(2));
|
||||||
|
REQUIRE(i == s0.begin() + 1);
|
||||||
|
REQUIRE(s0 == map_t{{1,2},{3,4}});
|
||||||
|
}
|
||||||
|
{
|
||||||
|
map_t s0{{1,2},{2,3},{3,4}};
|
||||||
|
auto i = s0.erase(s0.begin() + 1, s0.end());
|
||||||
|
REQUIRE(i == s0.end());
|
||||||
|
REQUIRE(s0 == map_t{{1,2}});
|
||||||
|
}
|
||||||
|
{
|
||||||
|
map_t s0{{1,2},{2,3},{2,1},{3,4}};
|
||||||
|
REQUIRE(s0.erase(1) == 1);
|
||||||
|
REQUIRE(s0.erase(2) == 2);
|
||||||
|
REQUIRE(s0.erase(6) == 0);
|
||||||
|
REQUIRE(s0 == map_t{{3,4}});
|
||||||
|
}
|
||||||
|
{
|
||||||
|
map_t s0{{1,2},{2,3},{3,4}};
|
||||||
|
map_t s1{{2,3},{3,4},{5,6}};
|
||||||
|
s0.swap(s1);
|
||||||
|
REQUIRE(s0 == map_t{{2,3},{3,4},{5,6}});
|
||||||
|
REQUIRE(s1 == map_t{{1,2},{2,3},{3,4}});
|
||||||
|
swap(s1, s0);
|
||||||
|
REQUIRE(s0 == map_t{{1,2},{2,3},{3,4}});
|
||||||
|
REQUIRE(s1 == map_t{{2,3},{3,4},{5,6}});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SECTION("lookup") {
|
||||||
|
using map_t = flat_multimap<int, unsigned>;
|
||||||
|
{
|
||||||
|
map_t s0{{1,2},{2,3},{2,1},{3,4},{4,5},{5,6}};
|
||||||
|
REQUIRE(s0.count(3) == 1);
|
||||||
|
REQUIRE(s0.count(2) == 2);
|
||||||
|
REQUIRE_FALSE(s0.count(6));
|
||||||
|
REQUIRE(my_as_const(s0).count(5));
|
||||||
|
REQUIRE_FALSE(my_as_const(s0).count(0));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
map_t s0{{1,2},{2,3},{3,4},{4,5},{5,6}};
|
||||||
|
REQUIRE(s0.find(2) == s0.begin() + 1);
|
||||||
|
REQUIRE(my_as_const(s0).find(3) == s0.cbegin() + 2);
|
||||||
|
REQUIRE(s0.find(6) == s0.end());
|
||||||
|
REQUIRE(my_as_const(s0).find(0) == s0.cend());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
map_t s0{{1,2},{2,3},{2,1},{3,4},{4,5},{5,6}};
|
||||||
|
REQUIRE(s0.equal_range(2) == std::make_pair(s0.begin() + 1, s0.begin() + 3));
|
||||||
|
REQUIRE(s0.equal_range(6) == std::make_pair(s0.end(), s0.end()));
|
||||||
|
REQUIRE(my_as_const(s0).equal_range(2) == std::make_pair(s0.cbegin() + 1, s0.cbegin() + 3));
|
||||||
|
REQUIRE(my_as_const(s0).equal_range(0) == std::make_pair(s0.cbegin(), s0.cbegin()));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
map_t s0{{0,1},{0,0},{3,2},{6,3}};
|
||||||
|
REQUIRE(s0.lower_bound(0) == s0.begin());
|
||||||
|
REQUIRE(s0.lower_bound(1) == s0.begin() + 2);
|
||||||
|
REQUIRE(s0.lower_bound(10) == s0.end());
|
||||||
|
REQUIRE(my_as_const(s0).lower_bound(-1) == s0.cbegin());
|
||||||
|
REQUIRE(my_as_const(s0).lower_bound(7) == s0.cbegin() + 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SECTION("observers") {
|
||||||
|
struct my_less {
|
||||||
|
int i;
|
||||||
|
my_less(int i) : i(i) {}
|
||||||
|
bool operator()(int l, int r) const {
|
||||||
|
return l < r;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
using map_t = flat_multimap<int, unsigned, my_less>;
|
||||||
|
map_t s0(my_less(42));
|
||||||
|
REQUIRE(my_as_const(s0).key_comp().i == 42);
|
||||||
|
REQUIRE(my_as_const(s0).value_comp()({2,50},{4,20}));
|
||||||
|
}
|
||||||
|
SECTION("operators") {
|
||||||
|
using map_t = flat_multimap<int, unsigned>;
|
||||||
|
|
||||||
|
REQUIRE(map_t{{1,2},{3,4}} == map_t{{3,4},{1,2}});
|
||||||
|
REQUIRE_FALSE(map_t{{1,2},{3,4}} == map_t{{2,4},{1,2}});
|
||||||
|
REQUIRE_FALSE(map_t{{1,2},{3,4}} == map_t{{1,3},{1,2}});
|
||||||
|
REQUIRE_FALSE(map_t{{1,2},{3,4}} == map_t{{3,4},{1,2},{0,0}});
|
||||||
|
|
||||||
|
REQUIRE_FALSE(map_t{{1,2},{3,4}} != map_t{{3,4},{1,2}});
|
||||||
|
REQUIRE(map_t{{1,2},{3,4}} != map_t{{2,4},{1,2}});
|
||||||
|
REQUIRE(map_t{{1,2},{3,4}} != map_t{{1,3},{1,2}});
|
||||||
|
REQUIRE(map_t{{1,2},{3,4}} != map_t{{3,4},{1,2},{0,0}});
|
||||||
|
|
||||||
|
REQUIRE(map_t{{0,2},{3,4}} < map_t{{1,2},{3,4}});
|
||||||
|
REQUIRE(map_t{{1,1},{3,4}} < map_t{{1,2},{3,4}});
|
||||||
|
REQUIRE(map_t{{1,2},{3,4}} < map_t{{1,2},{3,4},{5,6}});
|
||||||
|
|
||||||
|
REQUIRE(map_t{{0,2},{3,4}} <= map_t{{1,2},{3,4}});
|
||||||
|
REQUIRE(map_t{{1,1},{3,4}} <= map_t{{1,2},{3,4}});
|
||||||
|
REQUIRE(map_t{{1,2},{3,4}} <= map_t{{1,2},{3,4},{5,6}});
|
||||||
|
|
||||||
|
REQUIRE(map_t{{1,2},{3,4}} > map_t{{0,2},{3,4}});
|
||||||
|
REQUIRE(map_t{{1,2},{3,4}} > map_t{{1,1},{3,4}});
|
||||||
|
REQUIRE(map_t{{1,2},{3,4},{5,6}} > map_t{{1,2},{3,4}});
|
||||||
|
|
||||||
|
REQUIRE(map_t{{1,2},{3,4}} >= map_t{{0,2},{3,4}});
|
||||||
|
REQUIRE(map_t{{1,2},{3,4}} >= map_t{{1,1},{3,4}});
|
||||||
|
REQUIRE(map_t{{1,2},{3,4},{5,6}} >= map_t{{1,2},{3,4}});
|
||||||
|
|
||||||
|
REQUIRE_FALSE(map_t{{1,2},{3,4}} < map_t{{1,2},{3,4}});
|
||||||
|
REQUIRE(map_t{{1,2},{3,4}} <= map_t{{1,2},{3,4}});
|
||||||
|
REQUIRE_FALSE(map_t{{1,2},{3,4}} > map_t{{1,2},{3,4}});
|
||||||
|
REQUIRE(map_t{{1,2},{3,4}} >= map_t{{1,2},{3,4}});
|
||||||
|
|
||||||
|
const map_t s0;
|
||||||
|
REQUIRE(s0 == s0);
|
||||||
|
REQUIRE_FALSE(s0 != s0);
|
||||||
|
REQUIRE_FALSE(s0 < s0);
|
||||||
|
REQUIRE_FALSE(s0 > s0);
|
||||||
|
REQUIRE(s0 <= s0);
|
||||||
|
REQUIRE(s0 >= s0);
|
||||||
|
}
|
||||||
|
}
|
||||||
428
untests/flat_multiset_tests.cpp
Normal file
428
untests/flat_multiset_tests.cpp
Normal file
@@ -0,0 +1,428 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* 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)
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#define CATCH_CONFIG_FAST_COMPILE
|
||||||
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
|
#include <flat_hpp/flat_multiset.hpp>
|
||||||
|
using namespace flat_hpp;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
template < typename T >
|
||||||
|
class dummy_allocator {
|
||||||
|
public:
|
||||||
|
using size_type = std::size_t;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using pointer = T*;
|
||||||
|
using const_pointer = const T*;
|
||||||
|
using reference = T&;
|
||||||
|
using const_reference = const T&;
|
||||||
|
using value_type = T;
|
||||||
|
|
||||||
|
using propagate_on_container_move_assignment = std::true_type;
|
||||||
|
using is_always_equal = std::true_type;
|
||||||
|
|
||||||
|
template < typename U >
|
||||||
|
struct rebind { using other = dummy_allocator<U>; };
|
||||||
|
|
||||||
|
dummy_allocator() = default;
|
||||||
|
dummy_allocator(int i) : i(i) {}
|
||||||
|
|
||||||
|
template < typename U >
|
||||||
|
dummy_allocator(const dummy_allocator<U>& o) noexcept {
|
||||||
|
i = o.i;
|
||||||
|
}
|
||||||
|
|
||||||
|
T* allocate(std::size_t n) noexcept {
|
||||||
|
return static_cast<T*>(std::malloc(sizeof(T) * n));
|
||||||
|
}
|
||||||
|
|
||||||
|
void deallocate(T* p, std::size_t n) noexcept {
|
||||||
|
(void)n;
|
||||||
|
std::free(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename U, typename... Args >
|
||||||
|
void construct(U* p, Args&&... args) {
|
||||||
|
::new((void*)p) U(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy(pointer p) {
|
||||||
|
p->~T();
|
||||||
|
}
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template < typename T, typename U >
|
||||||
|
bool operator==(const dummy_allocator<T>&, const dummy_allocator<U>&) noexcept {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T, typename U >
|
||||||
|
bool operator!=(const dummy_allocator<T>& l, const dummy_allocator<U>& r) noexcept {
|
||||||
|
return !(l == r);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
constexpr std::add_const_t<T>& my_as_const(T& t) noexcept {
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("flat_multiset") {
|
||||||
|
SECTION("types") {
|
||||||
|
using set_t = flat_multiset<int>;
|
||||||
|
|
||||||
|
static_assert(
|
||||||
|
std::is_same<set_t::key_type, int>::value,
|
||||||
|
"unit test static error");
|
||||||
|
static_assert(
|
||||||
|
std::is_same<set_t::value_type, int>::value,
|
||||||
|
"unit test static error");
|
||||||
|
|
||||||
|
static_assert(
|
||||||
|
std::is_same<set_t::size_type, std::size_t>::value,
|
||||||
|
"unit test static error");
|
||||||
|
static_assert(
|
||||||
|
std::is_same<set_t::difference_type, std::ptrdiff_t>::value,
|
||||||
|
"unit test static error");
|
||||||
|
|
||||||
|
static_assert(
|
||||||
|
std::is_same<set_t::reference, int&>::value,
|
||||||
|
"unit test static error");
|
||||||
|
static_assert(
|
||||||
|
std::is_same<set_t::const_reference, const int&>::value,
|
||||||
|
"unit test static error");
|
||||||
|
|
||||||
|
static_assert(
|
||||||
|
std::is_same<set_t::pointer, int*>::value,
|
||||||
|
"unit test static error");
|
||||||
|
static_assert(
|
||||||
|
std::is_same<set_t::const_pointer, const int*>::value,
|
||||||
|
"unit test static error");
|
||||||
|
}
|
||||||
|
SECTION("ctors") {
|
||||||
|
using alloc_t = dummy_allocator<int>;
|
||||||
|
using set_t = flat_multiset<int, std::less<int>, std::vector<int, alloc_t>>;
|
||||||
|
using set2_t = flat_multiset<int, std::greater<int>, std::vector<int, alloc_t>>;
|
||||||
|
using vec_t = std::vector<int>;
|
||||||
|
|
||||||
|
{
|
||||||
|
auto s0 = set_t();
|
||||||
|
auto s1 = set2_t(alloc_t());
|
||||||
|
auto s2 = set_t(std::less<int>());
|
||||||
|
auto s3 = set2_t(std::greater<int>(), alloc_t());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
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(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}));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto s0 = set_t({0,1,2});
|
||||||
|
auto s1 = set2_t({0,1,2}, alloc_t());
|
||||||
|
auto s2 = set_t({0,1,2}, std::less<int>());
|
||||||
|
auto s3 = set2_t({0,1,2}, std::greater<int>(), alloc_t());
|
||||||
|
|
||||||
|
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{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 s3 = set_t(s2, alloc_t(42));
|
||||||
|
REQUIRE(s2 == s3);
|
||||||
|
auto s4 = set_t(std::move(s3), alloc_t(21));
|
||||||
|
REQUIRE(s3.empty());
|
||||||
|
REQUIRE(s4 == 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") {
|
||||||
|
using set_t = flat_multiset<int>;
|
||||||
|
|
||||||
|
{
|
||||||
|
set_t s0;
|
||||||
|
|
||||||
|
REQUIRE(s0.empty());
|
||||||
|
REQUIRE_FALSE(s0.size());
|
||||||
|
REQUIRE(s0.max_size() == std::allocator<int>().max_size());
|
||||||
|
|
||||||
|
s0.insert(42);
|
||||||
|
|
||||||
|
REQUIRE_FALSE(s0.empty());
|
||||||
|
REQUIRE(s0.size() == 1u);
|
||||||
|
REQUIRE(s0.max_size() == std::allocator<int>().max_size());
|
||||||
|
|
||||||
|
s0.insert(42);
|
||||||
|
REQUIRE(s0.size() == 2u);
|
||||||
|
|
||||||
|
s0.insert(84);
|
||||||
|
REQUIRE(s0.size() == 3u);
|
||||||
|
|
||||||
|
s0.clear();
|
||||||
|
|
||||||
|
REQUIRE(s0.empty());
|
||||||
|
REQUIRE_FALSE(s0.size());
|
||||||
|
REQUIRE(s0.max_size() == std::allocator<int>().max_size());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
set_t s0;
|
||||||
|
|
||||||
|
REQUIRE(s0.capacity() == 0);
|
||||||
|
s0.reserve(42);
|
||||||
|
REQUIRE(s0.capacity() == 42);
|
||||||
|
s0.insert({1,2,3});
|
||||||
|
REQUIRE(s0.capacity() == 42);
|
||||||
|
s0.shrink_to_fit();
|
||||||
|
REQUIRE(s0.size() == 3);
|
||||||
|
REQUIRE(s0.capacity() == 3);
|
||||||
|
REQUIRE(s0 == set_t{1,2,3});
|
||||||
|
|
||||||
|
using alloc2_t = dummy_allocator<int>;
|
||||||
|
|
||||||
|
using set2_t = flat_multiset<
|
||||||
|
int,
|
||||||
|
std::less<int>,
|
||||||
|
std::deque<int, alloc2_t>>;
|
||||||
|
|
||||||
|
set2_t s1;
|
||||||
|
s1.insert({1,2,3});
|
||||||
|
REQUIRE(s1 == set2_t{1,2,3});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SECTION("inserts") {
|
||||||
|
struct obj_t {
|
||||||
|
obj_t(int i) : i(i) {}
|
||||||
|
int i;
|
||||||
|
|
||||||
|
bool operator<(const obj_t& o) const {
|
||||||
|
return i < o.i;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const obj_t& o) const {
|
||||||
|
return i == o.i;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using set_t = flat_multiset<obj_t>;
|
||||||
|
|
||||||
|
{
|
||||||
|
set_t s0;
|
||||||
|
|
||||||
|
auto i0 = s0.insert(1); // 1
|
||||||
|
REQUIRE(s0 == set_t{1});
|
||||||
|
REQUIRE(i0 == s0.begin());
|
||||||
|
|
||||||
|
auto i1 = s0.insert(obj_t(1)); // 1,1
|
||||||
|
REQUIRE(s0 == set_t{1,1});
|
||||||
|
REQUIRE(i1 == s0.begin() + 1);
|
||||||
|
|
||||||
|
auto i2 = s0.insert(obj_t(2)); // 1,1,2
|
||||||
|
REQUIRE(s0 == set_t{1,1,2});
|
||||||
|
REQUIRE(i2 == s0.begin() + 2);
|
||||||
|
|
||||||
|
auto o2 = obj_t(2);
|
||||||
|
auto i3 = s0.insert(o2); // 1,1,2,2
|
||||||
|
REQUIRE(i3 == s0.begin() + 3);
|
||||||
|
|
||||||
|
s0.insert(s0.cbegin(), 1); // 1,1,1,2,2
|
||||||
|
s0.insert(s0.cbegin(), 2); // 1,1,1,2,2,2
|
||||||
|
s0.insert(s0.cend(), 1); // 1,1,1,1,2,2,2
|
||||||
|
s0.insert(s0.cend(), 2); // 1,1,1,1,2,2,2,2
|
||||||
|
REQUIRE(s0 == set_t{1,1,1,1,2,2,2,2});
|
||||||
|
|
||||||
|
s0.insert(s0.cbegin(), 0); // 0,1,1,1,1,2,2,2,2
|
||||||
|
REQUIRE(s0 == set_t{0,1,1,1,1,2,2,2,2});
|
||||||
|
s0.insert(s0.cend(), 3); // 0,1,1,1,1,2,2,2,2,3
|
||||||
|
REQUIRE(s0 == set_t{0,1,1,1,1,2,2,2,2,3});
|
||||||
|
s0.insert(s0.cbegin(), 4); // 0,1,1,1,1,2,2,2,2,3,4
|
||||||
|
s0.insert(s0.cend(), -1); // -1,0,1,1,1,1,2,2,2,2,3,4
|
||||||
|
REQUIRE(s0 == set_t{-1,0,1,1,1,1,2,2,2,2,3,4});
|
||||||
|
|
||||||
|
s0.insert(s0.cbegin() + 2, obj_t(5)); // -1,0,1,1,1,1,2,2,2,2,3,4,5
|
||||||
|
REQUIRE(s0 == set_t{-1,0,1,1,1,1,2,2,2,2,3,4,5});
|
||||||
|
s0.insert(s0.cbegin(), obj_t(-2)); // -2,-1,0,1,1,1,1,2,2,2,2,3,4,5
|
||||||
|
REQUIRE(s0 == set_t{-2,-1,0,1,1,1,1,2,2,2,2,3,4,5});
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
set_t s0;
|
||||||
|
|
||||||
|
auto e0 = s0.emplace(3); // 3
|
||||||
|
REQUIRE(s0 == set_t{3});
|
||||||
|
REQUIRE(e0 == s0.begin());
|
||||||
|
|
||||||
|
auto e1 = s0.emplace(obj_t(3)); // 3,3
|
||||||
|
REQUIRE(e1 == s0.begin() + 1);
|
||||||
|
|
||||||
|
auto e2 = s0.emplace(4); // 3,3,4
|
||||||
|
REQUIRE(s0 == set_t{3,3,4});
|
||||||
|
REQUIRE(e2 == s0.begin() + 2);
|
||||||
|
|
||||||
|
auto e3 = s0.emplace_hint(s0.cbegin(), 1); // 1,3,3,4
|
||||||
|
REQUIRE(e3 == s0.begin());
|
||||||
|
auto e4 = s0.emplace_hint(s0.cend(), 2); // 1,2,3,3,4
|
||||||
|
REQUIRE(e4 == s0.begin() + 1);
|
||||||
|
s0.emplace_hint(s0.cbegin(), 5); // 1,2,3,3,4,5
|
||||||
|
s0.emplace_hint(s0.cend(), 6); // 1,2,3,3,4,5,6
|
||||||
|
REQUIRE(s0 == set_t{1,2,3,3,4,5,6});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SECTION("erasers") {
|
||||||
|
using set_t = flat_multiset<int>;
|
||||||
|
{
|
||||||
|
set_t s0{1,2,3,4,5};
|
||||||
|
s0.clear();
|
||||||
|
REQUIRE(s0.empty());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
set_t s0{1,2,3,4,5};
|
||||||
|
auto i = s0.erase(s0.find(3));
|
||||||
|
REQUIRE(i == s0.begin() + 2);
|
||||||
|
REQUIRE(s0 == set_t{1,2,4,5});
|
||||||
|
}
|
||||||
|
{
|
||||||
|
set_t s0{1,2,3,4,5};
|
||||||
|
auto i = s0.erase(s0.begin() + 2, s0.end());
|
||||||
|
REQUIRE(i == s0.end());
|
||||||
|
REQUIRE(s0 == set_t{1,2});
|
||||||
|
}
|
||||||
|
{
|
||||||
|
set_t s0{1,2,3,3,4,5};
|
||||||
|
REQUIRE(s0.erase(2) == 1);
|
||||||
|
REQUIRE(s0.erase(3) == 2);
|
||||||
|
REQUIRE(s0.erase(6) == 0);
|
||||||
|
REQUIRE(s0 == set_t{1,4,5});
|
||||||
|
}
|
||||||
|
{
|
||||||
|
set_t s0{1,2,3};
|
||||||
|
set_t s1{3,4,5};
|
||||||
|
s0.swap(s1);
|
||||||
|
REQUIRE(s0 == set_t{3,4,5});
|
||||||
|
REQUIRE(s1 == set_t{1,2,3});
|
||||||
|
swap(s1, s0);
|
||||||
|
REQUIRE(s0 == set_t{1,2,3});
|
||||||
|
REQUIRE(s1 == set_t{3,4,5});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SECTION("lookup") {
|
||||||
|
using set_t = flat_multiset<int>;
|
||||||
|
{
|
||||||
|
set_t s0{1,2,3,3,4,5};
|
||||||
|
REQUIRE(s0.count(2) == 1);
|
||||||
|
REQUIRE(s0.count(3) == 2);
|
||||||
|
REQUIRE_FALSE(s0.count(6));
|
||||||
|
REQUIRE(my_as_const(s0).count(5));
|
||||||
|
REQUIRE_FALSE(my_as_const(s0).count(0));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
set_t s0{1,2,3,4,5};
|
||||||
|
REQUIRE(s0.find(2) == s0.begin() + 1);
|
||||||
|
REQUIRE(my_as_const(s0).find(3) == s0.cbegin() + 2);
|
||||||
|
REQUIRE(s0.find(6) == s0.end());
|
||||||
|
REQUIRE(my_as_const(s0).find(0) == s0.cend());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
set_t s0{1,2,3,3,4,5};
|
||||||
|
REQUIRE(s0.equal_range(3) == std::make_pair(s0.begin() + 2, s0.begin() + 4));
|
||||||
|
REQUIRE(s0.equal_range(6) == std::make_pair(s0.end(), s0.end()));
|
||||||
|
REQUIRE(my_as_const(s0).equal_range(3) == std::make_pair(s0.cbegin() + 2, s0.cbegin() + 4));
|
||||||
|
REQUIRE(my_as_const(s0).equal_range(0) == std::make_pair(s0.cbegin(), s0.cbegin()));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
set_t s0{0,0,3,6,9};
|
||||||
|
REQUIRE(s0.lower_bound(0) == s0.begin());
|
||||||
|
REQUIRE(s0.lower_bound(1) == s0.begin() + 2);
|
||||||
|
REQUIRE(s0.lower_bound(10) == s0.end());
|
||||||
|
REQUIRE(my_as_const(s0).lower_bound(-1) == s0.cbegin());
|
||||||
|
REQUIRE(my_as_const(s0).lower_bound(7) == s0.cbegin() + 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SECTION("observers") {
|
||||||
|
struct my_less {
|
||||||
|
int i;
|
||||||
|
my_less(int i) : i(i) {}
|
||||||
|
bool operator()(int l, int r) const {
|
||||||
|
return l < r;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
using set_t = flat_multiset<int, my_less>;
|
||||||
|
set_t s0(my_less(42));
|
||||||
|
REQUIRE(my_as_const(s0).key_comp().i == 42);
|
||||||
|
REQUIRE(my_as_const(s0).value_comp().i == 42);
|
||||||
|
}
|
||||||
|
SECTION("operators") {
|
||||||
|
using set_t = flat_multiset<int>;
|
||||||
|
|
||||||
|
REQUIRE(set_t{1,2,3} == set_t{3,2,1});
|
||||||
|
REQUIRE_FALSE(set_t{1,2,3} == set_t{3,2,4});
|
||||||
|
REQUIRE_FALSE(set_t{1,2,3} == set_t{1,2,3,4});
|
||||||
|
|
||||||
|
REQUIRE(set_t{1,2,3} != set_t{3,2,4});
|
||||||
|
REQUIRE_FALSE(set_t{1,2,3} != set_t{3,2,1});
|
||||||
|
|
||||||
|
REQUIRE(set_t{2,3,4,6} < set_t{2,3,5});
|
||||||
|
REQUIRE(set_t{2,3,4,6} <= set_t{2,3,5});
|
||||||
|
REQUIRE_FALSE(set_t{2,3,5} < set_t{2,3,4,6});
|
||||||
|
REQUIRE_FALSE(set_t{2,3,5} <= set_t{2,3,4,6});
|
||||||
|
|
||||||
|
REQUIRE_FALSE(set_t{2,3,4,6} > set_t{2,3,5});
|
||||||
|
REQUIRE_FALSE(set_t{2,3,4,6} >= set_t{2,3,5});
|
||||||
|
REQUIRE(set_t{2,3,5} > set_t{2,3,4,6});
|
||||||
|
REQUIRE(set_t{2,3,5} >= set_t{2,3,4,6});
|
||||||
|
|
||||||
|
REQUIRE_FALSE(set_t{1,2,3} < set_t{1,2,3});
|
||||||
|
REQUIRE(set_t{1,2,3} <= set_t{1,2,3});
|
||||||
|
REQUIRE_FALSE(set_t{1,2,3} > set_t{1,2,3});
|
||||||
|
REQUIRE(set_t{1,2,3} >= set_t{1,2,3});
|
||||||
|
|
||||||
|
const set_t s0;
|
||||||
|
REQUIRE(s0 == s0);
|
||||||
|
REQUIRE_FALSE(s0 != s0);
|
||||||
|
REQUIRE_FALSE(s0 < s0);
|
||||||
|
REQUIRE_FALSE(s0 > s0);
|
||||||
|
REQUIRE(s0 <= s0);
|
||||||
|
REQUIRE(s0 >= s0);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user