/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ // Original file Copyright Crytek GMBH or its affiliates, used under license. // Description : std::map replacement implemented using sorted vector. #ifndef CRYINCLUDE_CRYCOMMON_VECTORMAP_H #define CRYINCLUDE_CRYCOMMON_VECTORMAP_H #pragma once //-------------------------------------------------------------------------- // VectorMap // // Usage Notes: // This class is designed to be an (almost, see below) drop-in replacement // for std::map. It features an almost identical interface, but it is // implemented using a sorted vector rather than a tree. This is in most // cases more efficient, as there is less dynamic memory allocation and // pointer dereferencing. // // ************************************************************************* // PLEASE NOTE: There is one vital difference between std::map and VectorMap // that you will need to note before trying to replace std::map. Since // VectorMap is implemented using a vector, iterators can and will be // invalidated by many operations, such as insertions and deletions, and // due to sorting potentially even normal lookups. Please Please PLEASE make // sure that you are not storing any iterators to this class. // ************************************************************************* // // The class varies from the std::set API in that two of the erase methods // methods are not of void return type but return an iterator - this is // required in practice because they invalidate iterators, as noted above. // // * iterator erase(iterator where); // * iterator erase(iterator first, iterator last); // // // Performance Notes: // // This class uses the empty base optimization hack to allow comparison // predicate objects that have no state to take up no space in the object. // As a result the size of the overall VectorMap instance is the same as // that of the std::vector it uses to store the elements. // // In addition to the normal map interface, this class provides the // following members that can be used to manage memory requirements: // // * void reserve(size_type count); // Allocate enough space for count elements (see vector::reserve()). // // * size_type capacity() const; // Report how many elements can be stored without reallocating (see // vector::capacity()). // //-------------------------------------------------------------------------- template , typename A = std::allocator > > class VectorMap : private T // Empty base optimization { public: typedef K key_type; typedef V mapped_type; typedef A allocator_type; typedef std::pair value_type; typedef T key_compare; class FirstLess { public: FirstLess(const key_compare& comp) : m_comp(comp) {} bool operator()(const value_type& left, const value_type& right) const { return m_comp(left.first, right.first); } private: const key_compare& m_comp; }; typedef std::vector container_type; typedef typename container_type::iterator iterator; typedef typename container_type::const_iterator const_iterator; typedef typename container_type::reverse_iterator reverse_iterator; typedef typename container_type::const_reverse_iterator const_reverse_iterator; typedef value_type& reference; typedef const value_type& const_reference; typedef value_type* pointer; typedef const value_type* const_pointer; typedef typename std::allocator_traits::size_type size_type; VectorMap(); explicit VectorMap(const key_compare& comp); explicit VectorMap(const key_compare& comp, const allocator_type& alloc); VectorMap(const VectorMap& right); template VectorMap(InputIterator first, InputIterator last); template VectorMap(InputIterator first, InputIterator last, const key_compare& comp); template VectorMap(InputIterator first, InputIterator last, const key_compare& comp, const allocator_type& alloc); void SwapElementsWithVector(container_type& elementVector); iterator begin(); const_iterator begin() const; size_type capacity() const; void clear(); void clearAndFreeMemory(); size_type count(const key_type& key) const; bool empty() const; iterator end(); const_iterator end() const; std::pair equal_range(const key_type& key); std::pair equal_range(const key_type& key) const; iterator erase(iterator where); // See documentation above iterator erase(iterator first, iterator last); // See documentation above void erase(const key_type& key); template void erase_if(const Predicate& predicate); iterator find(const key_type& key); const_iterator find(const key_type& key) const; allocator_type get_allocator() const; std::pair insert(const value_type& val); iterator insert(iterator where, const value_type& val); template void insert(InputIterator first, InputIterator last); key_compare key_comp() const; iterator lower_bound(const key_type& key); const_iterator lower_bound(const key_type& key) const; size_type max_size() const; reverse_iterator rbegin(); const_reverse_iterator rbegin() const; reverse_iterator rend(); const_reverse_iterator rend() const; void reserve(size_type count); size_type size() const; void swap(VectorMap& other); iterator upper_bound(const key_type& key); const_iterator upper_bound(const key_type& key) const; mapped_type& operator[](const key_type& key); template void GetMemoryUsage(Sizer* pSizer) const { pSizer->AddObject(m_entries); } private: container_type m_entries; }; template VectorMap::VectorMap() { } template VectorMap::VectorMap(const key_compare& comp) : key_compare(comp) { } template VectorMap::VectorMap(const key_compare& comp, const allocator_type& alloc) : key_compare(comp) , m_entries(alloc) { } template VectorMap::VectorMap(const VectorMap& right) : key_compare(right) , m_entries(right.m_entries) { } template template VectorMap::VectorMap(InputIterator first, InputIterator last) { for (; first != last; ++first) { m_entries.push_back(*first); } std::sort(m_entries.begin(), m_entries.end(), FirstLess(static_cast(*this))); } template template VectorMap::VectorMap(InputIterator first, InputIterator last, const key_compare& comp) : key_compare(comp) { for (; first != last; ++first) { m_entries.push_back(*first); } std::sort(m_entries.begin(), m_entries.end(), FirstLess(static_cast(*this))); } template template VectorMap::VectorMap(InputIterator first, InputIterator last, const key_compare& comp, const allocator_type& alloc) : key_compare(comp) , m_entries(alloc) { for (; first != last; ++first) { m_entries.push_back(*first); } std::sort(m_entries.begin(), m_entries.end(), FirstLess(static_cast(*this))); } template void VectorMap::SwapElementsWithVector(typename VectorMap::container_type& elementVector) { m_entries.swap(elementVector); std::sort(m_entries.begin(), m_entries.end(), FirstLess(static_cast(*this))); } template typename VectorMap::iterator VectorMap::begin() { return m_entries.begin(); } template typename VectorMap::const_iterator VectorMap::begin() const { return m_entries.begin(); } template void VectorMap::clear() { m_entries.resize(0); } template void VectorMap::clearAndFreeMemory() { stl::free_container(m_entries); } template typename VectorMap::size_type VectorMap::capacity() const { return m_entries.capacity(); } template typename VectorMap::size_type VectorMap::count(const key_type& key) const { return size_type(std::binary_search(m_entries.begin(), m_entries.end(), value_type(key, mapped_type()), static_cast(*this))); } template bool VectorMap::empty() const { return m_entries.empty(); } template typename VectorMap::iterator VectorMap::end() { return m_entries.end(); } template typename VectorMap::const_iterator VectorMap::end() const { return m_entries.end(); } template std::pair::iterator, typename VectorMap::iterator> VectorMap::equal_range(const key_type& key) { iterator lower = lower_bound(key); if (lower != m_entries.end() && key_compare::operator()(key, (*lower).first)) { lower = m_entries.end(); } iterator upper = lower; if (upper != m_entries.end()) { ++upper; } return std::make_pair(lower, upper); } template std::pair::const_iterator, typename VectorMap::const_iterator> VectorMap::equal_range(const key_type& key) const { const_iterator lower = lower_bound(key); if (lower != m_entries.end() && key_compare::operator()(key, (*lower).first)) { lower = m_entries.end(); } const_iterator upper = lower; if (upper != m_entries.end()) { ++upper; } return std::make_pair(lower, upper); } template typename VectorMap::iterator VectorMap::erase(iterator where) { return m_entries.erase(where); } template template void VectorMap::erase_if(const Predicate& predicate) { m_entries.erase(std::remove_if(m_entries.begin(), m_entries.end(), predicate), m_entries.end()); std::sort(m_entries.begin(), m_entries.end(), FirstLess(static_cast(*this))); } template typename VectorMap::iterator VectorMap::erase(iterator first, iterator last) { return m_entries.erase(first, last); } template void VectorMap::erase(const key_type& key) { iterator where = find(key); if (where != m_entries.end()) { m_entries.erase(where); } } template typename VectorMap::iterator VectorMap::find(const key_type& key) { iterator it = lower_bound(key); if (it != m_entries.end() && key_compare::operator()(key, (*it).first)) { it = m_entries.end(); } return it; } template typename VectorMap::const_iterator VectorMap::find(const key_type& key) const { const_iterator it = lower_bound(key); if (it != m_entries.end() && key_compare::operator()(key, (*it).first)) { it = m_entries.end(); } return it; } template typename VectorMap::allocator_type VectorMap::get_allocator() const { return m_entries.get_allocator(); } template std::pair::iterator, bool> VectorMap::insert(const value_type& val) { iterator it = lower_bound(val.first); bool insertionMade = false; if (it == m_entries.end() || key_compare::operator()(val.first, (*it).first)) { it = m_entries.insert(it, val), insertionMade = true; } return std::make_pair(it, insertionMade); } template typename VectorMap::iterator VectorMap::insert(iterator where, const value_type& val) { return insert(val); } template template void VectorMap::insert(InputIterator first, InputIterator last) { for (; first != last; ++first) { insert(*first); } } template typename VectorMap::key_compare VectorMap::key_comp() const { return static_cast(*this); } template typename VectorMap::iterator VectorMap::lower_bound(const key_type& key) { int count = 0; count = m_entries.size(); iterator first = m_entries.begin(); iterator last = m_entries.end(); for (; 0 < count; ) { // divide and conquer, find half that contains answer int count2 = count / 2; iterator mid = first + count2; if (key_compare::operator()(mid->first, key)) { first = ++mid, count -= count2 + 1; } else { count = count2; } } return first; } template typename VectorMap::const_iterator VectorMap::lower_bound(const key_type& key) const { int count = 0; count = m_entries.size(); const_iterator first = m_entries.begin(); const_iterator last = m_entries.end(); for (; 0 < count; ) { // divide and conquer, find half that contains answer int count2 = count / 2; const_iterator mid = first + count2; if (key_compare::operator()(mid->first, key)) { first = ++mid, count -= count2 + 1; } else { count = count2; } } return first; } template typename VectorMap::size_type VectorMap::max_size() const { return m_entries.max_size(); } template typename VectorMap::reverse_iterator VectorMap::rbegin() { return m_entries.rbegin(); } template typename VectorMap::const_reverse_iterator VectorMap::rbegin() const { return m_entries.rbegin(); } template typename VectorMap::reverse_iterator VectorMap::rend() { return m_entries.rend(); } template typename VectorMap::const_reverse_iterator VectorMap::rend() const { return m_entries.rend(); } template void VectorMap::reserve(size_type count) { m_entries.reserve(count); } template typename VectorMap::size_type VectorMap::size() const { return m_entries.size(); } template void VectorMap::swap(VectorMap& other) { m_entries.swap(other.m_entries); std::swap(static_cast(*this), static_cast(other)); } template typename VectorMap::iterator VectorMap::upper_bound(const key_type& key) { iterator upper = lower_bound(key); if (upper != m_entries.end() && !key_compare::operator()(key, (*upper).first)) { ++upper; } return upper; } template typename VectorMap::const_iterator VectorMap::upper_bound(const key_type& key) const { iterator upper = lower_bound(key); if (upper != m_entries.end() && !key_compare::operator()(key, (*upper).first)) { ++upper; } return upper; } template typename VectorMap::mapped_type& VectorMap::operator[](const key_type& key) { iterator it = find(key); if (it == m_entries.end()) { it = insert(value_type(key, mapped_type())).first; } return (*it).second; } #endif // CRYINCLUDE_CRYCOMMON_VECTORMAP_H