• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2015 The TensorFlow Authors. All Rights Reserved.
2 
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6 
7     http://www.apache.org/licenses/LICENSE-2.0
8 
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15 
16 // NOT FOR INCLUSION BY CLIENT CODE. This file is only to be included by
17 // array_slice.h.
18 
19 // Helper functions and templates for ArraySlice.
20 
21 #ifndef TENSORFLOW_LIB_GTL_ARRAY_SLICE_INTERNAL_H_
22 #define TENSORFLOW_LIB_GTL_ARRAY_SLICE_INTERNAL_H_
23 
24 #include <stddef.h>
25 #include <algorithm>
26 #include <iterator>
27 #include <memory>
28 #include <string>
29 #include <type_traits>
30 #include <utility>
31 #include <vector>
32 #include "tensorflow/core/platform/logging.h"
33 
34 namespace tensorflow {
35 namespace gtl {
36 namespace array_slice_internal {
37 
38 // Template logic for generic constructors.
39 
40 // Wrappers whose Get() delegates to the appropriate method of a container, and
41 // is defined when this method exists. Delegates to the const method if C is a
42 // const type.
43 struct Data {
44   template <typename C>
GetData45   static decltype(std::declval<C>().data()) Get(C* v) {
46     return v->data();
47   }
48 };
49 
50 struct MutableData {
51   template <typename C>
GetMutableData52   static decltype(std::declval<C>().mutable_data()) Get(C* v) {
53     return v->mutable_data();
54   }
55 };
56 
57 struct Size {
58   template <typename C>
GetSize59   static decltype(std::declval<C>().size()) Get(C* v) {
60     return v->size();
61   }
62 };
63 
64 struct MutableStringData {
65   // Defined only for string.
GetMutableStringData66   static char* Get(string* v) { return v->empty() ? nullptr : &*v->begin(); }
67 };
68 
69 // Checks whether M::Get(C*) is defined and has a return type R such that
70 // Checker::valid<R>()==true.
71 template <typename M, typename Checker, typename C>
72 struct HasGetHelper : public M {
73  private:
74   struct None {};
75   // M::Get is selected when it is viable. Get(...) is selected otherwise.
76   using M::Get;
77   static None Get(...);
78 
79  public:
HasGetHasGetHelper80   static constexpr bool HasGet() {
81     using Result = decltype(Get(std::declval<C*>()));
82     return !std::is_same<Result, None>() && Checker::template valid<Result>();
83   }
84 };
85 
86 // Defines HasGet() for a particular method, container, and checker. If
87 // HasGet()==true, provides Get() that delegates to the method.
88 template <typename M, typename Checker, typename C,
89           bool /*has_get*/ = HasGetHelper<M, Checker, C>::HasGet()>
90 struct Wrapper {
HasGetWrapper91   static constexpr bool HasGet() { return false; }
92 };
93 
94 template <typename M, typename Checker, typename C>
95 struct Wrapper<M, Checker, C, true> {
96   static constexpr bool HasGet() { return true; }
97   static decltype(M::Get(std::declval<C*>())) Get(C* v) { return M::Get(v); }
98 };
99 
100 // Type checker for a method returning an integral value.
101 struct SizeChecker {
102   template <typename R>
103   static constexpr bool valid() {
104     return std::is_integral<R>::value;
105   }
106 };
107 
108 // Type checker for a method returning either a pointer to T or a less const
109 // version of that.
110 template <typename T>
111 struct DataChecker {
112   // We want to enable conversion from std::vector<T*> to ArraySlice<const T*>
113   // but
114   // disable conversion from std::vector<Derived> to ArraySlice<Base>. Here we
115   // use
116   // the fact that U** is convertible to Q* const* if and only if Q is the same
117   // type or a more cv-qualified version of U.
118   template <typename R>
119   static constexpr bool valid() {
120     return std::is_convertible<R*, T* const*>::value;
121   }
122 };
123 
124 // Aliases to A if A::HasGet()==true, or to B otherwise.
125 template <typename A, typename B>
126 using FirstWithGet = typename std::conditional<A::HasGet(), A, B>::type;
127 
128 // Wraps C::data() const, returning a pointer to const data.
129 template <typename T, typename C>
130 using ContainerData = Wrapper<Data, DataChecker<const T>, const C>;
131 
132 // Wraps a method returning a pointer to mutable data. Prefers data() over
133 // mutable_data(), and handles strings when T==char. If data() returns a pointer
134 // to mutable data, it is most likely overloaded, but may also be a single
135 // method 'T* C::data() const' in a non-STL-compliant container.
136 template <typename T, typename C>
137 using ContainerMutableData =
138     FirstWithGet<Wrapper<Data, DataChecker<T>, C>,
139                  FirstWithGet<Wrapper<MutableData, DataChecker<T>, C>,
140                               Wrapper<MutableStringData, DataChecker<T>, C>>>;
141 
142 // Wraps C::size() const.
143 template <typename C>
144 using ContainerSize = Wrapper<Size, SizeChecker, const C>;
145 
146 // Implementation class for ArraySlice and MutableArraySlice. In the case of
147 // ArraySlice, T will be a const type; for MutableArraySlice, T will be a
148 // mutable type.
149 template <typename T>
150 class ArraySliceImplBase {
151  public:
152   typedef T* pointer;
153   typedef const T* const_pointer;
154   typedef T& reference;
155   typedef const T& const_reference;
156   typedef pointer iterator;
157   typedef const_pointer const_iterator;
158   typedef std::reverse_iterator<iterator> reverse_iterator;
159   typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
160   typedef size_t size_type;
161   typedef ptrdiff_t difference_type;
162 
163   static const size_type npos = static_cast<size_type>(-1);
164 
165   ArraySliceImplBase(pointer array, size_type length)
166       : ptr_(array), length_(length) {}
167 
168   // Substring of another ArraySlice.
169   // pos must be non-negative and <= x.length().
170   // len must be non-negative and will be pinned to at most x.length() - pos.
171   ArraySliceImplBase(const ArraySliceImplBase& x, size_type pos, size_type len)
172       : ptr_(x.ptr_ + pos), length_(std::min(x.length_ - pos, len)) {}
173 
174   // Some of the const methods below return pointers and references to mutable
175   // data. This is only the case in this internal class; ArraySlice and
176   // MutableArraySlice provide deep-constness.
177 
178   pointer data() const { return ptr_; }
179   size_type size() const { return length_; }
180 
181   void clear() {
182     ptr_ = nullptr;
183     length_ = 0;
184   }
185 
186   reference operator[](size_type i) const { return ptr_[i]; }
187   reference at(size_type i) const {
188     DCHECK_LT(i, length_);
189     return ptr_[i];
190   }
191   reference front() const {
192     DCHECK_GT(length_, 0);
193     return ptr_[0];
194   }
195   reference back() const {
196     DCHECK_GT(length_, 0);
197     return ptr_[length_ - 1];
198   }
199 
200   void remove_prefix(size_type n) {
201     DCHECK_GE(length_, n);
202     ptr_ += n;
203     length_ -= n;
204   }
205   void remove_suffix(size_type n) {
206     DCHECK_GE(length_, n);
207     length_ -= n;
208   }
209 
210   iterator begin() const { return ptr_; }
211   iterator end() const { return ptr_ + length_; }
212   reverse_iterator rbegin() const { return reverse_iterator(end()); }
213   reverse_iterator rend() const { return reverse_iterator(begin()); }
214 
215   bool operator==(const ArraySliceImplBase& other) const {
216     if (size() != other.size()) return false;
217     if (data() == other.data()) return true;
218     return std::equal(data(), data() + size(), other.data());
219   }
220   bool operator!=(const ArraySliceImplBase& other) const {
221     return !(*this == other);
222   }
223 
224  private:
225   pointer ptr_;
226   size_type length_;
227 };
228 
229 template <typename T>
230 class ArraySliceImpl : public ArraySliceImplBase<const T> {
231  public:
232   using ArraySliceImplBase<const T>::ArraySliceImplBase;
233 
234   // Defined iff the data and size accessors for the container C have been
235   // defined.
236   template <typename C>
237   using EnableIfConvertibleFrom =
238       typename std::enable_if<ContainerData<T, C>::HasGet() &&
239                               ContainerSize<C>::HasGet()>::type;
240 
241   // Constructs from a container when EnableIfConvertibleFrom is
242   // defined. std::addressof handles types with overloaded operator&.
243   template <typename C>
244   explicit ArraySliceImpl(const C& v)
245       : ArraySliceImplBase<const T>(ContainerData<T, C>::Get(std::addressof(v)),
246                                     ContainerSize<C>::Get(std::addressof(v))) {}
247 };
248 
249 template <typename T>
250 class MutableArraySliceImpl : public ArraySliceImplBase<T> {
251  public:
252   using ArraySliceImplBase<T>::ArraySliceImplBase;
253 
254   template <typename C>
255   using EnableIfConvertibleFrom =
256       typename std::enable_if<ContainerMutableData<T, C>::HasGet() &&
257                               ContainerSize<C>::HasGet()>::type;
258 
259   template <typename C>
260   explicit MutableArraySliceImpl(C* v)
261       : ArraySliceImplBase<T>(ContainerMutableData<T, C>::Get(v),
262                               ContainerSize<C>::Get(v)) {}
263 };
264 
265 }  // namespace array_slice_internal
266 }  // namespace gtl
267 }  // namespace tensorflow
268 
269 #endif  // TENSORFLOW_LIB_GTL_ARRAY_SLICE_INTERNAL_H_
270