#pragma once #include <library/cpp/yt/assert/assert.h> #include <library/cpp/yt/misc/hash.h> #include <vector> #include <array> #include <optional> #include <initializer_list> // For size_t. #include <stddef.h> namespace google::protobuf { //////////////////////////////////////////////////////////////////////////////// // Forward declarations template <class T> class RepeatedField; template <class T> class RepeatedPtrField; //////////////////////////////////////////////////////////////////////////////// } // namespace google::protobuf namespace NYT { //////////////////////////////////////////////////////////////////////////////// // Forward declarations template <class T, size_t N> class TCompactVector; //////////////////////////////////////////////////////////////////////////////// //! TRange (inspired by TArrayRef from LLVM) /*! * Represents a constant reference to an array (zero or more elements * consecutively in memory), i. e. a start pointer and a length. It allows * various APIs to take consecutive elements easily and conveniently. * * This class does not own the underlying data, it is expected to be used in * situations where the data resides in some other buffer, whose lifetime * extends past that of the TRange. For this reason, it is not in general * safe to store an TRange. * * This is intended to be trivially copyable, so it should be passed by * value. */ template <class T> class TRange { public: using iterator = const T*; using const_iterator = const T*; using size_type = size_t; //! Constructs a null TRange. TRange() : Data_(nullptr) , Length_(0) { } //! Constructs a TRange from a pointer and length. TRange(const T* data, size_t length) : Data_(data) , Length_(length) { } //! Constructs a TRange from a range. TRange(const T* begin, const T* end) : Data_(begin) , Length_(end - begin) { } //! Constructs a TRange from a TCompactVector. template <size_t N> TRange(const TCompactVector<T, N>& elements) : Data_(elements.data()) , Length_(elements.size()) { } //! Constructs a TRange from an std::vector. template <class A> TRange(const std::vector<T, A>& elements) : Data_(elements.empty() ? nullptr : elements.data()) , Length_(elements.size()) { } //! Constructs a TRange from a C array. template <size_t N> TRange(const T (&elements)[N]) : Data_(elements) , Length_(N) { } //! Constructs a TRange from std::initializer_list. TRange(std::initializer_list<T> elements) : Data_(elements.begin()) , Length_(elements.size()) { } //! Constructs a TRange from std::array. template <size_t N> TRange(const std::array<T, N>& elements) : Data_(elements.data()) , Length_(N) { } //! Constructs a TRange from std::optional. //! Range will contain 0-1 elements. explicit TRange(const std::optional<T>& element) : Data_(element ? &*element : nullptr) , Length_(element ? 1 : 0) { } const_iterator Begin() const { return Data_; } // STL interop, for gcc. const_iterator begin() const { return Begin(); } const_iterator End() const { return Data_ + Length_; } // STL interop, for gcc. const_iterator end() const { return End(); } bool Empty() const { return Length_ == 0; } bool empty() const { return Empty(); } explicit operator bool() const { return Data_ != nullptr; } size_t Size() const { return Length_; } size_t size() const { return Size(); } const T& operator[](size_t index) const { YT_ASSERT(index < Size()); return Data_[index]; } const T& Front() const { YT_ASSERT(Length_ > 0); return Data_[0]; } const T& Back() const { YT_ASSERT(Length_ > 0); return Data_[Length_ - 1]; } TRange<T> Slice(size_t startOffset, size_t endOffset) const { YT_ASSERT(startOffset <= endOffset && endOffset <= Size()); return TRange<T>(Begin() + startOffset, endOffset - startOffset); } std::vector<T> ToVector() const { return std::vector<T>(Data_, Data_ + Length_); } protected: //! The start of the array, in an external buffer. const T* Data_; //! The number of elements. size_t Length_; }; // STL interop. template <class T> typename TRange<T>::const_iterator begin(TRange<T> ref) { return ref.Begin(); } template <class T> typename TRange<T>::const_iterator end(TRange<T> ref) { return ref.End(); } //////////////////////////////////////////////////////////////////////////////// //! Constructs a TRange from a pointer and length. template <class T> TRange<T> MakeRange(const T* data, size_t length) { return TRange<T>(data, length); } //! Constructs a TRange from a native range. template <class T> TRange<T> MakeRange(const T* begin, const T* end) { return TRange<T>(begin, end); } //! Constructs a TRange from a TCompactVector. template <class T, size_t N> TRange<T> MakeRange(const TCompactVector<T, N>& elements) { return elements; } //! "Copy-constructor". template <class T> TRange<T> MakeRange(TRange<T> range) { return range; } //! Constructs a TRange from an std::vector. template <class T> TRange<T> MakeRange(const std::vector<T>& elements) { return elements; } //! Constructs a TRange from an std::array. template <class T, size_t N> TRange<T> MakeRange(const std::array<T, N>& elements) { return elements; } //! Constructs a TRange from a C array. template <class T, size_t N> TRange<T> MakeRange(const T (& elements)[N]) { return TRange<T>(elements); } //! Constructs a TRange from RepeatedField. template <class T> TRange<T> MakeRange(const google::protobuf::RepeatedField<T>& elements) { return TRange<T>(elements.data(), elements.size()); } //! Constructs a TRange from RepeatedPtrField. template <class T> TRange<const T*> MakeRange(const google::protobuf::RepeatedPtrField<T>& elements) { return TRange<const T*>(elements.data(), elements.size()); } template <class U, class T> TRange<U> ReinterpretCastRange(TRange<T> range) { static_assert(sizeof(T) == sizeof(U), "T and U must have equal sizes."); return TRange<U>(reinterpret_cast<const U*>(range.Begin()), range.Size()); } //////////////////////////////////////////////////////////////////////////////// // TMutableRange (inspired by TMutableArrayRef from LLVM) /* * Represents a mutable reference to an array (zero or more elements * consecutively in memory), i. e. a start pointer and a length. * It allows various APIs to take and modify consecutive elements easily and * conveniently. * * This class does not own the underlying data, it is expected to be used in * situations where the data resides in some other buffer, whose lifetime * extends past that of the TMutableRange. For this reason, it is not in * general safe to store a TMutableRange. * * This is intended to be trivially copyable, so it should be passed by value. */ template <class T> class TMutableRange : public TRange<T> { public: using iterator = T*; //! Constructs a null TMutableRange. TMutableRange() { } //! Constructs a TMutableRange from a pointer and length. TMutableRange(T* data, size_t length) : TRange<T>(data, length) { } //! Constructs a TMutableRange from a range. TMutableRange(T* begin, T* end) : TRange<T>(begin, end) { } //! Constructs a TMutableRange from a TCompactVector. template <size_t N> TMutableRange(TCompactVector<T, N>& elements) : TRange<T>(elements) { } //! Constructs a TMutableRange from an std::vector. TMutableRange(std::vector<T>& elements) : TRange<T>(elements) { } //! Constructs a TMutableRange from std::array. template <size_t N> TMutableRange(std::array<T, N>& elements) : TRange<T>(elements.data(), N) { } //! Construct a TMutableRange from an std::optional //! Range will contain 0-1 elements. explicit TMutableRange(std::optional<T>& optional) : TRange<T>(optional) { } //! Constructs a TMutableRange from a C array. template <size_t N> TMutableRange(T (& elements)[N]) : TRange<T>(elements) { } using TRange<T>::Begin; using TRange<T>::End; using TRange<T>::Front; using TRange<T>::Back; using TRange<T>::operator[]; iterator Begin() const { return const_cast<T*>(this->Data_); } // STL interop, for gcc. iterator begin() const { return Begin(); } iterator End() const { return this->Begin() + this->Size(); } // STL interop, for gcc. iterator end() const { return End(); } T& operator[](size_t index) { YT_ASSERT(index <= this->Size()); return Begin()[index]; } T& Front() { YT_ASSERT(this->Length_ > 0); return Begin()[0]; } T& Back() { YT_ASSERT(this->Length_ > 0); return Begin()[this->Length_ - 1]; } TMutableRange<T> Slice(size_t startOffset, size_t endOffset) const { YT_ASSERT(startOffset <= endOffset && endOffset <= this->Size()); return TMutableRange<T>(Begin() + startOffset, endOffset - startOffset); } TMutableRange<T> Slice(T* begin, T* end) const { YT_ASSERT(begin >= Begin()); YT_ASSERT(end <= End()); return TMutableRange<T>(begin, end); } }; // STL interop. template <class T> typename TMutableRange<T>::iterator begin(TMutableRange<T> ref) { return ref.Begin(); } template <class T> typename TMutableRange<T>::iterator end(TMutableRange<T> ref) { return ref.End(); } //////////////////////////////////////////////////////////////////////////////// //! Constructs a TMutableRange from a pointer and length. template <class T> TMutableRange<T> MakeMutableRange(T* data, size_t length) { return TMutableRange<T>(data, length); } //! Constructs a TMutableRange from a native range. template <class T> TMutableRange<T> MakeMutableRange(T* begin, T* end) { return TMutableRange<T>(begin, end); } //! Constructs a TMutableRange from a TCompactVector. template <class T, size_t N> TMutableRange<T> MakeMutableRange(TCompactVector<T, N>& elements) { return elements; } //! "Copy-constructor". template <class T> TMutableRange<T> MakeMutableRange(TMutableRange<T> range) { return range; } //! Constructs a TMutableRange from an std::vector. template <class T> TMutableRange<T> MakeMutableRange(std::vector<T>& elements) { return elements; } //! Constructs a TMutableRange from an std::array. template <class T, size_t N> TMutableRange<T> MakeMutableRange(std::array<T, N>& elements) { return elements; } //! Constructs a TMutableRange from a C array. template <class T, size_t N> TMutableRange<T> MakeMutableRange(T (& elements)[N]) { return TMutableRange<T>(elements); } //! Constructs a TMutableRange from RepeatedField. template <class T> TMutableRange<T> MakeMutableRange(google::protobuf::RepeatedField<T>& elements) { return TMutableRange<T>(elements.data(), elements.size()); } //! Constructs a TMutableRange from RepeatedPtrField. template <class T> TMutableRange<T*> MakeMutableRange(google::protobuf::RepeatedPtrField<T>& elements) { return TMutableRange<const T*>(elements.data(), elements.size()); } template <class U, class T> TMutableRange<U> ReinterpretCastMutableRange(TMutableRange<T> range) { static_assert(sizeof(T) == sizeof(U), "T and U must have equal sizes."); return TMutableRange<U>(reinterpret_cast<U*>(range.Begin()), range.Size()); } //////////////////////////////////////////////////////////////////////////////// // Mark TMutableRange and TMutableRange as PODs. namespace NMpl { template <class T> struct TIsPod; template <class T> struct TIsPod<TRange<T>> { static const bool Value = true; }; template <class T> struct TIsPod<TMutableRange<T>> { static const bool Value = true; }; } // namespace NMpl //////////////////////////////////////////////////////////////////////////////// } // namespace NYT template <class T> struct hash<NYT::TRange<T>> { size_t operator()(const NYT::TRange<T>& range) const { size_t result = 0; for (const auto& element : range) { NYT::HashCombine(result, element); } return result; } }; template <class T> struct hash<NYT::TMutableRange<T>> { size_t operator()(const NYT::TMutableRange<T>& range) const { size_t result = 0; for (const auto& element : range) { NYT::HashCombine(result, element); } return result; } };