block_item.h 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. #pragma once
  2. #include <yql/essentials/public/udf/udf_value.h>
  3. #include <yql/essentials/public/udf/udf_data_type.h>
  4. #include <yql/essentials/public/udf/udf_string_ref.h>
  5. #include <yql/essentials/public/udf/udf_type_size_check.h>
  6. namespace NYql::NUdf {
  7. class TBlockItem {
  8. using EMarkers = TUnboxedValuePod::EMarkers;
  9. public:
  10. TBlockItem() noexcept = default;
  11. ~TBlockItem() noexcept = default;
  12. TBlockItem(const TBlockItem& value) noexcept = default;
  13. TBlockItem(TBlockItem&& value) noexcept = default;
  14. TBlockItem& operator=(const TBlockItem& value) noexcept = default;
  15. TBlockItem& operator=(TBlockItem&& value) noexcept = default;
  16. template <typename T, typename = std::enable_if_t<TPrimitiveDataType<T>::Result>>
  17. inline explicit TBlockItem(T value);
  18. inline explicit TBlockItem(NYql::NDecimal::TInt128 value) {
  19. *reinterpret_cast<NYql::NDecimal::TInt128*>(&Raw) = value;
  20. Raw.Simple.Meta = static_cast<ui8>(EMarkers::Embedded);
  21. }
  22. inline explicit TBlockItem(IBoxedValuePtr&& value) {
  23. Raw.Resource.Meta = static_cast<ui8>(EMarkers::Boxed);
  24. Raw.Resource.Value = value.Release();
  25. Raw.Resource.Value->ReleaseRef();
  26. }
  27. inline explicit TBlockItem(TStringValue&& value, ui32 size = Max<ui32>(), ui32 offset = 0U) {
  28. Y_DEBUG_ABORT_UNLESS(size);
  29. Y_DEBUG_ABORT_UNLESS(offset < std::min(TRawStringValue::OffsetLimit, value.Size()));
  30. Raw.StringValue.Size = std::min(value.Size() - offset, size);
  31. Raw.StringValue.Offset = offset;
  32. Raw.StringValue.Value = value.ReleaseBuf();
  33. Raw.StringValue.Meta = static_cast<ui8>(EMarkers::String);
  34. }
  35. inline explicit TBlockItem(bool value) {
  36. Raw.Simple.bool_ = value ? 1 : 0;
  37. Raw.Simple.Meta = static_cast<ui8>(EMarkers::Embedded);
  38. }
  39. inline explicit TBlockItem(TStringRef value) {
  40. Raw.StringRef.Value = value.Data();
  41. Raw.StringRef.Size = value.Size();
  42. Raw.Simple.Meta = static_cast<ui8>(EMarkers::String);
  43. }
  44. inline explicit TBlockItem(const TBlockItem* tupleItems) {
  45. Raw.Tuple.Value = tupleItems;
  46. Raw.Simple.Meta = static_cast<ui8>(EMarkers::Embedded);
  47. }
  48. inline TBlockItem(ui64 low, ui64 high) {
  49. Raw.Halfs[0] = low;
  50. Raw.Halfs[1] = high;
  51. }
  52. inline static TBlockItem Embedded(const TStringRef& value) {
  53. UDF_VERIFY(value.Size() <= sizeof(TRawEmbeddedValue::Buffer));
  54. TBlockItem v;
  55. v.Raw.Embedded.Size = value.Size();
  56. v.Raw.Embedded.Meta = static_cast<ui8>(EMarkers::Embedded);
  57. if (v.Raw.Embedded.Size) {
  58. std::memcpy(v.Raw.Embedded.Buffer, value.Data(), v.Raw.Embedded.Size);
  59. }
  60. return v;
  61. }
  62. inline ui64 Low() const {
  63. return Raw.Halfs[0];
  64. }
  65. inline ui64 High() const {
  66. return Raw.Halfs[1];
  67. }
  68. // TODO: deprecate As<T>() in favor of Get<T>()
  69. template <typename T, typename = std::enable_if_t<TPrimitiveDataType<T>::Result>>
  70. inline T As() const;
  71. template <typename T, typename = std::enable_if_t<TPrimitiveDataType<T>::Result>>
  72. inline T Get() const;
  73. inline NYql::NDecimal::TInt128 GetInt128() const {
  74. Y_DEBUG_ABORT_UNLESS(GetMarkers() == EMarkers::Embedded);
  75. auto v = *reinterpret_cast<const NYql::NDecimal::TInt128*>(&Raw);
  76. const auto p = reinterpret_cast<ui8*>(&v);
  77. p[0xF] = (p[0xE] & 0x80) ? 0xFF : 0x00;
  78. return v;
  79. }
  80. // TODO: deprecate AsTuple() in favor of GetElements()
  81. inline const TBlockItem* AsTuple() const {
  82. Y_DEBUG_ABORT_UNLESS(GetMarkers() == EMarkers::Embedded);
  83. return Raw.Tuple.Value;
  84. }
  85. inline const TBlockItem* GetElements() const {
  86. Y_DEBUG_ABORT_UNLESS(GetMarkers() == EMarkers::Embedded);
  87. return Raw.Tuple.Value;
  88. }
  89. inline TBlockItem GetElement(ui32 index) const {
  90. Y_DEBUG_ABORT_UNLESS(GetMarkers() == EMarkers::Embedded);
  91. return Raw.Tuple.Value[index];
  92. }
  93. // TUnboxedValuePod stores strings as refcounted TStringValue,
  94. // TBlockItem can store pointer to both refcounted string and simple string view
  95. inline TStringRef AsStringRef() const {
  96. Y_DEBUG_ABORT_UNLESS(GetMarkers() == EMarkers::String);
  97. return TStringRef(Raw.StringRef.Value, Raw.StringRef.Size);
  98. }
  99. inline TStringValue AsStringValue() const {
  100. Y_DEBUG_ABORT_UNLESS(GetMarkers() == EMarkers::String);
  101. return TStringValue(Raw.StringValue.Value);
  102. }
  103. inline TStringRef GetStringRefFromValue() const {
  104. Y_DEBUG_ABORT_UNLESS(GetMarkers() == EMarkers::String);
  105. return { Raw.StringValue.Value->Data() + (Raw.StringValue.Offset & 0xFFFFFF), Raw.StringValue.Size };
  106. }
  107. inline TBlockItem MakeOptional() const
  108. {
  109. if (Raw.Simple.Meta)
  110. return *this;
  111. TBlockItem result(*this);
  112. ++result.Raw.Simple.Count;
  113. return result;
  114. }
  115. inline TBlockItem GetOptionalValue() const
  116. {
  117. if (Raw.Simple.Meta)
  118. return *this;
  119. Y_DEBUG_ABORT_UNLESS(Raw.Simple.Count > 0U, "Can't get value from empty.");
  120. TBlockItem result(*this);
  121. --result.Raw.Simple.Count;
  122. return result;
  123. }
  124. inline IBoxedValuePtr GetBoxed() const
  125. {
  126. Y_DEBUG_ABORT_UNLESS(GetMarkers() == EMarkers::Boxed, "Value is not boxed");
  127. return Raw.Resource.Value;
  128. }
  129. inline void* GetRawPtr()
  130. {
  131. return &Raw;
  132. }
  133. inline const void* GetRawPtr() const
  134. {
  135. return &Raw;
  136. }
  137. inline explicit operator bool() const { return bool(Raw); }
  138. EMarkers GetMarkers() const {
  139. return static_cast<EMarkers>(Raw.Simple.Meta);
  140. }
  141. bool HasValue() const { return EMarkers::Empty != GetMarkers(); }
  142. bool IsBoxed() const { return EMarkers::Boxed == GetMarkers(); }
  143. bool IsEmbedded() const { return EMarkers::Embedded == GetMarkers(); }
  144. inline void SetTimezoneId(ui16 id) {
  145. UDF_VERIFY(GetMarkers() == EMarkers::Embedded, "Value is not a datetime");
  146. Raw.Simple.TimezoneId = id;
  147. }
  148. inline ui16 GetTimezoneId() const {
  149. UDF_VERIFY(GetMarkers() == EMarkers::Embedded, "Value is not a datetime");
  150. return Raw.Simple.TimezoneId;
  151. }
  152. private:
  153. union TRaw {
  154. ui64 Halfs[2] = {0, 0};
  155. TRawEmbeddedValue Embedded;
  156. TRawBoxedValue Resource;
  157. TRawStringValue StringValue;
  158. struct {
  159. union {
  160. #define FIELD(type) type type##_;
  161. PRIMITIVE_VALUE_TYPES(FIELD);
  162. #undef FIELD
  163. // According to the YQL <-> arrow type mapping convention,
  164. // boolean values are processed as 8-bit unsigned integer
  165. // with either 0 or 1 as a condition payload.
  166. ui8 bool_;
  167. ui64 Count;
  168. };
  169. union {
  170. ui64 FullMeta;
  171. struct {
  172. TTimezoneId TimezoneId;
  173. ui8 Reserved[5];
  174. ui8 Meta;
  175. };
  176. };
  177. } Simple;
  178. struct {
  179. const char* Value;
  180. ui32 Size;
  181. ui8 Reserved;
  182. ui8 Meta;
  183. } StringRef;
  184. struct {
  185. // client should know tuple size
  186. const TBlockItem* Value;
  187. } Tuple;
  188. explicit operator bool() const { return Simple.FullMeta | Simple.Count; }
  189. } Raw;
  190. };
  191. UDF_ASSERT_TYPE_SIZE(TBlockItem, 16);
  192. #define VALUE_AS(xType) \
  193. template <> \
  194. inline xType TBlockItem::As<xType>() const \
  195. { \
  196. Y_DEBUG_ABORT_UNLESS(GetMarkers() == EMarkers::Embedded); \
  197. return Raw.Simple.xType##_; \
  198. }
  199. #define VALUE_GET(xType) \
  200. template <> \
  201. inline xType TBlockItem::Get<xType>() const \
  202. { \
  203. Y_DEBUG_ABORT_UNLESS(GetMarkers() == EMarkers::Embedded); \
  204. return Raw.Simple.xType##_; \
  205. }
  206. #define VALUE_CONSTR(xType) \
  207. template <> \
  208. inline TBlockItem::TBlockItem(xType value) \
  209. { \
  210. Raw.Simple.xType##_ = value; \
  211. Raw.Simple.Meta = static_cast<ui8>(EMarkers::Embedded); \
  212. }
  213. PRIMITIVE_VALUE_TYPES(VALUE_AS)
  214. PRIMITIVE_VALUE_TYPES(VALUE_GET)
  215. PRIMITIVE_VALUE_TYPES(VALUE_CONSTR)
  216. // XXX: TBlockItem constructor with <bool> parameter is implemented above.
  217. VALUE_AS(bool)
  218. VALUE_GET(bool)
  219. #undef VALUE_AS
  220. #undef VALUE_GET
  221. #undef VALUE_CONSTR
  222. }