/* * 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. #ifndef CRYINCLUDE_CRYAISYSTEM_POLYGONSETOPS_BIDIRMAP_H #define CRYINCLUDE_CRYAISYSTEM_POLYGONSETOPS_BIDIRMAP_H #pragma once #include #include /// Small utility to compare pointers by the values they point to. template class PointerValueCompare { public: bool operator() (const T* lhs, const T* rhs) const { return *lhs < *rhs; } }; /** * @brief Allows going from values to keys as well. * * NOTE Jul 10, 2007: not truly generic but could be made if needed. * Uses two std::sets to index pairs of values. Supports a subset of STL-like * operations, however everything's capitalized (e.g. 'Iterator' instead of * 'iterator'), partly to indicate that no specific effort has been made * to make it really STL-conformant. */ template class BidirectionalMap { typedef std::set > FwdMap; typedef std::set > BwdMap; FwdMap mFwd; BwdMap mBwd; void Swap (BidirectionalMap&); public: typedef std::pair DataRecord; BidirectionalMap (); BidirectionalMap (const BidirectionalMap&); ~BidirectionalMap (); BidirectionalMap& operator= (const BidirectionalMap&); void Insert (const T1&, const T0&); void Insert (const T0&, const T1&); void Erase (const T0&); void Erase (const T1&); void Clear (); class Iterator; Iterator Find (const T0&) const; Iterator Find (const T1&) const; const T1& operator[] (const T0&) const; const T0& operator[] (const T1&) const; int Size () const; bool Empty () const; // TODO Jun 28, 2007: make the GetKeys function a template is possible: // bimap.GetKeys (); // Using terms "primary" and "secondary" implies asymetry between the two // sets of values where there's essentially none (except for fairly minor // implementation one). // template // std::vector GetKeys () const; // use the swap idiom: // bimap.GetKeys().swap (your_key_vec); std::vector GetPrimaryKeys () const; std::vector GetSecondaryKeys () const; class Iterator { typename FwdMap::const_iterator mPrimKeysIter; public: Iterator (const typename FwdMap::const_iterator& prim_keys_iter); Iterator& operator++ (); const DataRecord* operator* () const; bool operator== (const Iterator&) const; bool operator!= (const Iterator&) const; }; Iterator Begin () const; Iterator End () const; }; template inline BidirectionalMap::BidirectionalMap () { } template inline BidirectionalMap::BidirectionalMap (const BidirectionalMap& rhs) { typename FwdMap::const_iterator it = rhs.mFwd.begin (); typename FwdMap::const_iterator end = rhs.mFwd.end (); for (; it != end; ++it) { const DataRecord* data = reinterpret_cast (*it); Insert (data->first, data->second); } } template inline BidirectionalMap::~BidirectionalMap () { Clear (); } template inline BidirectionalMap& BidirectionalMap::operator= (const BidirectionalMap& rhs) { BidirectionalMap tmp (rhs); Swap (tmp); return *this; } template inline void BidirectionalMap::Swap (BidirectionalMap& rhs) { mFwd.swap (rhs.mFwd); mBwd.swap (rhs.mBwd); } template inline void BidirectionalMap::Insert(const T1& f, const T0& i) { DataRecord* new_val = new DataRecord (i, f); std::pair fwd_result = mFwd.insert (&new_val->first); assert (fwd_result.second); std::pair bwd_result = mBwd.insert (&new_val->second); assert (bwd_result.second); } template inline void BidirectionalMap::Insert(const T0& i, const T1& f) { Insert (f, i); } template inline void BidirectionalMap::Erase(const T0& i) { typename FwdMap::iterator fwd_it = mFwd.find (&i); assert (fwd_it != mFwd.end ()); const DataRecord* to_be_deleted = reinterpret_cast (*fwd_it); typename BwdMap::iterator bwd_it = mBwd.find (&to_be_deleted->second); assert (bwd_it != mBwd.end ()); mFwd.erase (fwd_it); mBwd.erase (bwd_it); delete to_be_deleted; } template inline void BidirectionalMap::Erase(const T1& f) { typename BwdMap::const_iterator bwd_it = mBwd.find (&f); assert (bwd_it != mBwd.end ()); const DataRecord* to_be_deleted = reinterpret_cast ((char* )*bwd_it - offsetof(DataRecord, second)); typename FwdMap::const_iterator fwd_it = mFwd.find (&to_be_deleted->first); assert (fwd_it != mFwd.end ()); mFwd.erase (fwd_it); mBwd.erase (bwd_it); delete to_be_deleted; } template inline void BidirectionalMap::Clear() { typename FwdMap::iterator fwd_it = mFwd.begin (); typename FwdMap::iterator fwd_end = mFwd.end (); for (; fwd_it != fwd_end; ++fwd_it) { delete reinterpret_cast (*fwd_it); } mFwd.clear (); mBwd.clear (); } template inline typename BidirectionalMap::Iterator BidirectionalMap::Find (const T0& i) const { return Iterator (mFwd.find (&i)); } template inline typename BidirectionalMap::Iterator BidirectionalMap::Find (const T1& f) const { typename BwdMap::const_iterator it = mBwd.find (&f); if (it == mBwd.end ()) { return mFwd.end (); } const DataRecord* value = reinterpret_cast * > ((char* )*it - offsetof(DataRecord, second)); return Iterator (mFwd.find (&value->first)); } template inline const T1& BidirectionalMap::operator[] (const T0& i) const { return (*Find (i))->second; } template inline const T0& BidirectionalMap::operator[] (const T1& f) const { return (*Find (f))->first; } template inline int BidirectionalMap::Size () const { assert (mFwd.size () == mBwd.size ()); return mFwd.size (); } template inline bool BidirectionalMap::Empty () const { assert (mFwd.size () == mBwd.size ()); return mFwd.empty (); } #if 0 template template inline std::vector BidirectionalMap::GetKeys () const { std::vector result; typename FwdMap::const_iterator it = mFwd.begin (); typename FwdMap::const_iterator end = mFwd.end (); for (; it != end; ++it) { result.push_back (**it); } return result; } #endif template inline std::vector BidirectionalMap::GetPrimaryKeys () const { std::vector result; result.reserve (mFwd.size ()); typename FwdMap::const_iterator it = mFwd.begin (); typename FwdMap::const_iterator end = mFwd.end (); for (; it != end; ++it) { result.push_back (**it); } return result; } template inline std::vector BidirectionalMap::GetSecondaryKeys () const { std::vector result; result.reserve (mBwd.size ()); #if 0 typename BwdMap::const_iterator it = mBwd.begin (); typename BwdMap::const_iterator end = mBwd.end (); for (; it != end; ++it) { result.push_back (**it); } #endif Iterator it = Begin (); Iterator end = End (); for (; it != end; ++it) { result.push_back ((*it)->second); } return result; } template inline BidirectionalMap::Iterator::Iterator (const typename FwdMap::const_iterator& prim_keys_iter) : mPrimKeysIter (prim_keys_iter) { } template inline typename BidirectionalMap::Iterator& BidirectionalMap::Iterator::operator++ () { ++mPrimKeysIter; return *this; } template inline const typename BidirectionalMap::DataRecord* BidirectionalMap::Iterator::operator* () const { return reinterpret_cast (*mPrimKeysIter); } template inline bool BidirectionalMap::Iterator::operator== (const Iterator& rhs) const { return mPrimKeysIter == rhs.mPrimKeysIter; } template inline bool BidirectionalMap::Iterator::operator!= (const Iterator& rhs) const { return !(mPrimKeysIter == rhs.mPrimKeysIter); } template inline typename BidirectionalMap::Iterator BidirectionalMap::Begin () const { return Iterator (mFwd.begin ()); } template inline typename BidirectionalMap::Iterator BidirectionalMap::End () const { return Iterator (mFwd.end ()); } #endif // CRYINCLUDE_CRYAISYSTEM_POLYGONSETOPS_BIDIRMAP_H