diff options
author | Tim Shen <timshen@google.com> | 2018-08-30 11:20:16 -0700 |
---|---|---|
committer | TensorFlower Gardener <gardener@tensorflow.org> | 2018-08-30 11:29:03 -0700 |
commit | 09f2c342c0e74834bebf8045d5e77dcef8323539 (patch) | |
tree | 3a969695f54840366629df7f39e4da7f9ac103cd /tensorflow/core/lib | |
parent | 9e12f1df3270b5e0b310645e6c3cae9fbd3f5dfc (diff) |
Remove (Mutable)ArraySlice implementation and alias them to absl::Span.
There are several API migrations happening:
* ArraySlice's sub-slice constructor => .subspan
* MutableArraySlice's container pointer constructor => absl::MakeSpan
PiperOrigin-RevId: 210946124
Diffstat (limited to 'tensorflow/core/lib')
-rw-r--r-- | tensorflow/core/lib/gtl/array_slice.h | 281 | ||||
-rw-r--r-- | tensorflow/core/lib/gtl/array_slice_internal.h | 269 | ||||
-rw-r--r-- | tensorflow/core/lib/gtl/array_slice_test.cc | 664 |
3 files changed, 5 insertions, 1209 deletions
diff --git a/tensorflow/core/lib/gtl/array_slice.h b/tensorflow/core/lib/gtl/array_slice.h index b773a65569..8f47faf89e 100644 --- a/tensorflow/core/lib/gtl/array_slice.h +++ b/tensorflow/core/lib/gtl/array_slice.h @@ -13,293 +13,22 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -// An ArraySlice<T> represents an immutable array of elements of type -// T. It has a length "length", and a base pointer "ptr", and the -// array it represents contains the elements "ptr[0] .. ptr[len-1]". -// The backing store for the array is *not* owned by the ArraySlice -// object, and clients must arrange for the backing store to remain -// live while the ArraySlice object is in use. -// -// An ArraySlice<T> is somewhat analogous to a StringPiece, but for -// array elements of type T. -// -// Implicit conversion operations are provided from types such as -// std::vector<T> and util::gtl::InlinedVector<T, N>. Note that ArraySlice -// objects constructed from types in this way may be invalidated by -// any operations that mutate the underlying vector. -// -// One common use for ArraySlice is when passing arguments to a -// routine where you want to be able to accept a variety of array -// types (e.g. a vector, a util::gtl::InlinedVector, a C-style array, -// etc.). The usual approach here is to have the client explicitly -// pass in a pointer and a length, as in: -// -// void MyRoutine(const int* elems, int N) { -// for (int i = 0; i < N; i++) { .. do something with elems[i] .. } -// } -// -// Unfortunately, this leads to ugly and error-prone code at the call site: -// -// std::vector<int> my_vector; -// MyRoutine(vector_as_array(&my_vector), my_vector.size()); -// -// util::gtl::InlinedVector<int, 4> my_inline_vector; -// MyRoutine(my_inline_vector.array(), my_inline_vector.size()); -// -// int my_array[10]; -// MyRoutine(my_array, 10); -// -// Instead, you can use an ArraySlice as the argument to the routine: -// -// void MyRoutine(ArraySlice<int> a) { -// for (int i = 0; i < a.size(); i++) { .. do something with a[i] .. } -// } -// -// This makes the call sites cleaner, for the most part: -// -// std::vector<int> my_vector; -// MyRoutine(my_vector); -// -// util::gtl::InlinedVector<int, 4> my_inline_vector; -// MyRoutine(my_inline_vector); -// -// int my_array[10]; -// MyRoutine(my_array); -// -// int* my_array = new int[10]; -// MyRoutine(gtl::ArraySlice<int>(my_array, 10)); -// -// MutableArraySlice<T> represents a mutable array of elements, and, like -// ArraySlice, does not own the backing store. The implicit constructors it -// provides allow functions not to worry about whether their mutable arguments -// refer to vectors, arrays, proto2::RepeatedFields, etc.: -// -// void MyMutatingRoutine(MutableArraySlice<int> a) { -// for (int i = 0; i < a.size(); i++) { .. mutate a[i] .. } -// } -// -// std::vector<int> my_vector; -// MyMutatingRoutine(&my_vector); -// -// int my_array[10]; -// MyMutatingRoutine(my_array); -// -// int* my_array = new int[10]; -// MyMutatingRoutine(gtl::MutableArraySlice<int>(my_array, 10)); -// -// MyProto my_proto; -// for (int i = 0; i < 10; ++i) { my_proto.add_value(i); } -// MyMutatingRoutine(my_proto.mutable_value()); - #ifndef TENSORFLOW_CORE_LIB_GTL_ARRAY_SLICE_H_ #define TENSORFLOW_CORE_LIB_GTL_ARRAY_SLICE_H_ -#include <initializer_list> -#include <type_traits> -#include <vector> - -#include "tensorflow/core/lib/gtl/array_slice_internal.h" +#include "absl/types/span.h" +// TODO(timshen): This is kept only because lots of targets transitively depend +// on it. Remove all targets' dependencies. #include "tensorflow/core/lib/gtl/inlined_vector.h" namespace tensorflow { namespace gtl { template <typename T> -class ArraySlice { - private: - typedef array_slice_internal::ArraySliceImpl<T> Impl; - - public: - typedef T value_type; - typedef typename Impl::pointer pointer; - typedef typename Impl::const_pointer const_pointer; - typedef typename Impl::reference reference; - typedef typename Impl::const_reference const_reference; - typedef typename Impl::iterator iterator; - typedef typename Impl::const_iterator const_iterator; - typedef typename Impl::reverse_iterator reverse_iterator; - typedef typename Impl::const_reverse_iterator const_reverse_iterator; - typedef typename Impl::size_type size_type; - typedef typename Impl::difference_type difference_type; - - static const size_type npos = Impl::npos; - - ArraySlice() : impl_(nullptr, 0) {} - ArraySlice(const_pointer array, size_type length) : impl_(array, length) {} - - // Implicit conversion constructors - ArraySlice(const std::vector<value_type>& v) // NOLINT(runtime/explicit) - : impl_(v.data(), v.size()) {} - - template <size_t N> - ArraySlice(const value_type (&a)[N]) // NOLINT(runtime/explicit) - : impl_(a, N) {} - - template <int N> - ArraySlice(const InlinedVector<value_type, N>& v) // NOLINT(runtime/explicit) - : impl_(v.data(), v.size()) {} - - // The constructor for any class supplying 'data() const' that returns either - // const T* or a less const-qualified version of it, and 'some_integral_type - // size() const'. proto2::RepeatedField<T>, string and (since C++11) - // std::vector<T,A> and std::array<T, N> are examples of this. See - // array_slice_internal.h for details. - template <typename V, - typename = typename Impl::template EnableIfConvertibleFrom<V>> - ArraySlice(const V& v) // NOLINT(runtime/explicit) - : impl_(v) {} - - // Implicitly constructs an ArraySlice from an initializer list. This makes it - // possible to pass a brace-enclosed initializer list to a function expecting - // an ArraySlice: - // void Process(ArraySlice<int> x); - // Process({1, 2, 3}); - // The data referenced by the initializer_list must outlive this - // ArraySlice. For example, "ArraySlice<int> s={1,2};" and "return - // ArraySlice<int>({3,4});" are errors, as the resulting ArraySlice may - // reference data that is no longer valid. - ArraySlice(std::initializer_list<value_type> v) // NOLINT(runtime/explicit) - : impl_(v.begin(), v.size()) {} - - // Substring of another ArraySlice. - // pos must be non-negative and <= x.length(). - // len must be non-negative and will be pinned to at most x.length() - pos. - // If len==npos, the substring continues till the end of x. - ArraySlice(const ArraySlice& x, size_type pos, size_type len) - : impl_(x.impl_, pos, len) {} - - const_pointer data() const { return impl_.data(); } - size_type size() const { return impl_.size(); } - size_type length() const { return size(); } - bool empty() const { return size() == 0; } - - void clear() { impl_.clear(); } - - const_reference operator[](size_type i) const { return impl_[i]; } - const_reference at(size_type i) const { return impl_.at(i); } - const_reference front() const { return impl_.front(); } - const_reference back() const { return impl_.back(); } - - const_iterator begin() const { return impl_.begin(); } - const_iterator end() const { return impl_.end(); } - const_reverse_iterator rbegin() const { return impl_.rbegin(); } - const_reverse_iterator rend() const { return impl_.rend(); } - - void remove_prefix(size_type n) { impl_.remove_prefix(n); } - void remove_suffix(size_type n) { impl_.remove_suffix(n); } - - // These relational operators have the same semantics as the - // std::vector<T> relational operators: they do deep (element-wise) - // comparisons. Array slices are equal iff their size is the same - // and all their elements are equal. - bool operator==(ArraySlice<T> other) const { return impl_ == other.impl_; } - bool operator!=(ArraySlice<T> other) const { return impl_ != other.impl_; } - - private: - Impl impl_; -}; - -// Mutable version of ArraySlice, which allows the clients to mutate the -// underlying data. It is implicitly convertible to ArraySlice since it provides -// the data() and size() methods with correct signatures. When a -// MutableArraySlice is created from a pointer to a container (as opposed to raw -// memory pointer), the pointer must not be null. -// -// A note on const-ness: "mutable" here refers to the mutability of the -// underlying data, not of the slice itself. It is perfectly reasonable to have -// a variable of type "const MutableArraySlice<T>"; this means that the bounds -// of the view on the array cannot be changed, but the underlying data in the -// array still may be modified. This is akin to a "T* const" pointer, as opposed -// to a "const T*" pointer (corresponding to a non-const ArraySlice<T>). -template <typename T> -class MutableArraySlice { - private: - typedef array_slice_internal::MutableArraySliceImpl<T> Impl; - - public: - typedef T value_type; - typedef typename Impl::pointer pointer; - typedef typename Impl::const_pointer const_pointer; - typedef typename Impl::reference reference; - typedef typename Impl::const_reference const_reference; - typedef typename Impl::iterator iterator; - typedef typename Impl::const_iterator const_iterator; - typedef typename Impl::reverse_iterator reverse_iterator; - typedef typename Impl::const_reverse_iterator const_reverse_iterator; - typedef typename Impl::size_type size_type; - typedef typename Impl::difference_type difference_type; - - static const size_type npos = Impl::npos; - - MutableArraySlice() : impl_(nullptr, 0) {} - MutableArraySlice(pointer array, size_type length) : impl_(array, length) {} - - // Implicit conversion constructors - MutableArraySlice(std::vector<value_type>* v) // NOLINT(runtime/explicit) - : impl_(v->data(), v->size()) {} - - template <size_t N> - MutableArraySlice(value_type (&a)[N]) // NOLINT(runtime/explicit) - : impl_(a, N) {} - - template <int N> - MutableArraySlice( - InlinedVector<value_type, N>* v) // NOLINT(runtime/explicit) - : impl_(v->data(), v->size()) {} - - // The constructor for any class supplying 'T* data()' or 'T* mutable_data()' - // (the former is called if both exist), and 'some_integral_type size() - // const'. proto2::RepeatedField is an example of this. Also supports string - // arguments, when T==char. The appropriate ctor is selected using SFINAE. See - // array_slice_internal.h for details. - template <typename V, - typename = typename Impl::template EnableIfConvertibleFrom<V>> - MutableArraySlice(V* v) // NOLINT(runtime/explicit) - : impl_(v) {} +using ArraySlice = absl::Span<const T>; - // Substring of another MutableArraySlice. - // pos must be non-negative and <= x.length(). - // len must be non-negative and will be pinned to at most x.length() - pos. - // If len==npos, the substring continues till the end of x. - MutableArraySlice(const MutableArraySlice& x, size_type pos, size_type len) - : impl_(x.impl_, pos, len) {} - - // Accessors. - pointer data() const { return impl_.data(); } - size_type size() const { return impl_.size(); } - size_type length() const { return size(); } - bool empty() const { return size() == 0; } - - void clear() { impl_.clear(); } - - reference operator[](size_type i) const { return impl_[i]; } - reference at(size_type i) const { return impl_.at(i); } - reference front() const { return impl_.front(); } - reference back() const { return impl_.back(); } - - iterator begin() const { return impl_.begin(); } - iterator end() const { return impl_.end(); } - reverse_iterator rbegin() const { return impl_.rbegin(); } - reverse_iterator rend() const { return impl_.rend(); } - - void remove_prefix(size_type n) { impl_.remove_prefix(n); } - void remove_suffix(size_type n) { impl_.remove_suffix(n); } - - bool operator==(ArraySlice<T> other) const { - return ArraySlice<T>(*this) == other; - } - bool operator!=(ArraySlice<T> other) const { - return ArraySlice<T>(*this) != other; - } - - private: - Impl impl_; -}; - -template <typename T> -const typename ArraySlice<T>::size_type ArraySlice<T>::npos; template <typename T> -const typename MutableArraySlice<T>::size_type MutableArraySlice<T>::npos; +using MutableArraySlice = absl::Span<T>; } // namespace gtl } // namespace tensorflow diff --git a/tensorflow/core/lib/gtl/array_slice_internal.h b/tensorflow/core/lib/gtl/array_slice_internal.h deleted file mode 100644 index 689dd8a646..0000000000 --- a/tensorflow/core/lib/gtl/array_slice_internal.h +++ /dev/null @@ -1,269 +0,0 @@ -/* Copyright 2015 The TensorFlow Authors. All Rights Reserved. - -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. -==============================================================================*/ - -// NOT FOR INCLUSION BY CLIENT CODE. This file is only to be included by -// array_slice.h. - -// Helper functions and templates for ArraySlice. - -#ifndef TENSORFLOW_LIB_GTL_ARRAY_SLICE_INTERNAL_H_ -#define TENSORFLOW_LIB_GTL_ARRAY_SLICE_INTERNAL_H_ - -#include <stddef.h> -#include <algorithm> -#include <iterator> -#include <memory> -#include <string> -#include <type_traits> -#include <utility> -#include <vector> -#include "tensorflow/core/platform/logging.h" - -namespace tensorflow { -namespace gtl { -namespace array_slice_internal { - -// Template logic for generic constructors. - -// Wrappers whose Get() delegates to the appropriate method of a container, and -// is defined when this method exists. Delegates to the const method if C is a -// const type. -struct Data { - template <typename C> - static decltype(std::declval<C>().data()) Get(C* v) { - return v->data(); - } -}; - -struct MutableData { - template <typename C> - static decltype(std::declval<C>().mutable_data()) Get(C* v) { - return v->mutable_data(); - } -}; - -struct Size { - template <typename C> - static decltype(std::declval<C>().size()) Get(C* v) { - return v->size(); - } -}; - -struct MutableStringData { - // Defined only for string. - static char* Get(string* v) { return v->empty() ? nullptr : &*v->begin(); } -}; - -// Checks whether M::Get(C*) is defined and has a return type R such that -// Checker::valid<R>()==true. -template <typename M, typename Checker, typename C> -struct HasGetHelper : public M { - private: - struct None {}; - // M::Get is selected when it is viable. Get(...) is selected otherwise. - using M::Get; - static None Get(...); - - public: - static constexpr bool HasGet() { - using Result = decltype(Get(std::declval<C*>())); - return !std::is_same<Result, None>() && Checker::template valid<Result>(); - } -}; - -// Defines HasGet() for a particular method, container, and checker. If -// HasGet()==true, provides Get() that delegates to the method. -template <typename M, typename Checker, typename C, - bool /*has_get*/ = HasGetHelper<M, Checker, C>::HasGet()> -struct Wrapper { - static constexpr bool HasGet() { return false; } -}; - -template <typename M, typename Checker, typename C> -struct Wrapper<M, Checker, C, true> { - static constexpr bool HasGet() { return true; } - static decltype(M::Get(std::declval<C*>())) Get(C* v) { return M::Get(v); } -}; - -// Type checker for a method returning an integral value. -struct SizeChecker { - template <typename R> - static constexpr bool valid() { - return std::is_integral<R>::value; - } -}; - -// Type checker for a method returning either a pointer to T or a less const -// version of that. -template <typename T> -struct DataChecker { - // We want to enable conversion from std::vector<T*> to ArraySlice<const T*> - // but - // disable conversion from std::vector<Derived> to ArraySlice<Base>. Here we - // use - // the fact that U** is convertible to Q* const* if and only if Q is the same - // type or a more cv-qualified version of U. - template <typename R> - static constexpr bool valid() { - return std::is_convertible<R*, T* const*>::value; - } -}; - -// Aliases to A if A::HasGet()==true, or to B otherwise. -template <typename A, typename B> -using FirstWithGet = typename std::conditional<A::HasGet(), A, B>::type; - -// Wraps C::data() const, returning a pointer to const data. -template <typename T, typename C> -using ContainerData = Wrapper<Data, DataChecker<const T>, const C>; - -// Wraps a method returning a pointer to mutable data. Prefers data() over -// mutable_data(), and handles strings when T==char. If data() returns a pointer -// to mutable data, it is most likely overloaded, but may also be a single -// method 'T* C::data() const' in a non-STL-compliant container. -template <typename T, typename C> -using ContainerMutableData = - FirstWithGet<Wrapper<Data, DataChecker<T>, C>, - FirstWithGet<Wrapper<MutableData, DataChecker<T>, C>, - Wrapper<MutableStringData, DataChecker<T>, C>>>; - -// Wraps C::size() const. -template <typename C> -using ContainerSize = Wrapper<Size, SizeChecker, const C>; - -// Implementation class for ArraySlice and MutableArraySlice. In the case of -// ArraySlice, T will be a const type; for MutableArraySlice, T will be a -// mutable type. -template <typename T> -class ArraySliceImplBase { - public: - typedef T* pointer; - typedef const T* const_pointer; - typedef T& reference; - typedef const T& const_reference; - typedef pointer iterator; - typedef const_pointer const_iterator; - typedef std::reverse_iterator<iterator> reverse_iterator; - typedef std::reverse_iterator<const_iterator> const_reverse_iterator; - typedef size_t size_type; - typedef ptrdiff_t difference_type; - - static const size_type npos = static_cast<size_type>(-1); - - ArraySliceImplBase(pointer array, size_type length) - : ptr_(array), length_(length) {} - - // Substring of another ArraySlice. - // pos must be non-negative and <= x.length(). - // len must be non-negative and will be pinned to at most x.length() - pos. - ArraySliceImplBase(const ArraySliceImplBase& x, size_type pos, size_type len) - : ptr_(x.ptr_ + pos), length_(std::min(x.length_ - pos, len)) {} - - // Some of the const methods below return pointers and references to mutable - // data. This is only the case in this internal class; ArraySlice and - // MutableArraySlice provide deep-constness. - - pointer data() const { return ptr_; } - size_type size() const { return length_; } - - void clear() { - ptr_ = nullptr; - length_ = 0; - } - - reference operator[](size_type i) const { return ptr_[i]; } - reference at(size_type i) const { - DCHECK_LT(i, length_); - return ptr_[i]; - } - reference front() const { - DCHECK_GT(length_, 0); - return ptr_[0]; - } - reference back() const { - DCHECK_GT(length_, 0); - return ptr_[length_ - 1]; - } - - void remove_prefix(size_type n) { - DCHECK_GE(length_, n); - ptr_ += n; - length_ -= n; - } - void remove_suffix(size_type n) { - DCHECK_GE(length_, n); - length_ -= n; - } - - iterator begin() const { return ptr_; } - iterator end() const { return ptr_ + length_; } - reverse_iterator rbegin() const { return reverse_iterator(end()); } - reverse_iterator rend() const { return reverse_iterator(begin()); } - - bool operator==(const ArraySliceImplBase& other) const { - if (size() != other.size()) return false; - if (data() == other.data()) return true; - return std::equal(data(), data() + size(), other.data()); - } - bool operator!=(const ArraySliceImplBase& other) const { - return !(*this == other); - } - - private: - pointer ptr_; - size_type length_; -}; - -template <typename T> -class ArraySliceImpl : public ArraySliceImplBase<const T> { - public: - using ArraySliceImplBase<const T>::ArraySliceImplBase; - - // Defined iff the data and size accessors for the container C have been - // defined. - template <typename C> - using EnableIfConvertibleFrom = - typename std::enable_if<ContainerData<T, C>::HasGet() && - ContainerSize<C>::HasGet()>::type; - - // Constructs from a container when EnableIfConvertibleFrom is - // defined. std::addressof handles types with overloaded operator&. - template <typename C> - explicit ArraySliceImpl(const C& v) - : ArraySliceImplBase<const T>(ContainerData<T, C>::Get(std::addressof(v)), - ContainerSize<C>::Get(std::addressof(v))) {} -}; - -template <typename T> -class MutableArraySliceImpl : public ArraySliceImplBase<T> { - public: - using ArraySliceImplBase<T>::ArraySliceImplBase; - - template <typename C> - using EnableIfConvertibleFrom = - typename std::enable_if<ContainerMutableData<T, C>::HasGet() && - ContainerSize<C>::HasGet()>::type; - - template <typename C> - explicit MutableArraySliceImpl(C* v) - : ArraySliceImplBase<T>(ContainerMutableData<T, C>::Get(v), - ContainerSize<C>::Get(v)) {} -}; - -} // namespace array_slice_internal -} // namespace gtl -} // namespace tensorflow - -#endif // TENSORFLOW_LIB_GTL_ARRAY_SLICE_INTERNAL_H_ diff --git a/tensorflow/core/lib/gtl/array_slice_test.cc b/tensorflow/core/lib/gtl/array_slice_test.cc deleted file mode 100644 index c798a488cb..0000000000 --- a/tensorflow/core/lib/gtl/array_slice_test.cc +++ /dev/null @@ -1,664 +0,0 @@ -/* Copyright 2015 The TensorFlow Authors. All Rights Reserved. - -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. -==============================================================================*/ - -#include "tensorflow/core/lib/gtl/array_slice.h" - -#include <algorithm> -#include <array> -#include <string> -#include <vector> - -#include "tensorflow/core/lib/gtl/inlined_vector.h" -#include "tensorflow/core/lib/gtl/stl_util.h" -#include "tensorflow/core/platform/macros.h" -#include "tensorflow/core/platform/test.h" -#include "tensorflow/core/platform/types.h" - -namespace tensorflow { -namespace gtl { -namespace { - -typedef ArraySlice<int> IntSlice; -typedef ArraySlice<char> CharSlice; -typedef MutableArraySlice<int> MutableIntSlice; -typedef MutableArraySlice<char> MutableCharSlice; -typedef std::vector<int> IntVec; - -// Append 0..len-1 to *v -template <typename Vector> -static void Fill(Vector* v, int len, int offset = 0) { - for (int i = 0; i < len; i++) { - v->push_back(i + offset); - } -} - -static void TestHelper(const IntSlice& vorig, const IntVec& vec) { - IntSlice other; // To test the assignment return value. - IntSlice v = other = vorig; - const int len = vec.size(); - EXPECT_EQ(v.size(), vec.size()); - - for (int i = 0; i < len; i++) { - EXPECT_EQ(v[i], vec[i]); - EXPECT_EQ(v.at(i), vec[i]); - } - EXPECT_EQ(v.begin(), gtl::vector_as_array(&vec)); - - int counter = 0; - for (IntSlice::iterator it = v.begin(); it != v.end(); ++it) { - EXPECT_EQ(counter, *it); - counter++; - } - EXPECT_EQ(counter, len); - - counter = 0; - for (IntSlice::const_iterator it = v.begin(); it != v.end(); ++it) { - EXPECT_EQ(counter, *it); - counter++; - } - EXPECT_EQ(counter, len); - - if (len > 0) { - EXPECT_EQ(0, v.front()); - EXPECT_EQ(len - 1, v.back()); - v.remove_suffix(1); - EXPECT_EQ(len - 1, v.size()); - for (size_t i = 0; i < v.size(); ++i) { - EXPECT_EQ(i, v[i]); - } - if (len > 1) { - v.remove_prefix(1); - EXPECT_EQ(len - 2, v.size()); - for (size_t i = 0; i < v.size(); ++i) { - EXPECT_EQ(i + 1, v[i]); - } - } - } -} - -// The element access test that is applicable both when MutableArraySlice is -// const and when it's not. -template <class V> -void MutableTestHelperTemplated(V v, int* ptr, const int len) { - CHECK_EQ(v.size(), len); - - for (int i = 0; i < len; i++) { - EXPECT_EQ(ptr + i, &v[i]); - EXPECT_EQ(ptr + i, &v.at(i)); - } - EXPECT_EQ(ptr, v.begin()); - EXPECT_EQ(ptr + len, v.end()); - EXPECT_EQ(ptr, v.data()); - - int counter = 0; - for (MutableIntSlice::const_iterator it = v.begin(); it != v.end(); ++it) { - EXPECT_EQ(ptr + counter, &*it); - counter++; - } - EXPECT_EQ(counter, len); - - EXPECT_EQ(len, std::distance(v.rbegin(), v.rend())); - - if (len > 0) { - EXPECT_EQ(ptr, &v.front()); - EXPECT_EQ(ptr + len - 1, &v.back()); - EXPECT_EQ(ptr + len - 1, &*v.rbegin()); - EXPECT_EQ(ptr, &*(v.rend() - 1)); - } -} - -static void MutableTestHelper(const MutableIntSlice& vorig, int* ptr, - const int len) { - // Test the data accessors both when the MutableArraySlice is declared const, - // and when it is not. - MutableTestHelperTemplated<const MutableIntSlice&>(vorig, ptr, len); - MutableTestHelperTemplated<MutableIntSlice>(vorig, ptr, len); - - MutableIntSlice other; // To test the assignment return value. - MutableIntSlice v = other = vorig; - EXPECT_EQ(ptr, v.data()); - - int counter = 0; - for (MutableIntSlice::iterator it = v.begin(); it != v.end(); ++it) { - EXPECT_EQ(ptr + counter, &*it); - counter++; - } - EXPECT_EQ(counter, len); - - if (len > 0) { - // Test that elements are assignable. - v[0] = 1; - v.front() = 2; - v.back() = 5; - *v.data() = 4; - std::fill(v.begin(), v.end(), 5); - std::fill(v.rbegin(), v.rend(), 6); - // Test size-changing methods. - v.remove_suffix(1); - EXPECT_EQ(len - 1, v.size()); - for (size_t i = 0; i < v.size(); ++i) { - EXPECT_EQ(ptr + i, &v[i]); - } - if (len > 1) { - v.remove_prefix(1); - EXPECT_EQ(len - 2, v.size()); - for (size_t i = 0; i < v.size(); ++i) { - EXPECT_EQ(ptr + i + 1, &v[i]); - } - } - } -} - -template <typename Vector> -static void TestImplicitConversion(const IntSlice& v, const Vector& vec) { - EXPECT_EQ(v.size(), vec.size()); - for (size_t i = 0; i < v.size(); i++) { - EXPECT_EQ(v[i], vec[i]); - } -} - -template <typename Vector> -static void TestImplicitConversion(const CharSlice& v, const Vector& vec) { - TestImplicitConversion(IntVec(v.begin(), v.end()), vec); -} - -static void TestImplicitConversion(const MutableIntSlice& v, const int* data, - int size) { - EXPECT_EQ(size, v.size()); - for (size_t i = 0; i < v.size(); i++) { - EXPECT_EQ(data + i, &v[i]); - } -} - -static void TestImplicitConversion(const MutableCharSlice& v, const char* data, - int size) { - EXPECT_EQ(size, v.size()); - for (size_t i = 0; i < v.size(); i++) { - EXPECT_EQ(data + i, &v[i]); - } -} -// A struct supplying the data(), mutable_data() and size() methods, just like -// e.g. proto2::RepeatedField. -struct RepeatedField { - std::vector<int> storage; - const int* data() const { return storage.data(); } - int* mutable_data() { return storage.data(); } - int size() const { return storage.size(); } -}; - -// A struct supplying the data() (both mutable and const versions) and -// size(). It also supplies mutable_data() but we test that data() is selected -// instead. -struct ContainerWithOverloads { - std::vector<int> storage; - std::vector<int> wrong_storage; - const int* data() const { return storage.data(); } - int* data() { return storage.data(); } - // MutableArraySlice should not call mutable_data(), preferring data() - // instead. - int* mutable_data() { return wrong_storage.data(); } - int size() const { return storage.size(); } -}; - -// A struct supplying data() and size() methods. -struct ContainerWithShallowConstData { - std::vector<int> storage; - int* data() const { return const_cast<int*>(storage.data()); } - int size() const { return storage.size(); } -}; - -TEST(IntSlice, Simple) { - for (int len = 0; len < 20; len++) { - IntVec vec; - Fill(&vec, len); - TestHelper(IntSlice(vec), vec); - TestHelper(IntSlice(vec.data(), vec.size()), vec); - } -} - -TEST(IntSlice, WithPosAndLen) { - IntVec vec; - Fill(&vec, 20); - for (size_t len = 0; len < vec.size(); len++) { - IntVec subvec(vec.begin(), vec.begin() + len); - TestImplicitConversion(IntSlice(vec, 0, len), subvec); - TestImplicitConversion(IntSlice(IntSlice(vec), 0, len), subvec); - } - EXPECT_EQ(0, IntSlice(vec, 0, 0).size()); - EXPECT_EQ(0, IntSlice(IntSlice(vec), 0, 0).size()); - TestImplicitConversion(IntSlice(vec, 0, IntSlice::npos), vec); -} - -TEST(IntSlice, Clear) { - for (int len = 0; len < 20; len++) { - IntVec vec; - Fill(&vec, len); - IntSlice v(vec); - v.clear(); - EXPECT_EQ(0, v.size()); - EXPECT_EQ(v.begin(), v.end()); - } -} - -TEST(IntSlice, Swap) { - for (int l1 = 0; l1 < 20; l1++) { - for (int l2 = 0; l2 < 20; l2++) { - IntVec avec, bvec; - Fill(&avec, l1); - Fill(&bvec, l2, 100); - IntSlice a(avec), b(bvec); - using std::swap; - swap(a, b); - EXPECT_EQ(l1, b.size()); - EXPECT_EQ(l2, a.size()); - for (int i = 0; i < l1; i++) { - EXPECT_EQ(i, b[i]); - } - for (int i = 0; i < l2; i++) { - EXPECT_EQ(100 + i, a[i]); - } - } - } -} - -TEST(IntSlice, ImplicitConversion) { - for (int len = 0; len < 20; len++) { - IntVec vec; - Fill(&vec, len); - IntSlice slice; - slice = vec; - TestImplicitConversion(vec, vec); - TestImplicitConversion(slice, vec); - TestImplicitConversion(IntSlice(vec.data(), vec.size()), vec); - } -} - -TEST(IntSlice, InlinedVectorConversion) { - for (int len = 0; len < 20; len++) { - InlinedVector<int, 4> inline_vec; - for (int i = 0; i < len; i++) { - inline_vec.push_back(i); - } - IntVec vec; - Fill(&vec, len); - IntSlice v = inline_vec; // Test assignment - static_cast<void>(v); - TestImplicitConversion(inline_vec, vec); - } -} - -TEST(IntSlice, StaticArrayConversion) { - int array[20]; - IntVec vec; - Fill(&vec, TF_ARRAYSIZE(array)); - std::copy(vec.begin(), vec.end(), array); - IntSlice v = array; // Test assignment - static_cast<void>(v); - TestImplicitConversion(array, vec); -} - -TEST(IntSlice, StdArrayConversion) { - std::array<int, 20> array; - IntVec vec; - Fill(&vec, array.size()); - std::copy(vec.begin(), vec.end(), array.begin()); - - // Check assignment. - { - IntSlice v = array; - static_cast<void>(v); - } - - // Check sub-slice initialization. - { - IntSlice v = {array, 10, 15}; - static_cast<void>(v); - } - - TestImplicitConversion(array, vec); -} - -// Values according to the Fill function. -static const int test_const_array[] = {0, 1, 2}; - -TEST(IntSlice, ConstStaticArrayConversion) { - IntVec vec; - Fill(&vec, TF_ARRAYSIZE(test_const_array)); - IntSlice v = test_const_array; // Test assignment - static_cast<void>(v); - TestImplicitConversion(test_const_array, vec); -} - -TEST(IntSlice, RepeatedFieldConversion) { - RepeatedField repeated_field; - IntVec vec; - Fill(&vec, 20); - repeated_field.storage = vec; - IntSlice v = repeated_field; // Test assignment - static_cast<void>(v); - TestImplicitConversion(repeated_field, vec); -} - -TEST(IntSlice, ContainerWithOverloadsConversion) { - ContainerWithOverloads container; - Fill(&container.storage, 20); - container.wrong_storage.resize(container.size()); - IntSlice v = container; // Test assignment - static_cast<void>(v); - TestImplicitConversion(container, container.storage); -} - -TEST(IntSlice, ContainerWithShallowConstDataConversion) { - ContainerWithShallowConstData container; - Fill(&container.storage, 20); - IntSlice v = container; // Test assignment - static_cast<void>(v); - TestImplicitConversion(container, container.storage); -} - -TEST(IntSlice, MutableIntSliceConversion) { - IntVec vec(20); - IntSlice slice = MutableIntSlice(&vec); - EXPECT_EQ(vec.size(), slice.size()); - EXPECT_EQ(vec.data(), slice.data()); -} - -TEST(IntSlice, Equality) { - IntVec vec1(20); - IntVec vec2(20); - // These two slices are from different vectors, but have the same - // size and have the same elements (right now). They should - // compare equal. - const IntSlice from1(vec1); - const IntSlice from2(vec2); - EXPECT_EQ(from1, from1); - EXPECT_EQ(from1, from2); - - // This verifies that MutableArraySlices can be compared freely with - // ArraySlices. - const MutableIntSlice mutable_from1(&vec1); - const MutableIntSlice mutable_from2(&vec2); - EXPECT_EQ(from1, mutable_from1); - EXPECT_EQ(mutable_from1, from1); - EXPECT_EQ(mutable_from1, mutable_from2); - EXPECT_EQ(mutable_from2, mutable_from1); - - // With a different size, the array slices should not be equal. - EXPECT_NE(from1, IntSlice(from1, 0, from1.size() - 1)); - - // With different contents, the array slices should not be equal. - ++vec2.back(); - EXPECT_NE(from1, from2); -} - -// Compile-asserts that the argument has the expected type. -template <typename Expected, typename T> -void CheckType(const T& value) { - ::testing::StaticAssertTypeEq<Expected, T>(); -} - -TEST(IntSlice, ExposesContainerTypesAndConsts) { - IntSlice slice; - const IntSlice const_slice; - CheckType<IntSlice::iterator>(slice.begin()); - CheckType<IntSlice::const_iterator>(const_slice.end()); - CheckType<IntSlice::const_reverse_iterator>(const_slice.rbegin()); - CheckType<IntSlice::reverse_iterator>(slice.rend()); - ::testing::StaticAssertTypeEq<int, IntSlice::value_type>(); - ::testing::StaticAssertTypeEq<const int*, IntSlice::pointer>(); - ::testing::StaticAssertTypeEq<const int&, IntSlice::const_reference>(); - EXPECT_EQ(static_cast<IntSlice::size_type>(-1), IntSlice::npos); -} - -void TestEmpty(IntSlice slice) { ASSERT_TRUE(slice.empty()); } - -void TestRange(IntSlice slice, int from, int to) { - ASSERT_EQ(to - from + 1, slice.size()); - for (size_t i = 0; i < slice.size(); ++i) { - EXPECT_EQ(from + i, slice[i]); - } -} - -TEST(IntSlice, InitializerListConversion) { - TestEmpty({}); - TestRange({1}, 1, 1); - TestRange({10, 11, 12, 13}, 10, 13); -} - -TEST(CharSlice, StringConversion) { - IntVec vec; - Fill(&vec, 20); - string str(vec.begin(), vec.end()); - CharSlice v = str; // Test assignment - static_cast<void>(v); - TestImplicitConversion(str, vec); -} - -TEST(IntPtrSlice, ConstConversion) { - int one = 1; - int two = 2; - std::vector<int*> vec; - vec.push_back(&one); - vec.push_back(&two); - ArraySlice<const int*> v = vec; - ASSERT_EQ(2, v.size()); - EXPECT_EQ(&one, v[0]); - EXPECT_EQ(&two, v[1]); -} - -TEST(MutableIntSlice, Simple) { - for (int len = 0; len < 20; len++) { - IntVec vec(len); - MutableTestHelper(MutableIntSlice(&vec), vec.data(), len); - MutableTestHelper(MutableIntSlice(vec.data(), vec.size()), vec.data(), len); - } -} - -TEST(MutableIntSlice, WithPosAndLen) { - IntVec vec(20); - for (size_t len = 0; len < vec.size(); len++) { - TestImplicitConversion(MutableIntSlice(&vec, 0, len), vec.data(), len); - TestImplicitConversion(MutableIntSlice(MutableIntSlice(&vec), 0, len), - vec.data(), len); - } - EXPECT_EQ(0, MutableIntSlice(&vec, 0, 0).size()); - EXPECT_EQ(0, MutableIntSlice(MutableIntSlice(&vec), 0, 0).size()); - TestImplicitConversion(MutableIntSlice(&vec, 0, MutableIntSlice::npos), - vec.data(), vec.size()); -} - -TEST(MutableIntSlice, Clear) { - for (int len = 0; len < 20; len++) { - IntVec vec(len); - MutableIntSlice v(&vec); - v.clear(); - EXPECT_EQ(0, v.size()); - EXPECT_EQ(v.begin(), v.end()); - } -} - -TEST(MutableIntSlice, Swap) { - for (int l1 = 0; l1 < 20; l1++) { - for (int l2 = 0; l2 < 20; l2++) { - IntVec avec(l1), bvec(l2); - MutableIntSlice a(&avec), b(&bvec); - using std::swap; - swap(a, b); - EXPECT_EQ(l1, b.size()); - EXPECT_EQ(l2, a.size()); - for (int i = 0; i < l1; i++) { - EXPECT_EQ(&avec[i], &b[i]); - } - for (int i = 0; i < l2; i++) { - EXPECT_EQ(&bvec[i], &a[i]); - } - } - } -} - -TEST(MutableIntSlice, ImplicitConversion) { - for (int len = 0; len < 20; len++) { - IntVec vec(len); - MutableIntSlice slice; - slice = &vec; - TestImplicitConversion(&vec, vec.data(), len); - TestImplicitConversion(slice, vec.data(), len); - TestImplicitConversion(MutableIntSlice(vec.data(), vec.size()), vec.data(), - len); - } -} - -TEST(MutableIntSlice, InlinedVectorConversion) { - for (int len = 0; len < 20; len++) { - InlinedVector<int, 4> inline_vec; - for (int i = 0; i < len; i++) { - inline_vec.push_back(i); - } - MutableIntSlice v = &inline_vec; // Test assignment - static_cast<void>(v); - TestImplicitConversion(&inline_vec, inline_vec.data(), inline_vec.size()); - } -} - -TEST(MutableIntSlice, StaticArrayConversion) { - int array[20]; - MutableIntSlice v = array; // Test assignment - static_cast<void>(v); - TestImplicitConversion(array, array, TF_ARRAYSIZE(array)); -} - -TEST(MutableIntSlice, StdArrayConversion) { - std::array<int, 20> array; - - // Check assignment. - { - MutableIntSlice v = &array; - static_cast<void>(v); - } - - // Check sub-slice initialization. - { - MutableIntSlice v = {&array, 10, 15}; - static_cast<void>(v); - } - - TestImplicitConversion(&array, &array[0], array.size()); -} - -TEST(MutableIntSlice, RepeatedFieldConversion) { - RepeatedField repeated_field; - Fill(&repeated_field.storage, 20); - MutableIntSlice v = &repeated_field; // Test assignment - static_cast<void>(v); - TestImplicitConversion(&repeated_field, repeated_field.storage.data(), - repeated_field.storage.size()); -} - -TEST(MutableIntSlice, ContainerWithOverloadsConversion) { - ContainerWithOverloads container; - Fill(&container.storage, 20); - container.wrong_storage.resize(container.size()); - MutableIntSlice v = &container; // Test assignment - static_cast<void>(v); - TestImplicitConversion(&container, container.storage.data(), - container.storage.size()); -} - -TEST(MutableIntSlice, ContainerWithShallowConstDataConversion) { - ContainerWithShallowConstData container; - Fill(&container.storage, 20); - MutableIntSlice v = &container; // Test assignment - static_cast<void>(v); - TestImplicitConversion(&container, container.storage.data(), - container.storage.size()); -} - -TEST(MutableIntSlice, TypedefsAndConstants) { - ::testing::StaticAssertTypeEq<int, MutableIntSlice::value_type>(); - ::testing::StaticAssertTypeEq<int*, MutableIntSlice::pointer>(); - ::testing::StaticAssertTypeEq<const int*, MutableIntSlice::const_pointer>(); - ::testing::StaticAssertTypeEq<int&, MutableIntSlice::reference>(); - ::testing::StaticAssertTypeEq<const int&, MutableIntSlice::const_reference>(); - - EXPECT_EQ(static_cast<MutableIntSlice::size_type>(-1), MutableIntSlice::npos); -} - -TEST(MutableIntSlice, IteratorsAndReferences) { - auto accept_pointer = [](int* x) {}; - auto accept_reference = [](int& x) {}; - auto accept_iterator = [](MutableIntSlice::iterator x) {}; - auto accept_reverse_iterator = [](MutableIntSlice::reverse_iterator x) {}; - - int a[1]; - MutableIntSlice s = a; - - accept_pointer(s.data()); - accept_iterator(s.begin()); - accept_iterator(s.end()); - accept_reverse_iterator(s.rbegin()); - accept_reverse_iterator(s.rend()); - - accept_reference(s[0]); - accept_reference(s.at(0)); - accept_reference(s.front()); - accept_reference(s.back()); -} - -TEST(MutableIntSlice, IteratorsAndReferences_Const) { - auto accept_pointer = [](int* x) {}; - auto accept_reference = [](int& x) {}; - auto accept_iterator = [](MutableIntSlice::iterator x) {}; - auto accept_reverse_iterator = [](MutableIntSlice::reverse_iterator x) {}; - - int a[1]; - const MutableIntSlice s = a; - - accept_pointer(s.data()); - accept_iterator(s.begin()); - accept_iterator(s.end()); - accept_reverse_iterator(s.rbegin()); - accept_reverse_iterator(s.rend()); - - accept_reference(s[0]); - accept_reference(s.at(0)); - accept_reference(s.front()); - accept_reference(s.back()); -} - -bool TestMutableOverload(MutableIntSlice slice) { return false; } - -bool TestMutableOverload(MutableCharSlice slice) { return true; } - -TEST(MutableCharSlice, StringConversion) { - for (int len = 0; len < 20; len++) { - string str(len, '\0'); - MutableCharSlice v = &str; // Test assignment - static_cast<void>(v); - TestImplicitConversion(v, str.data(), str.size()); - } - // Verify that only the correct overload is feasible. Note that this would - // fail if the string ctor was declared simply as MutableArraySlice(string*), - // since in that case both overloads would be feasible. - string str; - EXPECT_TRUE(TestMutableOverload(&str)); - - // Avoid warning "unused function 'TestMutableOverload'" - int a[1]; - EXPECT_FALSE(TestMutableOverload(a)); -} - -} // namespace -} // namespace gtl -} // namespace tensorflow |