/******************************************************************************* * 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 #include #include #include #include #include #include #include #include "detail/pair_compare.hpp" #include "detail/is_transparent.hpp" namespace flat_hpp { template < typename Key , typename Value , typename Compare = std::less , typename Container = std::vector> > class flat_map : private detail::pair_compare< typename Container::value_type, Compare> { using base_type = detail::pair_compare< typename Container::value_type, Compare>; 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 : private key_compare { public: bool operator()(const value_type& l, const value_type& r) const { return key_compare::operator()(l.first, r.first); } protected: friend class flat_map; explicit value_compare(key_compare compare) : key_compare(std::move(compare)) {} }; public: flat_map() noexcept(std::is_nothrow_default_constructible_v && std::is_nothrow_default_constructible_v) {} explicit flat_map(const Compare& c) : base_type(c) {} template < typename Allocator > explicit flat_map(const Allocator& a) : data_(a) {} template < typename Allocator > flat_map(const Compare& c, const Allocator& a) : base_type(c) , data_(a) {} template < typename InputIter > flat_map(InputIter first, InputIter last) { insert(first, last); } template < typename InputIter > flat_map(InputIter first, InputIter last, const Compare& c) : base_type(c) { insert(first, last); } template < typename InputIter, typename Allocator > flat_map(InputIter first, InputIter last, const Allocator& a) : data_(a) { insert(first, last); } template < typename InputIter , typename Allocator > flat_map(InputIter first, InputIter last, const Compare& c, const Allocator& a) : base_type(c) , data_(a) { insert(first, last); } flat_map(std::initializer_list ilist) { insert(ilist); } flat_map(std::initializer_list ilist, const Compare& c) : base_type(c) { insert(ilist); } template < typename Allocator > flat_map(std::initializer_list ilist, const Allocator& a) : data_(a) { insert(ilist); } template < typename Allocator > flat_map(std::initializer_list ilist, const Compare& c, const Allocator& a) : base_type(c) , data_(a) { insert(ilist); } template < typename Allocator > flat_map(flat_map&& other, const Allocator& a) : base_type(static_cast(other)) , data_(std::move(other.data_), a) {} template < typename Allocator > flat_map(const flat_map& other, const Allocator& a) : base_type(static_cast(other)) , data_(other.data_, a) {} flat_map(flat_map&& other) = default; flat_map(const flat_map& other) = default; flat_map& operator=(flat_map&& other) = default; flat_map& operator=(const flat_map& other) = default; flat_map& operator=(std::initializer_list ilist) { flat_map(ilist).swap(*this); return *this; } iterator begin() noexcept(noexcept(std::declval().begin())) { return data_.begin(); } const_iterator begin() const noexcept(noexcept(std::declval().begin())) { return data_.begin(); } const_iterator cbegin() const noexcept(noexcept(std::declval().cbegin())) { return data_.cbegin(); } iterator end() noexcept(noexcept(std::declval().end())) { return data_.end(); } const_iterator end() const noexcept(noexcept(std::declval().end())) { return data_.end(); } const_iterator cend() const noexcept(noexcept(std::declval().cend())) { return data_.cend(); } reverse_iterator rbegin() noexcept(noexcept(std::declval().rbegin())) { return data_.rbegin(); } const_reverse_iterator rbegin() const noexcept(noexcept(std::declval().rbegin())) { return data_.rbegin(); } const_reverse_iterator crbegin() const noexcept(noexcept(std::declval().crbegin())) { return data_.crbegin(); } reverse_iterator rend() noexcept(noexcept(std::declval().rend())) { return data_.rend(); } const_reverse_iterator rend() const noexcept(noexcept(std::declval().rend())) { return data_.rend(); } const_reverse_iterator crend() const noexcept(noexcept(std::declval().crend())) { return data_.crend(); } bool empty() const noexcept(noexcept(std::declval().empty())) { return data_.empty(); } size_type size() const noexcept(noexcept(std::declval().size())) { return data_.size(); } size_type max_size() const noexcept(noexcept(std::declval().max_size())) { return data_.max_size(); } size_type capacity() const noexcept(noexcept(std::declval().capacity())) { 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()).first->second; } mapped_type& operator[](const key_type& key) { const iterator iter = find(key); return iter != end() ? iter->second : emplace(key, mapped_type()).first->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_map::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_map::at: key not found"); } template < typename K > std::enable_if_t< detail::is_transparent_v, mapped_type&> at(const K& key) { const iterator iter = find(key); if ( iter != end() ) { return iter->second; } throw std::out_of_range("flat_map::at: key not found"); } template < typename K > std::enable_if_t< detail::is_transparent_v, const mapped_type&> at(const K& key) const { const const_iterator iter = find(key); if ( iter != end() ) { return iter->second; } throw std::out_of_range("flat_map::at: key not found"); } std::pair insert(value_type&& value) { const iterator iter = lower_bound(value.first); return iter == end() || this->operator()(value, *iter) ? std::make_pair(data_.insert(iter, std::move(value)), true) : std::make_pair(iter, false); } std::pair insert(const value_type& value) { const iterator iter = lower_bound(value.first); return iter == end() || this->operator()(value, *iter) ? std::make_pair(data_.insert(iter, value), true) : std::make_pair(iter, false); } iterator insert(const_iterator hint, value_type&& value) { return (hint == begin() || this->operator()(*(hint - 1), value)) && (hint == end() || this->operator()(value, *hint)) ? data_.insert(hint, std::move(value)) : insert(std::move(value)).first; } iterator insert(const_iterator hint, const value_type& value) { return (hint == begin() || this->operator()(*(hint - 1), value)) && (hint == end() || this->operator()(value, *hint)) ? data_.insert(hint, value) : insert(value).first; } template < typename InputIter > void insert(InputIter first, InputIter last) { while ( first != last ) { insert(*first++); } } void insert(std::initializer_list ilist) { insert(ilist.begin(), ilist.end()); } template < typename... Args > std::pair emplace(Args&&... args) { return insert(value_type(std::forward(args)...)); } template < typename... Args > iterator emplace_hint(const_iterator hint, Args&&... args) { return insert(hint, value_type(std::forward(args)...)); } void clear() noexcept(noexcept(std::declval().clear())) { 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 const_iterator iter = find(key); return iter != end() ? (erase(iter), 1) : 0; } void swap(flat_map& other) noexcept(std::is_nothrow_swappable_v && std::is_nothrow_swappable_v) { using std::swap; swap( static_cast(*this), static_cast(other)); swap(data_, other.data_); } size_type count(const key_type& key) const { const const_iterator iter = find(key); return iter != end() ? 1 : 0; } template < typename K > std::enable_if_t< detail::is_transparent_v, size_type> count(const K& key) const { const const_iterator iter = find(key); return iter != end() ? 1 : 0; } iterator find(const key_type& key) { const iterator iter = lower_bound(key); return iter != end() && !this->operator()(key, *iter) ? iter : end(); } const_iterator find(const key_type& key) const { const const_iterator iter = lower_bound(key); return iter != end() && !this->operator()(key, *iter) ? iter : end(); } template < typename K > std::enable_if_t< detail::is_transparent_v, iterator> find(const K& key) { const iterator iter = lower_bound(key); return iter != end() && !this->operator()(key, *iter) ? iter : end(); } template < typename K > std::enable_if_t< detail::is_transparent_v, const_iterator> find(const K& key) const { const const_iterator iter = lower_bound(key); return iter != end() && !this->operator()(key, *iter) ? iter : end(); } std::pair equal_range(const key_type& key) { const base_type& comp = *this; return std::equal_range(begin(), end(), key, comp); } std::pair equal_range(const key_type& key) const { const base_type& comp = *this; return std::equal_range(begin(), end(), key, comp); } template < typename K > std::enable_if_t< detail::is_transparent_v, std::pair> equal_range(const K& key) { const base_type& comp = *this; return std::equal_range(begin(), end(), key, comp); } template < typename K > std::enable_if_t< detail::is_transparent_v, std::pair> equal_range(const K& key) const { const base_type& comp = *this; return std::equal_range(begin(), end(), key, comp); } iterator lower_bound(const key_type& key) { const base_type& comp = *this; return std::lower_bound(begin(), end(), key, comp); } const_iterator lower_bound(const key_type& key) const { const base_type& comp = *this; return std::lower_bound(begin(), end(), key, comp); } template < typename K > std::enable_if_t< detail::is_transparent_v, iterator> lower_bound(const K& key) { const base_type& comp = *this; return std::lower_bound(begin(), end(), key, comp); } template < typename K > std::enable_if_t< detail::is_transparent_v, const_iterator> lower_bound(const K& key) const { const base_type& comp = *this; return std::lower_bound(begin(), end(), key, comp); } iterator upper_bound(const key_type& key) { const base_type& comp = *this; return std::upper_bound(begin(), end(), key, comp); } const_iterator upper_bound(const key_type& key) const { const base_type& comp = *this; return std::upper_bound(begin(), end(), key, comp); } template < typename K > std::enable_if_t< detail::is_transparent_v, iterator> upper_bound(const K& key) { const base_type& comp = *this; return std::upper_bound(begin(), end(), key, comp); } template < typename K > std::enable_if_t< detail::is_transparent_v, const_iterator> upper_bound(const K& key) const { const base_type& comp = *this; return std::upper_bound(begin(), end(), key, comp); } key_compare key_comp() const { return *this; } value_compare value_comp() const { return value_compare(key_comp()); } private: container_type data_; }; } namespace flat_hpp { template < typename Key , typename Value , typename Compare , typename Container > void swap( flat_map& l, flat_map& r) noexcept(noexcept(l.swap(r))) { l.swap(r); } template < typename Key , typename Value , typename Compare , typename Container > bool operator==( const flat_map& l, const flat_map& 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_map& l, const flat_map& r) { return !(l == r); } template < typename Key , typename Value , typename Compare , typename Container > bool operator<( const flat_map& l, const flat_map& 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_map& l, const flat_map& r) { return r < l; } template < typename Key , typename Value , typename Compare , typename Container > bool operator<=( const flat_map& l, const flat_map& r) { return !(r < l); } template < typename Key , typename Value , typename Compare , typename Container > bool operator>=( const flat_map& l, const flat_map& r) { return !(l < r); } }