c++ - One-to-one relation in STL terms -
as know there no biunivocal mapping datastruct/adt in c++ (stl) , c++1y. need sorted associative container allows me map key set value set , vice versa.
what best approach or existant solution?
my proposal is:
#!/usr/bin/env bash -vex # cls ; bash self.bash 2>&1 | tee self.log | less warn="-w -wall -wextra -werror" g++ -x c++ - -std=gnu++1y $warn -ofast -o <<__eof && ./a && echo -e "\e[1;32msucceeded\e[0m" || echo -e "\e[1;31mfailed\e[0m" #include <list> #include <tuple> #include <map> #include <functional> #include <string> #include <cstdlib> #include <cassert> template< typename a, typename b > class bijection { using data_type = std::list< std::tuple< const, b const > >; public : using iterator = typename data_type::iterator; using const_iterator = typename data_type::const_iterator; private : using direct_mapping_type = std::map< std::reference_wrapper< const >, iterator, std::less< const & > > ; using inverse_mapping_type = std::map< std::reference_wrapper< b const >, iterator, std::less< b const & > >; using direct_iterator = typename direct_mapping_type::iterator; using inverse_iterator = typename inverse_mapping_type::iterator; public : auto size() const { return data_.size(); } iterator find(a const & a) { auto const direct = direct_mapping_.find(a); if (direct == direct_mapping_.end()) { return data_.end(); } else { return direct->second; } } iterator find(b const & b) { auto const inverse = inverse_mapping_.find(b); if (inverse == inverse_mapping_.end()) { return data_.end(); } else { return inverse->second; } } auto erase(iterator pos) { auto const & element = *pos; direct_mapping_.erase(std::get< 0 >(element)); inverse_mapping_.erase(std::get< 1 >(element)); return data_.erase(pos); } template< typename x, typename y > std::tuple< iterator, bool, bool > insert(x && x, y && y) { direct_iterator direct = direct_mapping_.find(x); inverse_iterator inverse = inverse_mapping_.find(y); bool const d = (direct != direct_mapping_.end()); bool const = (inverse != inverse_mapping_.end()); if (d && i) { iterator ix = inverse->second; iterator iy = direct->second; inverse_mapping_.erase(inverse); direct_mapping_.erase(direct); if (ix != iy) { inverse_mapping_.erase(std::get< 1 >(*iy)); direct_mapping_.erase(std::get< 0 >(*ix)); data_.erase(iy); data_.erase(ix); } else { data_.erase(ix); // iy } } else if (d) { iterator iy = direct->second; direct_mapping_.erase(direct); inverse_mapping_.erase(std::get< 1 >(*iy)); data_.erase(iy); } else if (i) { iterator ix = inverse->second; inverse_mapping_.erase(inverse); direct_mapping_.erase(std::get< 0 >(*ix)); data_.erase(ix); } data_.emplace_back(std::forward< x >(x), std::forward< y >(y)); auto const & element = data_.back(); iterator = --data_.end(); direct_mapping_.emplace(std::get< 0 >(element), it); inverse_mapping_.emplace(std::get< 1 >(element), it); return std::make_tuple(it, d, i); } private : data_type data_; direct_mapping_type direct_mapping_; inverse_mapping_type inverse_mapping_; }; int main() { using = std::size_t; using b = std::string; using m = bijection< a, b >; m m; assert(1 == (m.insert(a(111), b("111")), m.size())); assert(1 == (m.insert(a(111), b("111")), m.size())); assert(2 == (m.insert(a(222), b("222")), m.size())); assert(3 == (m.insert(a(333), b("333")), m.size())); assert(2 == (m.insert(a(222), b("111")), m.size())); assert(3 == (m.insert(a(111), b("222")), m.size())); assert(2 == (m.insert(a(111), b("111")), m.size())); assert(1 == (m.insert(a(333), b("111")), m.size())); assert(1 == (m.insert(a(333), b("333")), m.size())); assert(1 == (m.insert(a(111), b("333")), m.size())); assert(0 == (m.erase(m.find(a(111))), m.size())); return exit_success; } __eof
if need tested can use boost bimap library.
Comments
Post a Comment