#ifndef VTR_VECTOR_MAP #define VTR_VECTOR_MAP #include #include "vtr_assert.h" #include "vtr_sentinels.h" namespace vtr { //A vector-like container which is indexed by K (instead of size_t as in std::vector). // //The main use of this container is to behave like a std::vector which is indexed by //vtr::StrongId. // //Requires that K be convertable to size_t with the size_t operator (i.e. size_t()), and //that the conversion results in a linearly increasing index into the underlying vector. // //This results in a container that is somewhat similar to a std::map (i.e. converts from one //type to another), but requires contiguously ascending (i.e. linear) keys. Unlike std::map //only the values are stored (at the specified index/key), reducing memory usage and improving //cache locality. Furthermore, operator[] and find() return the value or iterator directly //associated with the value (like std::vector) rather than a std::pair (like std::map). //insert() takes both the key and value as separate arguments and has no return value. // //Additionally, vector_map will silently create values for 'gaps' in the index range (i.e. //those elements are initialized with Sentinel::INVALID()). // //If you need a fully featured std::map like container without the above differences see //vtr::linear_map. // //If you do not need std::map-like features see vtr::vector. // //Note that it is possible to use vector_map with sparse/non-contiguous keys, but this is typically //memory inefficient as the underlying vector will allocate space for [0..size_t(max_key)-1], //where max_key is the largest key that has been inserted. // //As with a std::vector, it is the caller's responsibility to ensure there is sufficient space //when a given index/key before it is accessed. The exception to this are the find(), insert() and //update() methods which handle non-existing keys gracefully. template> class vector_map { public: //Public types typedef typename std::vector::const_reference const_reference; typedef typename std::vector::reference reference; typedef typename std::vector::iterator iterator; typedef typename std::vector::const_iterator const_iterator; typedef typename std::vector::const_reverse_iterator const_reverse_iterator; public: //Constructor template vector_map(Args&&... args) : vec_(std::forward(args)...) { } public: //Accessors //Iterators const_iterator begin() const { return vec_.begin(); } const_iterator end() const { return vec_.end(); } const_reverse_iterator rbegin() const { return vec_.rbegin(); } const_reverse_iterator rend() const { return vec_.rend(); } //Indexing const_reference operator[] (const K n) const { size_t index = size_t(n); VTR_ASSERT_SAFE_MSG(index >= 0 && index < vec_.size(), "Out-of-range index"); return vec_[index]; } const_iterator find(const K key) const { if(size_t(key) < vec_.size()) { return vec_.begin() + size_t(key); } else { return vec_.end(); } } std::size_t size() const { return vec_.size(); } bool empty() const { return vec_.empty(); } bool contains(const K key) const { return size_t(key) < vec_.size(); } size_t count(const K key) const { return contains(key) ? 1 : 0; } public: //Mutators //Delegate potentially overloaded functions to the underlying vector with perfect //forwarding template void push_back(Args&&... args) { vec_.push_back(std::forward(args)...); } template void emplace_back(Args&&... args) { vec_.emplace_back(std::forward(args)...); } template void resize(Args&&... args) { vec_.resize(std::forward(args)...); } void clear() { vec_.clear(); } size_t capacity() const { return vec_.capacity(); } void shrink_to_fit() { vec_.shrink_to_fit(); } //Iterators iterator begin() { return vec_.begin(); } iterator end() { return vec_.end(); } //Indexing reference operator[] (const K n) { VTR_ASSERT_SAFE_MSG(size_t(n) < vec_.size(), "Out-of-range index"); return vec_[size_t(n)]; } iterator find(const K key) { if(size_t(key) < vec_.size()) { return vec_.begin() + size_t(key); } else { return vec_.end(); } } void insert(const K key, const V value) { if(size_t(key) >= vec_.size()) { //Resize so key is in range vec_.resize(size_t(key) + 1, Sentinel::INVALID()); } //Insert the value operator[](key) = value; } void update(const K key, const V value) { insert(key, value); } //Swap (this enables std::swap via ADL) friend void swap(vector_map& x, vector_map& y) { std::swap(x.vec_, y.vec_); } private: std::vector vec_; }; } //namespace #endif