diff options
author | Gil <mcg@google.com> | 2018-01-29 08:38:32 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-01-29 08:38:32 -0800 |
commit | 5a280ca1d62ac3750bf590328e3d08e0e3342cfc (patch) | |
tree | dd5733c418293e4100ad50bb899c36c9042af6d2 /Firestore/core/src/firebase/firestore/util | |
parent | 63a380ba33b59b571d7abd7b4565b5e63eb4680d (diff) |
Import iterator_adaptors from google3 (#718)
* Import iterator_adapters from google3
* Remove -Wconversion which is annoyingly hard to satisfy
* Strip dependency on absl_container from iterator_adapters_test
* Format and lint iterator_adaptors
* More flexible copyright checking in Travis
Diffstat (limited to 'Firestore/core/src/firebase/firestore/util')
-rw-r--r-- | Firestore/core/src/firebase/firestore/util/CMakeLists.txt | 1 | ||||
-rw-r--r-- | Firestore/core/src/firebase/firestore/util/iterator_adaptors.h | 812 |
2 files changed, 813 insertions, 0 deletions
diff --git a/Firestore/core/src/firebase/firestore/util/CMakeLists.txt b/Firestore/core/src/firebase/firestore/util/CMakeLists.txt index b763a63..3e32111 100644 --- a/Firestore/core/src/firebase/firestore/util/CMakeLists.txt +++ b/Firestore/core/src/firebase/firestore/util/CMakeLists.txt @@ -113,6 +113,7 @@ cc_library( comparison.h config.h firebase_assert.h + iterator_adaptors.h log.h ordered_code.cc ordered_code.h diff --git a/Firestore/core/src/firebase/firestore/util/iterator_adaptors.h b/Firestore/core/src/firebase/firestore/util/iterator_adaptors.h new file mode 100644 index 0000000..042fd72 --- /dev/null +++ b/Firestore/core/src/firebase/firestore/util/iterator_adaptors.h @@ -0,0 +1,812 @@ +/* + * Copyright 2005, 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. + */ + +// Provides some iterator adaptors and views. + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_ITERATOR_ADAPTORS_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_ITERATOR_ADAPTORS_H_ + +#include <iterator> +#include <memory> +#include <type_traits> + +#include "absl/base/port.h" +#include "absl/meta/type_traits.h" + +namespace firebase { +namespace firestore { +namespace util { + +namespace internal { + +// value == true if Iter prohibits modification of its pointees. +template <typename Iter> +struct IsConstIter + : std::is_const<typename std::remove_reference< + typename std::iterator_traits<Iter>::reference>::type> {}; + +template <bool Cond, typename T> +struct AddConstIf : std::conditional<Cond, const T, T> {}; + +// SynthIterTraits propagates the constness of the 'BaseIter' iterator +// type to its own exported 'pointer' and 'reference' typedefs. +template <typename BaseIter, typename Val> +struct SynthIterTraits : std::iterator_traits<BaseIter> { + private: + static constexpr bool kIterConst = IsConstIter<BaseIter>::value; + + public: + using value_type = typename std::remove_cv<Val>::type; + using pointer = typename AddConstIf<kIterConst, Val>::type*; + using reference = typename AddConstIf<kIterConst, Val>::type&; +}; + +// PointeeSynthIterTraits is similar to SynthIterTraits, but the 'Ptr' +// parameter is a pointer-like type, and value_type is the pointee. +template <typename BaseIter, typename Ptr> +struct PointeeSynthIterTraits : std::iterator_traits<BaseIter> { + private: + static constexpr bool kIterConst = IsConstIter<BaseIter>::value; + + public: + using value_type = typename std::pointer_traits<Ptr>::element_type; + using pointer = typename AddConstIf<kIterConst, value_type>::type*; + using reference = typename AddConstIf<kIterConst, value_type>::type&; +}; + +// CRTP base class for generating iterator adaptors. +// 'Sub' is the derived type, and 'Policy' encodes +// all of the behavior for the adaptor. +// Policy requirements: +// - type 'underlying_iterator': the underlying iterator type. +// - type 'adapted_traits': the traits of the adaptor. +// - static 'Extract(underlying_iterator)': convert iterator to reference. +// +template <typename Sub, typename Policy> +class IteratorAdaptorBase { + private: + // Everything needed from the Policy type is expressed in this section. + using Iterator = typename Policy::underlying_iterator; + using OutTraits = typename Policy::adapted_traits; + static typename OutTraits::reference Extract(const Iterator& it) { + return Policy::Extract(it); + } + + public: + using iterator_category = typename OutTraits::iterator_category; + using value_type = typename OutTraits::value_type; + using pointer = typename OutTraits::pointer; + using reference = typename OutTraits::reference; + using difference_type = typename OutTraits::difference_type; + + IteratorAdaptorBase() : it_() { + } + // NOLINTNEXTLINE(runtime/explicit) + IteratorAdaptorBase(Iterator it) : it_(it) { + } + + Sub& sub() { + return static_cast<Sub&>(*this); + } + const Sub& sub() const { + return static_cast<const Sub&>(*this); + } + + const Iterator& base() const { + return it_; + } + + reference get() const { + return Extract(base()); + } + reference operator*() const { + return get(); + } + pointer operator->() const { + return &get(); + } + reference operator[](difference_type d) const { + return *(sub() + d); + } + + Sub& operator++() { + ++it_; + return sub(); + } + Sub& operator--() { + --it_; + return sub(); + } + Sub operator++(int /*unused*/) { + return it_++; + } + Sub operator--(int /*unused*/) { + return it_--; + } + + Sub& operator+=(difference_type d) { + it_ += d; + return sub(); + } + Sub& operator-=(difference_type d) { + it_ -= d; + return sub(); + } + + bool operator==(Sub b) const { + return base() == b.base(); + } + bool operator!=(Sub b) const { + return base() != b.base(); + } + // These shouldn't be necessary, as implicit conversion from 'Iterator' + // should be enough to make such comparisons work. + bool operator==(Iterator b) const { + return *this == Sub(b); + } + bool operator!=(Iterator b) const { + return *this != Sub(b); + } + + friend Sub operator+(Sub it, difference_type d) { + return it.base() + d; + } + friend Sub operator+(difference_type d, Sub it) { + return it + d; + } + friend Sub operator-(Sub it, difference_type d) { + return it.base() - d; + } + friend difference_type operator-(Sub a, Sub b) { + return a.base() - b.base(); + } + + friend bool operator<(Sub a, Sub b) { + return a.base() < b.base(); + } + friend bool operator>(Sub a, Sub b) { + return a.base() > b.base(); + } + friend bool operator<=(Sub a, Sub b) { + return a.base() <= b.base(); + } + friend bool operator>=(Sub a, Sub b) { + return a.base() >= b.base(); + } + + private: + Iterator it_; +}; + +template <typename It> +struct FirstPolicy { + using underlying_iterator = It; + using adapted_traits = + SynthIterTraits<underlying_iterator, + typename std::iterator_traits< + underlying_iterator>::value_type::first_type>; + static typename adapted_traits::reference Extract( + const underlying_iterator& it) { + return it->first; + } +}; + +template <typename It> +struct SecondPolicy { + using underlying_iterator = It; + using adapted_traits = + SynthIterTraits<underlying_iterator, + typename std::iterator_traits< + underlying_iterator>::value_type::second_type>; + static typename adapted_traits::reference Extract( + const underlying_iterator& it) { + return it->second; + } +}; + +template <typename It> +struct SecondPtrPolicy { + using underlying_iterator = It; + using adapted_traits = + PointeeSynthIterTraits<underlying_iterator, + typename std::iterator_traits< + underlying_iterator>::value_type::second_type>; + static typename adapted_traits::reference Extract( + const underlying_iterator& it) { + return *it->second; + } +}; + +template <typename It> +struct PtrPolicy { + using underlying_iterator = It; + using adapted_traits = PointeeSynthIterTraits< + underlying_iterator, + typename std::iterator_traits<underlying_iterator>::value_type>; + static typename adapted_traits::reference Extract( + const underlying_iterator& it) { + return **it; + } +}; + +} // namespace internal + +// In both iterator adaptors, iterator_first<> and iterator_second<>, +// we build a new iterator based on a parameterized iterator type, "It". +// The value type, "Val" is determined by "It::value_type::first" or +// "It::value_type::second", respectively. + +// iterator_first<> adapts an iterator to return the first value of a pair. +// It is equivalent to calling it->first on every value. +// Example: +// +// hash_map<string, int> values; +// values["foo"] = 1; +// values["bar"] = 2; +// for (iterator_first<hash_map<string, int>::iterator> x = values.begin(); +// x != values.end(); ++x) { +// printf("%s", x->c_str()); +// } +template <typename It> +struct iterator_first + : internal::IteratorAdaptorBase<iterator_first<It>, + internal::FirstPolicy<It>> { + using Base = internal::IteratorAdaptorBase<iterator_first<It>, + internal::FirstPolicy<It>>; + iterator_first() { + } + iterator_first(It it) // NOLINT(runtime/explicit) + : Base(it) { + } + template <typename It2> + iterator_first(iterator_first<It2> o) // NOLINT(runtime/explicit) + : Base(o.base()) { + } +}; + +template <typename It> +iterator_first<It> make_iterator_first(It it) { + return iterator_first<It>(it); +} + +// iterator_second<> adapts an iterator to return the second value of a pair. +// It is equivalent to calling it->second on every value. +// Example: +// +// hash_map<string, int> values; +// values["foo"] = 1; +// values["bar"] = 2; +// for (iterator_second<hash_map<string, int>::iterator> x = values.begin(); +// x != values.end(); ++x) { +// int v = *x; +// printf("%d", v); +// } +template <typename It> +struct iterator_second + : internal::IteratorAdaptorBase<iterator_second<It>, + internal::SecondPolicy<It>> { + using Base = internal::IteratorAdaptorBase<iterator_second<It>, + internal::SecondPolicy<It>>; + iterator_second() { + } + iterator_second(It it) // NOLINT(runtime/explicit) + : Base(it) { + } + template <typename It2> + iterator_second(iterator_second<It2> o) // NOLINT(runtime/explicit) + : Base(o.base()) { + } +}; + +template <typename It> +iterator_second<It> make_iterator_second(It it) { + return iterator_second<It>(it); +} + +// iterator_second_ptr<> adapts an iterator to return the dereferenced second +// value of a pair. +// It is equivalent to calling *it->second on every value. +// The same result can be achieved by composition +// iterator_ptr<iterator_second<> > +// Can be used with maps where values are regular pointers or pointers wrapped +// into linked_ptr. This iterator adaptor can be used by classes to give their +// clients access to some of their internal data without exposing too much of +// it. +// +// Example: +// class MyClass { +// public: +// MyClass(const string& s); +// string DebugString() const; +// }; +// typedef hash_map<string, linked_ptr<MyClass> > MyMap; +// typedef iterator_second_ptr<MyMap::iterator> MyMapValuesIterator; +// MyMap values; +// values["foo"].reset(new MyClass("foo")); +// values["bar"].reset(new MyClass("bar")); +// for (MyMapValuesIterator it = values.begin(); it != values.end(); ++it) { +// printf("%s", it->DebugString().c_str()); +// } +template <typename It> +struct iterator_second_ptr + : internal::IteratorAdaptorBase<iterator_second_ptr<It>, + internal::SecondPtrPolicy<It>> { + using Base = internal::IteratorAdaptorBase<iterator_second_ptr<It>, + internal::SecondPtrPolicy<It>>; + iterator_second_ptr() { + } + iterator_second_ptr(It it) // NOLINT(runtime/explicit) + : Base(it) { + } + template <typename It2> + iterator_second_ptr(iterator_second_ptr<It2> o) // NOLINT(runtime/explicit) + : Base(o.base()) { + } +}; + +template <typename It> +iterator_second_ptr<It> make_iterator_second_ptr(It it) { + return iterator_second_ptr<It>(it); +} + +// iterator_ptr<> adapts an iterator to return the dereferenced value. +// With this adaptor you can write *it instead of **it, or it->something instead +// of (*it)->something. +// Can be used with vectors and lists where values are regular pointers +// or pointers wrapped into linked_ptr. This iterator adaptor can be used by +// classes to give their clients access to some of their internal data without +// exposing too much of it. +// +// Example: +// class MyClass { +// public: +// MyClass(const string& s); +// string DebugString() const; +// }; +// typedef vector<linked_ptr<MyClass> > MyVector; +// typedef iterator_ptr<MyVector::iterator> DereferencingIterator; +// MyVector values; +// values.push_back(make_linked_ptr(new MyClass("foo"))); +// values.push_back(make_linked_ptr(new MyClass("bar"))); +// for (DereferencingIterator it = values.begin(); it != values.end(); ++it) { +// printf("%s", it->DebugString().c_str()); +// } +// +// Without iterator_ptr you would have to do (*it)->DebugString() +template <typename It, typename Ptr /* ignored */ = void> +struct iterator_ptr : internal::IteratorAdaptorBase<iterator_ptr<It, Ptr>, + internal::PtrPolicy<It>> { + using Base = internal::IteratorAdaptorBase<iterator_ptr<It, Ptr>, + internal::PtrPolicy<It>>; + iterator_ptr() { + } + iterator_ptr(It it) // NOLINT(runtime/explicit) + : Base(it) { + } + template <typename It2> + iterator_ptr(iterator_ptr<It2> o) // NOLINT(runtime/explicit) + : Base(o.base()) { + } +}; + +template <typename It> +iterator_ptr<It> make_iterator_ptr(It it) { + return iterator_ptr<It>(it); +} + +namespace internal { + +// Template that uses SFINAE to inspect Container abilities: +// . Set has_size_type true, iff T::size_type is defined +// . Define size_type as T::size_type if defined, or size_t otherwise +template <typename C> +struct container_traits { + private: + // Test for availability of C::size_type. + template <typename U, typename = void> + struct test_size_type : std::false_type {}; + template <typename U> + struct test_size_type<U, absl::void_t<typename U::size_type>> + : std::true_type {}; + + // Conditional provisioning of a size_type which defaults to size_t. + template <bool Cond, typename U = void> + struct size_type_def { + using type = typename U::size_type; + }; + template <typename U> + struct size_type_def<false, U> { + using type = size_t; + }; + + public: + // Determine whether C::size_type is available. + static const bool has_size_type = test_size_type<C>::value; + + // Provide size_type as either C::size_type if available, or as size_t. + using size_type = typename size_type_def<has_size_type, C>::type; +}; + +template <typename C> +struct IterGenerator { + using container_type = C; + using iterator = typename C::iterator; + using const_iterator = typename C::const_iterator; + + static iterator begin(container_type& c) { // NOLINT(runtime/references) + return c.begin(); + } + static iterator end(container_type& c) { // NOLINT(runtime/references) + return c.end(); + } + static const_iterator begin(const container_type& c) { + return c.begin(); + } + static const_iterator end(const container_type& c) { + return c.end(); + } +}; + +template <typename SubIterGenerator> +struct ReversingIterGeneratorAdaptor { + using container_type = typename SubIterGenerator::container_type; + using iterator = std::reverse_iterator<typename SubIterGenerator::iterator>; + using const_iterator = + std::reverse_iterator<typename SubIterGenerator::const_iterator>; + + static iterator begin(container_type& c) { // NOLINT(runtime/references) + return iterator(SubIterGenerator::end(c)); + } + static iterator end(container_type& c) { // NOLINT(runtime/references) + return iterator(SubIterGenerator::begin(c)); + } + static const_iterator begin(const container_type& c) { + return const_iterator(SubIterGenerator::end(c)); + } + static const_iterator end(const container_type& c) { + return const_iterator(SubIterGenerator::begin(c)); + } +}; + +// C: the container type +// Iter: the type of mutable iterator to generate +// ConstIter: the type of constant iterator to generate +// IterGenerator: a policy type that returns native iterators from a C +template <typename C, + typename Iter, + typename ConstIter, + typename IterGenerator = internal::IterGenerator<C>> +class iterator_view_helper { + public: + using container_type = C; + using iterator = Iter; + using const_iterator = ConstIter; + using value_type = typename std::iterator_traits<iterator>::value_type; + using size_type = typename internal::container_traits<C>::size_type; + + explicit iterator_view_helper( + container_type& c) // NOLINT(runtime/references) + : c_(&c) { + } + + iterator begin() { + return iterator(IterGenerator::begin(container())); + } + iterator end() { + return iterator(IterGenerator::end(container())); + } + const_iterator begin() const { + return const_iterator(IterGenerator::begin(container())); + } + const_iterator end() const { + return const_iterator(IterGenerator::end(container())); + } + const_iterator cbegin() const { + return begin(); + } + const_iterator cend() const { + return end(); + } + const container_type& container() const { + return *c_; + } + container_type& container() { + return *c_; + } + + bool empty() const { + return begin() == end(); + } + size_type size() const { + return c_->size(); + } + + private: + container_type* c_; +}; + +template <typename C, + typename ConstIter, + typename IterGenerator = internal::IterGenerator<C>> +class const_iterator_view_helper { + public: + using container_type = C; + using const_iterator = ConstIter; + using value_type = typename std::iterator_traits<const_iterator>::value_type; + using size_type = typename internal::container_traits<C>::size_type; + + explicit const_iterator_view_helper(const container_type& c) : c_(&c) { + } + + // Allow implicit conversion from the corresponding iterator_view_helper. + // Erring on the side of constness should be allowed. E.g.: + // MyMap m; + // key_view_type<MyMap>::type keys = key_view(m); // ok + // key_view_type<const MyMap>::type const_keys = key_view(m); // ok + template <typename Iter> + const_iterator_view_helper(const iterator_view_helper<container_type, + Iter, + const_iterator, + IterGenerator>& v) + : c_(&v.container()) { + } + + const_iterator begin() const { + return const_iterator(IterGenerator::begin(container())); + } + const_iterator end() const { + return const_iterator(IterGenerator::end(container())); + } + const_iterator cbegin() const { + return begin(); + } + const_iterator cend() const { + return end(); + } + const container_type& container() const { + return *c_; + } + + bool empty() const { + return begin() == end(); + } + size_type size() const { + return c_->size(); + } + + private: + const container_type* c_; +}; + +} // namespace internal + +// Note: The views like value_view, key_view should be in gtl namespace. +// Currently there are lot of callers that reference the methods in the global +// namespace. +// +// Traits to provide a typedef abstraction for the return value +// of the key_view() and value_view() functions, such that +// they can be declared as: +// +// template <typename C> key_view_t<C> key_view(C& c); +// template <typename C> value_view_t<C> value_view(C& c); +// +// This abstraction allows callers of these functions to use readable +// type names, and allows the maintainers of iterator_adaptors.h to +// change the return types if needed without updating callers. + +template <typename C> +struct key_view_type { + using type = internal::iterator_view_helper< + C, + iterator_first<typename C::iterator>, + iterator_first<typename C::const_iterator>>; +}; + +template <typename C> +struct key_view_type<const C> { + using type = internal:: + const_iterator_view_helper<C, iterator_first<typename C::const_iterator>>; +}; + +template <typename C> +struct value_view_type { + using type = internal::iterator_view_helper< + C, + iterator_second<typename C::iterator>, + iterator_second<typename C::const_iterator>>; +}; + +template <typename C> +struct value_view_type<const C> { + using type = internal::const_iterator_view_helper< + C, + iterator_second<typename C::const_iterator>>; +}; + +// The key_view and value_view functions provide pretty ways to iterate either +// the keys or the values of a map using range based for loops. +// +// Example: +// hash_map<int, string> my_map; +// ... +// for (string val : value_view(my_map)) { +// ... +// } +// +// Note: If you pass a temporary container to key_view or value_view, be careful +// that the temporary container outlives the wrapper view to avoid dangling +// references. +// This is fine: PublishAll(value_view(Make()); +// This is not: for (const auto& v : value_view(Make())) Publish(v); + +template <typename C> +typename key_view_type<C>::type key_view( + C& map) { // NOLINT(runtime/references) + return typename key_view_type<C>::type(map); +} + +template <typename C> +typename key_view_type<const C>::type key_view(const C& map) { + return typename key_view_type<const C>::type(map); +} + +template <typename C> +typename value_view_type<C>::type value_view( + C& map) { // NOLINT(runtime/references) + return typename value_view_type<C>::type(map); +} + +template <typename C> +typename value_view_type<const C>::type value_view(const C& map) { + return typename value_view_type<const C>::type(map); +} + +// Abstract container view that dereferences the pointer-like .second member +// of a container's std::pair elements, such as the elements of std::map<K,V*> +// or of std::vector<std::pair<K,V*>>. +// +// Example: +// map<int, string*> elements; +// for (const string& element : deref_second_view(elements)) { +// ... +// } +// +// Note: If you pass a temporary container to deref_second_view, be careful that +// the temporary container outlives the deref_second_view to avoid dangling +// references. +// This is fine: PublishAll(deref_second_view(Make()); +// This is not: for (const auto& v : deref_second_view(Make())) { +// Publish(v); +// } + +template <typename C> +struct deref_second_view_type { + using type = internal::iterator_view_helper< + C, + iterator_second_ptr<typename C::iterator>, + iterator_second_ptr<typename C::const_iterator>>; +}; + +template <typename C> +struct deref_second_view_type<const C> { + using type = internal::const_iterator_view_helper< + C, + iterator_second_ptr<typename C::const_iterator>>; +}; + +template <typename C> +typename deref_second_view_type<C>::type deref_second_view( + C& map) { // NOLINT(runtime/references) + return typename deref_second_view_type<C>::type(map); +} + +template <typename C> +typename deref_second_view_type<const C>::type deref_second_view(const C& map) { + return typename deref_second_view_type<const C>::type(map); +} + +// Abstract container view that dereferences pointer elements. +// +// Example: +// vector<string*> elements; +// for (const string& element : deref_view(elements)) { +// ... +// } +// +// Note: If you pass a temporary container to deref_view, be careful that the +// temporary container outlives the deref_view to avoid dangling references. +// This is fine: PublishAll(deref_view(Make()); +// This is not: for (const auto& v : deref_view(Make())) { Publish(v); } + +template <typename C> +struct deref_view_type { + using type = + internal::iterator_view_helper<C, + iterator_ptr<typename C::iterator>, + iterator_ptr<typename C::const_iterator>>; +}; + +template <typename C> +struct deref_view_type<const C> { + using type = internal:: + const_iterator_view_helper<C, iterator_ptr<typename C::const_iterator>>; +}; + +template <typename C> +typename deref_view_type<C>::type deref_view( + C& c) { // NOLINT(runtime/references) + return typename deref_view_type<C>::type(c); +} + +template <typename C> +typename deref_view_type<const C>::type deref_view(const C& c) { + return typename deref_view_type<const C>::type(c); +} + +// Abstract container view that iterates backwards. +// +// Example: +// vector<string> elements; +// for (const string& element : reversed_view(elements)) { +// ... +// } +// +// Note: If you pass a temporary container to reversed_view_type, be careful +// that the temporary container outlives the reversed_view to avoid dangling +// references. This is fine: PublishAll(reversed_view(Make()); +// This is not: for (const auto& v : reversed_view(Make())) { Publish(v); } + +template <typename C> +struct reversed_view_type { + private: + using policy = + internal::ReversingIterGeneratorAdaptor<internal::IterGenerator<C>>; + + public: + using type = internal::iterator_view_helper<C, + typename policy::iterator, + typename policy::const_iterator, + policy>; +}; + +template <typename C> +struct reversed_view_type<const C> { + private: + using policy = + internal::ReversingIterGeneratorAdaptor<internal::IterGenerator<C>>; + + public: + using type = internal:: + const_iterator_view_helper<C, typename policy::const_iterator, policy>; +}; + +template <typename C> +typename reversed_view_type<C>::type reversed_view( + C& c) { // NOLINT(runtime/references) + return typename reversed_view_type<C>::type(c); +} + +template <typename C> +typename reversed_view_type<const C>::type reversed_view(const C& c) { + return typename reversed_view_type<const C>::type(c); +} + +} // namespace util +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_ITERATOR_ADAPTORS_H_ |