#pragma once #include #include #include #include #include #include // For size_t. #include namespace google::protobuf { //////////////////////////////////////////////////////////////////////////////// // Forward declarations template class RepeatedField; template class RepeatedPtrField; //////////////////////////////////////////////////////////////////////////////// } // namespace google::protobuf namespace NYT { //////////////////////////////////////////////////////////////////////////////// // Forward declarations template 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 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 TRange(const TCompactVector& elements) : Data_(elements.data()) , Length_(elements.size()) { } //! Constructs a TRange from an std::vector. template TRange(const std::vector& elements) : Data_(elements.empty() ? nullptr : elements.data()) , Length_(elements.size()) { } //! Constructs a TRange from a C array. template TRange(const T (&elements)[N]) : Data_(elements) , Length_(N) { } //! Constructs a TRange from std::initializer_list. TRange(std::initializer_list elements) : Data_(elements.begin()) , Length_(elements.size()) { } //! Constructs a TRange from std::array. template TRange(const std::array& elements) : Data_(elements.data()) , Length_(N) { } //! Constructs a TRange from std::optional. //! Range will contain 0-1 elements. explicit TRange(const std::optional& 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* Data() const { return Data_; } const T* data() const { return Data(); } 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 Slice(size_t startOffset, size_t endOffset) const { YT_ASSERT(startOffset <= endOffset && endOffset <= Size()); return TRange(Begin() + startOffset, endOffset - startOffset); } std::vector ToVector() const { return std::vector(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 typename TRange::const_iterator begin(TRange ref) { return ref.Begin(); } template typename TRange::const_iterator end(TRange ref) { return ref.End(); } //////////////////////////////////////////////////////////////////////////////// //! Constructs a TRange from a pointer and length. template TRange MakeRange(const T* data, size_t length) { return TRange(data, length); } //! Constructs a TRange from a native range. template TRange MakeRange(const T* begin, const T* end) { return TRange(begin, end); } //! Constructs a TRange from a TCompactVector. template TRange MakeRange(const TCompactVector& elements) { return elements; } //! "Copy-constructor". template TRange MakeRange(TRange range) { return range; } //! Constructs a TRange from an std::vector. template TRange MakeRange(const std::vector& elements) { return elements; } //! Constructs a TRange from an std::array. template TRange MakeRange(const std::array& elements) { return elements; } //! Constructs a TRange from a C array. template TRange MakeRange(const T (& elements)[N]) { return TRange(elements); } //! Constructs a TRange from RepeatedField. template TRange MakeRange(const google::protobuf::RepeatedField& elements) { return TRange(elements.data(), elements.size()); } //! Constructs a TRange from RepeatedPtrField. template TRange MakeRange(const google::protobuf::RepeatedPtrField& elements) { return TRange(elements.data(), elements.size()); } template TRange ReinterpretCastRange(TRange range) { static_assert(sizeof(T) == sizeof(U), "T and U must have equal sizes."); return TRange(reinterpret_cast(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 TMutableRange : public TRange { public: using iterator = T*; //! Constructs a null TMutableRange. TMutableRange() { } //! Constructs a TMutableRange from a pointer and length. TMutableRange(T* data, size_t length) : TRange(data, length) { } //! Constructs a TMutableRange from a range. TMutableRange(T* begin, T* end) : TRange(begin, end) { } //! Constructs a TMutableRange from a TCompactVector. template TMutableRange(TCompactVector& elements) : TRange(elements) { } //! Constructs a TMutableRange from an std::vector. TMutableRange(std::vector& elements) : TRange(elements) { } //! Constructs a TMutableRange from std::array. template TMutableRange(std::array& elements) : TRange(elements.data(), N) { } //! Construct a TMutableRange from an std::optional //! Range will contain 0-1 elements. explicit TMutableRange(std::optional& optional) : TRange(optional) { } //! Constructs a TMutableRange from a C array. template TMutableRange(T (& elements)[N]) : TRange(elements) { } using TRange::Begin; using TRange::End; using TRange::Front; using TRange::Back; using TRange::operator[]; iterator Begin() const { return const_cast(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 Slice(size_t startOffset, size_t endOffset) const { YT_ASSERT(startOffset <= endOffset && endOffset <= this->Size()); return TMutableRange(Begin() + startOffset, endOffset - startOffset); } TMutableRange Slice(T* begin, T* end) const { YT_ASSERT(begin >= Begin()); YT_ASSERT(end <= End()); return TMutableRange(begin, end); } }; // STL interop. template typename TMutableRange::iterator begin(TMutableRange ref) { return ref.Begin(); } template typename TMutableRange::iterator end(TMutableRange ref) { return ref.End(); } //////////////////////////////////////////////////////////////////////////////// //! Constructs a TMutableRange from a pointer and length. template TMutableRange MakeMutableRange(T* data, size_t length) { return TMutableRange(data, length); } //! Constructs a TMutableRange from a native range. template TMutableRange MakeMutableRange(T* begin, T* end) { return TMutableRange(begin, end); } //! Constructs a TMutableRange from a TCompactVector. template TMutableRange MakeMutableRange(TCompactVector& elements) { return elements; } //! "Copy-constructor". template TMutableRange MakeMutableRange(TMutableRange range) { return range; } //! Constructs a TMutableRange from an std::vector. template TMutableRange MakeMutableRange(std::vector& elements) { return elements; } //! Constructs a TMutableRange from an std::array. template TMutableRange MakeMutableRange(std::array& elements) { return elements; } //! Constructs a TMutableRange from a C array. template TMutableRange MakeMutableRange(T (& elements)[N]) { return TMutableRange(elements); } //! Constructs a TMutableRange from RepeatedField. template TMutableRange MakeMutableRange(google::protobuf::RepeatedField& elements) { return TMutableRange(elements.data(), elements.size()); } //! Constructs a TMutableRange from RepeatedPtrField. template TMutableRange MakeMutableRange(google::protobuf::RepeatedPtrField& elements) { return TMutableRange(elements.data(), elements.size()); } template TMutableRange ReinterpretCastMutableRange(TMutableRange range) { static_assert(sizeof(T) == sizeof(U), "T and U must have equal sizes."); return TMutableRange(reinterpret_cast(range.Begin()), range.Size()); } //////////////////////////////////////////////////////////////////////////////// // Mark TMutableRange and TMutableRange as PODs. namespace NMpl { template struct TIsPod; template struct TIsPod> { static const bool Value = true; }; template struct TIsPod> { static const bool Value = true; }; } // namespace NMpl //////////////////////////////////////////////////////////////////////////////// } // namespace NYT template struct hash> { size_t operator()(const NYT::TRange& range) const { size_t result = 0; for (const auto& element : range) { NYT::HashCombine(result, element); } return result; } }; template struct hash> { size_t operator()(const NYT::TMutableRange& range) const { size_t result = 0; for (const auto& element : range) { NYT::HashCombine(result, element); } return result; } };