/* * Copyright 2018 Google * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_IMMUTABLE_SORTED_MAP_ITERATOR_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_IMMUTABLE_SORTED_MAP_ITERATOR_H_ #include #include "Firestore/core/src/firebase/firestore/immutable/array_sorted_map.h" #include "Firestore/core/src/firebase/firestore/immutable/tree_sorted_map.h" namespace firebase { namespace firestore { namespace immutable { namespace impl { template class SortedMapIterator { public: using iterator_category = std::forward_iterator_tag; using value_type = V; using pointer = const value_type*; using reference = const value_type&; using difference_type = std::ptrdiff_t; public: // Default constructor to conform to the requirements of ForwardIterator SortedMapIterator() : tag_{Tag::Array}, array_iter_{} { } explicit SortedMapIterator(ArrayIter&& delegate) : tag_{Tag::Array}, array_iter_{std::move(delegate)} { } explicit SortedMapIterator(TreeIter&& delegate) : tag_{Tag::Tree}, tree_iter_{std::move(delegate)} { } SortedMapIterator(const SortedMapIterator& other) : tag_(other.tag_) { switch (tag_) { case Tag::Array: new (&array_iter_) ArrayIter{other.array_iter_}; break; case Tag::Tree: new (&tree_iter_) TreeIter{other.tree_iter_}; break; } } SortedMapIterator(SortedMapIterator&& other) : tag_(other.tag_) { switch (tag_) { case Tag::Array: new (&array_iter_) ArrayIter{std::move(other.array_iter_)}; break; case Tag::Tree: new (&tree_iter_) TreeIter{std::move(other.tree_iter_)}; break; } } ~SortedMapIterator() { switch (tag_) { case Tag::Array: array_iter_.~ArrayIter(); break; case Tag::Tree: tree_iter_.~TreeIter(); break; } } SortedMapIterator& operator=(const SortedMapIterator& other) { if (tag_ == other.tag_) { switch (tag_) { case Tag::Array: array_iter_ = other.array_iter_; break; case Tag::Tree: tree_iter_ = other.tree_iter_; break; } } else { this->~SortedMapIterator(); new (this) SortedMapIterator(other); } return *this; } SortedMapIterator& operator=(SortedMapIterator&& other) { if (tag_ == other.tag_) { switch (tag_) { case Tag::Array: array_iter_ = std::move(other.array_iter_); break; case Tag::Tree: tree_iter_ = std::move(other.tree_iter_); break; } } else { this->~SortedMapIterator(); new (this) SortedMapIterator(std::move(other)); } return *this; } pointer get() const { switch (tag_) { case Tag::Array: // std::array::iterator is not guaranteed to be a bare pointer but will // be a RandomAccessIterator which does have operator*(). return &*array_iter_; case Tag::Tree: return tree_iter_.get(); } UNREACHABLE(); } reference operator*() const { return *get(); } pointer operator->() const { return get(); } SortedMapIterator& operator++() { switch (tag_) { case Tag::Array: ++array_iter_; break; case Tag::Tree: ++tree_iter_; break; } return *this; } SortedMapIterator operator++(int /*unused*/) { SortedMapIterator result = *this; ++*this; return result; } friend bool operator==(const SortedMapIterator& a, const SortedMapIterator& b) { if (a.tag_ != b.tag_) { return false; } switch (a.tag_) { case Tag::Array: return a.array_iter_ == b.array_iter_; case Tag::Tree: return a.tree_iter_ == b.tree_iter_; } UNREACHABLE(); } bool operator!=(const SortedMapIterator& b) const { return !(*this == b); } private: enum class Tag { Array, Tree, }; Tag tag_; union { ArrayIter array_iter_; TreeIter tree_iter_; }; }; } // namespace impl } // namespace immutable } // namespace firestore } // namespace firebase #endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_IMMUTABLE_SORTED_MAP_ITERATOR_H_