// 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 #include #include #include #include #include #include #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 static decltype(std::declval().data()) Get(C* v) { return v->data(); } }; struct MutableData { template static decltype(std::declval().mutable_data()) Get(C* v) { return v->mutable_data(); } }; struct Size { template static decltype(std::declval().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()==true. template 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())); return !std::is_same() && Checker::template valid(); } }; // Defines HasGet() for a particular method, container, and checker. If // HasGet()==true, provides Get() that delegates to the method. template ::HasGet()> struct Wrapper { static constexpr bool HasGet() { return false; } }; template struct Wrapper { static constexpr bool HasGet() { return true; } static decltype(M::Get(std::declval())) Get(C* v) { return M::Get(v); } }; // Type checker for a method returning an integral value. struct SizeChecker { template static constexpr bool valid() { return std::is_integral::value; } }; // Type checker for a method returning either a pointer to T or a less const // version of that. template struct DataChecker { // We want to enable conversion from std::vector to ArraySlice // but // disable conversion from std::vector to ArraySlice. 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 static constexpr bool valid() { return std::is_convertible::value; } }; // Aliases to A if A::HasGet()==true, or to B otherwise. template using FirstWithGet = typename std::conditional::type; // Wraps C::data() const, returning a pointer to const data. template using ContainerData = Wrapper, 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 using ContainerMutableData = FirstWithGet, C>, FirstWithGet, C>, Wrapper, C>>>; // Wraps C::size() const. template using ContainerSize = Wrapper; // 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 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 reverse_iterator; typedef std::reverse_iterator const_reverse_iterator; typedef size_t size_type; typedef ptrdiff_t difference_type; static const size_type npos = -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 class ArraySliceImpl : public ArraySliceImplBase { public: using ArraySliceImplBase::ArraySliceImplBase; // Defined iff the data and size accessors for the container C have been // defined. template using EnableIfConvertibleFrom = typename std::enable_if::HasGet() && ContainerSize::HasGet()>::type; // Constructs from a container when EnableIfConvertibleFrom is // defined. std::addressof handles types with overloaded operator&. template explicit ArraySliceImpl(const C& v) : ArraySliceImplBase(ContainerData::Get(std::addressof(v)), ContainerSize::Get(std::addressof(v))) {} }; template class MutableArraySliceImpl : public ArraySliceImplBase { public: using ArraySliceImplBase::ArraySliceImplBase; template using EnableIfConvertibleFrom = typename std::enable_if::HasGet() && ContainerSize::HasGet()>::type; template explicit MutableArraySliceImpl(C* v) : ArraySliceImplBase(ContainerMutableData::Get(v), ContainerSize::Get(v)) {} }; } // namespace array_slice_internal } // namespace gtl } // namespace tensorflow #endif // TENSORFLOW_LIB_GTL_ARRAY_SLICE_INTERNAL_H_