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 // An ArraySlice<T> represents an immutable array of elements of type 17 // T. It has a length "length", and a base pointer "ptr", and the 18 // array it represents contains the elements "ptr[0] .. ptr[len-1]". 19 // The backing store for the array is *not* owned by the ArraySlice 20 // object, and clients must arrange for the backing store to remain 21 // live while the ArraySlice object is in use. 22 // 23 // An ArraySlice<T> is somewhat analogous to a StringPiece, but for 24 // array elements of type T. 25 // 26 // Implicit conversion operations are provided from types such as 27 // std::vector<T> and util::gtl::InlinedVector<T, N>. Note that ArraySlice 28 // objects constructed from types in this way may be invalidated by 29 // any operations that mutate the underlying vector. 30 // 31 // One common use for ArraySlice is when passing arguments to a 32 // routine where you want to be able to accept a variety of array 33 // types (e.g. a vector, a util::gtl::InlinedVector, a C-style array, 34 // etc.). The usual approach here is to have the client explicitly 35 // pass in a pointer and a length, as in: 36 // 37 // void MyRoutine(const int* elems, int N) { 38 // for (int i = 0; i < N; i++) { .. do something with elems[i] .. } 39 // } 40 // 41 // Unfortunately, this leads to ugly and error-prone code at the call site: 42 // 43 // std::vector<int> my_vector; 44 // MyRoutine(vector_as_array(&my_vector), my_vector.size()); 45 // 46 // util::gtl::InlinedVector<int, 4> my_inline_vector; 47 // MyRoutine(my_inline_vector.array(), my_inline_vector.size()); 48 // 49 // int my_array[10]; 50 // MyRoutine(my_array, 10); 51 // 52 // Instead, you can use an ArraySlice as the argument to the routine: 53 // 54 // void MyRoutine(ArraySlice<int> a) { 55 // for (int i = 0; i < a.size(); i++) { .. do something with a[i] .. } 56 // } 57 // 58 // This makes the call sites cleaner, for the most part: 59 // 60 // std::vector<int> my_vector; 61 // MyRoutine(my_vector); 62 // 63 // util::gtl::InlinedVector<int, 4> my_inline_vector; 64 // MyRoutine(my_inline_vector); 65 // 66 // int my_array[10]; 67 // MyRoutine(my_array); 68 // 69 // int* my_array = new int[10]; 70 // MyRoutine(gtl::ArraySlice<int>(my_array, 10)); 71 // 72 // MutableArraySlice<T> represents a mutable array of elements, and, like 73 // ArraySlice, does not own the backing store. The implicit constructors it 74 // provides allow functions not to worry about whether their mutable arguments 75 // refer to vectors, arrays, proto2::RepeatedFields, etc.: 76 // 77 // void MyMutatingRoutine(MutableArraySlice<int> a) { 78 // for (int i = 0; i < a.size(); i++) { .. mutate a[i] .. } 79 // } 80 // 81 // std::vector<int> my_vector; 82 // MyMutatingRoutine(&my_vector); 83 // 84 // int my_array[10]; 85 // MyMutatingRoutine(my_array); 86 // 87 // int* my_array = new int[10]; 88 // MyMutatingRoutine(gtl::MutableArraySlice<int>(my_array, 10)); 89 // 90 // MyProto my_proto; 91 // for (int i = 0; i < 10; ++i) { my_proto.add_value(i); } 92 // MyMutatingRoutine(my_proto.mutable_value()); 93 94 #ifndef TENSORFLOW_LIB_GTL_ARRAY_SLICE_H_ 95 #define TENSORFLOW_LIB_GTL_ARRAY_SLICE_H_ 96 97 #include <initializer_list> 98 #include <type_traits> 99 #include <vector> 100 101 #include "tensorflow/core/lib/gtl/array_slice_internal.h" 102 #include "tensorflow/core/lib/gtl/inlined_vector.h" 103 104 namespace tensorflow { 105 namespace gtl { 106 107 template <typename T> 108 class ArraySlice { 109 private: 110 typedef array_slice_internal::ArraySliceImpl<T> Impl; 111 112 public: 113 typedef T value_type; 114 typedef typename Impl::pointer pointer; 115 typedef typename Impl::const_pointer const_pointer; 116 typedef typename Impl::reference reference; 117 typedef typename Impl::const_reference const_reference; 118 typedef typename Impl::iterator iterator; 119 typedef typename Impl::const_iterator const_iterator; 120 typedef typename Impl::reverse_iterator reverse_iterator; 121 typedef typename Impl::const_reverse_iterator const_reverse_iterator; 122 typedef typename Impl::size_type size_type; 123 typedef typename Impl::difference_type difference_type; 124 125 static const size_type npos = Impl::npos; 126 127 ArraySlice() : impl_(nullptr, 0) {} 128 ArraySlice(const_pointer array, size_type length) : impl_(array, length) {} 129 130 // Implicit conversion constructors 131 ArraySlice(const std::vector<value_type>& v) // NOLINT(runtime/explicit) 132 : impl_(v.data(), v.size()) {} 133 134 template <size_t N> 135 ArraySlice(const value_type (&a)[N]) // NOLINT(runtime/explicit) 136 : impl_(a, N) {} 137 138 template <int N> 139 ArraySlice(const InlinedVector<value_type, N>& v) // NOLINT(runtime/explicit) 140 : impl_(v.data(), v.size()) {} 141 142 // The constructor for any class supplying 'data() const' that returns either 143 // const T* or a less const-qualified version of it, and 'some_integral_type 144 // size() const'. proto2::RepeatedField<T>, string and (since C++11) 145 // std::vector<T,A> and std::array<T, N> are examples of this. See 146 // array_slice_internal.h for details. 147 template <typename V, 148 typename = typename Impl::template EnableIfConvertibleFrom<V>> 149 ArraySlice(const V& v) // NOLINT(runtime/explicit) 150 : impl_(v) {} 151 152 // Implicitly constructs an ArraySlice from an initializer list. This makes it 153 // possible to pass a brace-enclosed initializer list to a function expecting 154 // an ArraySlice: 155 // void Process(ArraySlice<int> x); 156 // Process({1, 2, 3}); 157 // The data referenced by the initializer_list must outlive this 158 // ArraySlice. For example, "ArraySlice<int> s={1,2};" and "return 159 // ArraySlice<int>({3,4});" are errors, as the resulting ArraySlice may 160 // reference data that is no longer valid. 161 ArraySlice(std::initializer_list<value_type> v) // NOLINT(runtime/explicit) 162 : impl_(v.begin(), v.size()) {} 163 164 // Substring of another ArraySlice. 165 // pos must be non-negative and <= x.length(). 166 // len must be non-negative and will be pinned to at most x.length() - pos. 167 // If len==npos, the substring continues till the end of x. 168 ArraySlice(const ArraySlice& x, size_type pos, size_type len) 169 : impl_(x.impl_, pos, len) {} 170 171 const_pointer data() const { return impl_.data(); } 172 size_type size() const { return impl_.size(); } 173 size_type length() const { return size(); } 174 bool empty() const { return size() == 0; } 175 176 void clear() { impl_.clear(); } 177 178 const_reference operator[](size_type i) const { return impl_[i]; } 179 const_reference at(size_type i) const { return impl_.at(i); } 180 const_reference front() const { return impl_.front(); } 181 const_reference back() const { return impl_.back(); } 182 183 const_iterator begin() const { return impl_.begin(); } 184 const_iterator end() const { return impl_.end(); } 185 const_reverse_iterator rbegin() const { return impl_.rbegin(); } 186 const_reverse_iterator rend() const { return impl_.rend(); } 187 188 void remove_prefix(size_type n) { impl_.remove_prefix(n); } 189 void remove_suffix(size_type n) { impl_.remove_suffix(n); } 190 void pop_back() { remove_suffix(1); } 191 void pop_front() { remove_prefix(1); } 192 193 // These relational operators have the same semantics as the 194 // std::vector<T> relational operators: they do deep (element-wise) 195 // comparisons. Array slices are equal iff their size is the same 196 // and all their elements are equal. 197 bool operator==(ArraySlice<T> other) const { return impl_ == other.impl_; } 198 bool operator!=(ArraySlice<T> other) const { return impl_ != other.impl_; } 199 200 private: 201 Impl impl_; 202 }; 203 204 // Mutable version of ArraySlice, which allows the clients to mutate the 205 // underlying data. It is implicitly convertible to ArraySlice since it provides 206 // the data() and size() methods with correct signatures. When a 207 // MutableArraySlice is created from a pointer to a container (as opposed to raw 208 // memory pointer), the pointer must not be null. 209 // 210 // A note on const-ness: "mutable" here refers to the mutability of the 211 // underlying data, not of the slice itself. It is perfectly reasonable to have 212 // a variable of type "const MutableArraySlice<T>"; this means that the bounds 213 // of the view on the array cannot be changed, but the underlying data in the 214 // array still may be modified. This is akin to a "T* const" pointer, as opposed 215 // to a "const T*" pointer (corresponding to a non-const ArraySlice<T>). 216 template <typename T> 217 class MutableArraySlice { 218 private: 219 typedef array_slice_internal::MutableArraySliceImpl<T> Impl; 220 221 public: 222 typedef T value_type; 223 typedef typename Impl::pointer pointer; 224 typedef typename Impl::const_pointer const_pointer; 225 typedef typename Impl::reference reference; 226 typedef typename Impl::const_reference const_reference; 227 typedef typename Impl::iterator iterator; 228 typedef typename Impl::const_iterator const_iterator; 229 typedef typename Impl::reverse_iterator reverse_iterator; 230 typedef typename Impl::const_reverse_iterator const_reverse_iterator; 231 typedef typename Impl::size_type size_type; 232 typedef typename Impl::difference_type difference_type; 233 234 static const size_type npos = Impl::npos; 235 236 MutableArraySlice() : impl_(nullptr, 0) {} 237 MutableArraySlice(pointer array, size_type length) : impl_(array, length) {} 238 239 // Implicit conversion constructors 240 MutableArraySlice(std::vector<value_type>* v) // NOLINT(runtime/explicit) 241 : impl_(v->data(), v->size()) {} 242 243 template <size_t N> 244 MutableArraySlice(value_type (&a)[N]) // NOLINT(runtime/explicit) 245 : impl_(a, N) {} 246 247 template <int N> 248 MutableArraySlice( 249 InlinedVector<value_type, N>* v) // NOLINT(runtime/explicit) 250 : impl_(v->data(), v->size()) {} 251 252 // The constructor for any class supplying 'T* data()' or 'T* mutable_data()' 253 // (the former is called if both exist), and 'some_integral_type size() 254 // const'. proto2::RepeatedField is an example of this. Also supports string 255 // arguments, when T==char. The appropriate ctor is selected using SFINAE. See 256 // array_slice_internal.h for details. 257 template <typename V, 258 typename = typename Impl::template EnableIfConvertibleFrom<V>> 259 MutableArraySlice(V* v) // NOLINT(runtime/explicit) 260 : impl_(v) {} 261 262 // Substring of another MutableArraySlice. 263 // pos must be non-negative and <= x.length(). 264 // len must be non-negative and will be pinned to at most x.length() - pos. 265 // If len==npos, the substring continues till the end of x. 266 MutableArraySlice(const MutableArraySlice& x, size_type pos, size_type len) 267 : impl_(x.impl_, pos, len) {} 268 269 // Accessors. 270 pointer data() const { return impl_.data(); } 271 size_type size() const { return impl_.size(); } 272 size_type length() const { return size(); } 273 bool empty() const { return size() == 0; } 274 275 void clear() { impl_.clear(); } 276 277 reference operator[](size_type i) const { return impl_[i]; } 278 reference at(size_type i) const { return impl_.at(i); } 279 reference front() const { return impl_.front(); } 280 reference back() const { return impl_.back(); } 281 282 iterator begin() const { return impl_.begin(); } 283 iterator end() const { return impl_.end(); } 284 reverse_iterator rbegin() const { return impl_.rbegin(); } 285 reverse_iterator rend() const { return impl_.rend(); } 286 287 void remove_prefix(size_type n) { impl_.remove_prefix(n); } 288 void remove_suffix(size_type n) { impl_.remove_suffix(n); } 289 void pop_back() { remove_suffix(1); } 290 void pop_front() { remove_prefix(1); } 291 292 bool operator==(ArraySlice<T> other) const { 293 return ArraySlice<T>(*this) == other; 294 } 295 bool operator!=(ArraySlice<T> other) const { 296 return ArraySlice<T>(*this) != other; 297 } 298 299 // DEPRECATED(jacobsa): Please use data() instead. 300 pointer mutable_data() const { return impl_.data(); } 301 302 private: 303 Impl impl_; 304 }; 305 306 template <typename T> 307 const typename ArraySlice<T>::size_type ArraySlice<T>::npos; 308 template <typename T> 309 const typename MutableArraySlice<T>::size_type MutableArraySlice<T>::npos; 310 311 } // namespace gtl 312 } // namespace tensorflow 313 314 #endif // TENSORFLOW_LIB_GTL_ARRAY_SLICE_H_ 315