yql_wide_int.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. #pragma once
  2. #include <util/system/types.h>
  3. #include <type_traits>
  4. #include <tuple>
  5. #include <cmath>
  6. namespace NYql {
  7. #ifndef _win_
  8. typedef __int128 i128_t;
  9. typedef unsigned __int128 ui128_t;
  10. #endif
  11. template<typename TOneHalf, typename TSignedPart = std::make_signed_t<TOneHalf>, typename TUnsignedPart = std::make_unsigned_t<TOneHalf>>
  12. class TWide {
  13. private:
  14. using THalf = TOneHalf;
  15. using TPart = TUnsignedPart;
  16. using TIsSigned = std::is_same<THalf, TSignedPart>;
  17. using TIsUnsigned = std::is_same<THalf, TUnsignedPart>;
  18. static_assert(TIsSigned::value || TIsUnsigned::value, "Invalid using of TWide.");
  19. static_assert(sizeof(TSignedPart) == sizeof(TUnsignedPart), "Different sizes of TWide parts.");
  20. TPart Lo;
  21. THalf Hi;
  22. static constexpr auto FullBitSize = sizeof(TPart) << 4U;
  23. static constexpr auto PartBitSize = sizeof(TPart) << 3U;
  24. static constexpr auto QuarterBitSize = sizeof(TPart) << 2U;
  25. static constexpr TPart GetUpperQuarter(TPart h) {
  26. return h >> QuarterBitSize;
  27. }
  28. static constexpr TPart GetLowerQuarter(TPart h) {
  29. const auto mask = TPart(~TPart(0U)) >> QuarterBitSize;
  30. return h & mask;
  31. }
  32. template<typename T>
  33. constexpr std::enable_if_t<sizeof(T) <= sizeof(THalf), T> CastImpl() const {
  34. return static_cast<T>(Lo);
  35. }
  36. template<typename T>
  37. constexpr std::enable_if_t<sizeof(T) == sizeof(THalf) << 1U, T> CastImpl() const {
  38. return *reinterpret_cast<const T*>(this);
  39. }
  40. template<typename T>
  41. constexpr std::enable_if_t<sizeof(THalf) << 1U < sizeof(T), T> CastImpl() const {
  42. return (T(std::make_unsigned_t<T>(Hi) << PartBitSize)) | Lo;
  43. }
  44. constexpr size_t GetBits() const {
  45. size_t out = Hi ? PartBitSize : 0U;
  46. for (auto up = TPart(out ? Hi : Lo); up; up >>= 1U) {
  47. ++out;
  48. }
  49. return out;
  50. }
  51. using TUnsigned = TWide<TUnsignedPart, TSignedPart, TUnsignedPart>;
  52. using TSibling = std::conditional_t<std::is_same<THalf, TPart>::value,
  53. TWide<TSignedPart, TSignedPart, TUnsignedPart>, TWide<TUnsignedPart, TSignedPart, TUnsignedPart>>;
  54. friend TSibling;
  55. public:
  56. constexpr TWide() = default;
  57. constexpr TWide(const TWide& rhs) = default;
  58. constexpr TWide(TWide&& rhs) = default;
  59. constexpr TWide& operator=(const TWide& rhs) = default;
  60. constexpr TWide& operator=(TWide&& rhs) = default;
  61. constexpr TWide(const TSibling& rhs)
  62. : Lo(rhs.Lo), Hi(rhs.Hi)
  63. {}
  64. template<typename U, typename L>
  65. constexpr TWide(const U upper_rhs, const L lower_rhs)
  66. : Lo(lower_rhs), Hi(upper_rhs)
  67. {}
  68. template <typename T, std::enable_if_t<std::is_integral<T>::value && sizeof(THalf) < sizeof(T), size_t> Shift = PartBitSize>
  69. constexpr TWide(const T rhs)
  70. : Lo(rhs), Hi(rhs >> Shift)
  71. {}
  72. template <typename T, std::enable_if_t<std::is_integral<T>::value && sizeof(T) <= sizeof(THalf), bool> Signed = std::is_signed<T>::value>
  73. constexpr TWide(const T rhs)
  74. : Lo(rhs), Hi(Signed && rhs < 0 ? ~0 : 0)
  75. {}
  76. template <typename T, typename TArg = std::enable_if_t<std::is_class<T>::value && std::is_same<T, THalf>::value, THalf>>
  77. constexpr explicit TWide(const T& rhs)
  78. : Lo(rhs), Hi(TIsSigned::value && rhs < 0 ? ~0 : 0)
  79. {}
  80. template <typename T, std::enable_if_t<std::is_integral<T>::value && sizeof(THalf) < sizeof(T), size_t> Shift = PartBitSize>
  81. constexpr TWide& operator=(const T rhs) {
  82. Hi = rhs >> Shift;
  83. Lo = rhs;
  84. return *this;
  85. }
  86. template <typename T, std::enable_if_t<std::is_integral<T>::value && sizeof(T) <= sizeof(THalf), bool> Signed = std::is_signed<T>::value>
  87. constexpr TWide& operator=(const T rhs) {
  88. Hi = Signed && rhs < 0 ? ~0 : 0;
  89. Lo = rhs;
  90. return *this;
  91. }
  92. constexpr explicit operator bool() const { return bool(Hi) || bool(Lo); }
  93. constexpr explicit operator i8() const { return CastImpl<i8>(); }
  94. constexpr explicit operator ui8() const { return CastImpl<ui8>(); }
  95. constexpr explicit operator i16() const { return CastImpl<i16>(); }
  96. constexpr explicit operator ui16() const { return CastImpl<ui16>(); }
  97. constexpr explicit operator i32() const { return CastImpl<i32>(); }
  98. constexpr explicit operator ui32() const { return CastImpl<ui32>(); }
  99. constexpr explicit operator i64() const { return CastImpl<i64>(); }
  100. constexpr explicit operator ui64() const { return CastImpl<ui64>(); }
  101. #ifndef _win_
  102. constexpr explicit operator i128_t() const { return CastImpl<i128_t>(); }
  103. constexpr explicit operator ui128_t() const { return CastImpl<ui128_t>(); }
  104. #endif
  105. constexpr explicit operator float() const {
  106. return TIsSigned::value && Hi < 0 ? -float(-*this) : std::fma(float(Hi), std::exp2(float(PartBitSize)), float(Lo));
  107. }
  108. constexpr explicit operator double() const {
  109. return TIsSigned::value && Hi < 0 ? -double(-*this) : std::fma(double(Hi), std::exp2(double(PartBitSize)), double(Lo));
  110. }
  111. constexpr TWide operator~() const {
  112. return TWide(~Hi, ~Lo);
  113. }
  114. constexpr TWide operator+() const {
  115. return TWide(Hi, Lo);
  116. }
  117. constexpr TWide operator-() const {
  118. const auto sign = THalf(1) << PartBitSize - 1U;
  119. if (TIsSigned::value && !Lo && Hi == sign)
  120. return *this;
  121. return ++~*this;
  122. }
  123. constexpr TWide& operator++() {
  124. if (!++Lo) ++Hi;
  125. return *this;
  126. }
  127. constexpr TWide& operator--() {
  128. if (!Lo--) --Hi;
  129. return *this;
  130. }
  131. constexpr TWide operator++(int) {
  132. const TWide r(*this);
  133. ++*this;
  134. return r;
  135. }
  136. constexpr TWide operator--(int) {
  137. const TWide r(*this);
  138. --*this;
  139. return r;
  140. }
  141. constexpr TWide& operator&=(const TWide& rhs) {
  142. Hi &= rhs.Hi;
  143. Lo &= rhs.Lo;
  144. return *this;
  145. }
  146. constexpr TWide& operator|=(const TWide& rhs) {
  147. Hi |= rhs.Hi;
  148. Lo |= rhs.Lo;
  149. return *this;
  150. }
  151. constexpr TWide& operator^=(const TWide& rhs) {
  152. Hi ^= rhs.Hi;
  153. Lo ^= rhs.Lo;
  154. return *this;
  155. }
  156. constexpr TWide& operator+=(const TWide& rhs) {
  157. const auto l = Lo;
  158. Lo += rhs.Lo;
  159. Hi += rhs.Hi;
  160. if (l > Lo) ++Hi;
  161. return *this;
  162. }
  163. constexpr TWide& operator-=(const TWide& rhs) {
  164. const auto l = Lo;
  165. Lo -= rhs.Lo;
  166. Hi -= rhs.Hi;
  167. if (l < Lo) --Hi;
  168. return *this;
  169. }
  170. constexpr TWide& operator<<=(const TWide& rhs) {
  171. if (const auto shift = size_t(rhs.Lo) % FullBitSize) {
  172. if (shift < PartBitSize) {
  173. Hi = TPart(Hi) << shift;
  174. Hi |= Lo >> (PartBitSize - shift);
  175. Lo <<= shift;
  176. } else {
  177. Hi = Lo << (shift - PartBitSize);
  178. Lo = 0;
  179. }
  180. }
  181. return *this;
  182. }
  183. constexpr TWide& operator>>=(const TWide& rhs) {
  184. if (const auto shift = size_t(rhs.Lo) % FullBitSize) {
  185. if (shift < PartBitSize) {
  186. Lo >>= shift;
  187. Lo |= TPart(Hi) << (PartBitSize - shift);
  188. Hi >>= shift;
  189. } else {
  190. Lo = Hi >> (shift - PartBitSize);
  191. Hi = TIsSigned::value && Hi < 0 ? ~0 : 0;
  192. }
  193. }
  194. return *this;
  195. }
  196. constexpr TWide& operator*=(const TWide& rhs) { return *this = Mul(*this, rhs); }
  197. constexpr TWide& operator/=(const TWide& rhs) { return *this = DivMod(*this, rhs).first; }
  198. constexpr TWide& operator%=(const TWide& rhs) { return *this = DivMod(*this, rhs).second; }
  199. constexpr TWide operator&(const TWide& rhs) const { return TWide(*this) &= rhs; }
  200. constexpr TWide operator|(const TWide& rhs) const { return TWide(*this) |= rhs; }
  201. constexpr TWide operator^(const TWide& rhs) const { return TWide(*this) ^= rhs; }
  202. constexpr TWide operator+(const TWide& rhs) const { return TWide(*this) += rhs; }
  203. constexpr TWide operator-(const TWide& rhs) const { return TWide(*this) -= rhs; }
  204. constexpr TWide operator*(const TWide& rhs) const { return Mul(*this, rhs); }
  205. constexpr TWide operator/(const TWide& rhs) const { return DivMod(*this, rhs).first; }
  206. constexpr TWide operator%(const TWide& rhs) const { return DivMod(*this, rhs).second; }
  207. constexpr TWide operator<<(const TWide& rhs) const { return TWide(*this) <<= rhs; }
  208. constexpr TWide operator>>(const TWide& rhs) const { return TWide(*this) >>= rhs; }
  209. template <typename T>
  210. constexpr std::enable_if_t<std::is_integral<T>::value, T> operator&(const T rhs) const { return T(*this) & rhs; }
  211. constexpr bool operator==(const TWide& rhs) const { return std::tie(Hi, Lo) == std::tie(rhs.Hi, rhs.Lo); }
  212. constexpr bool operator!=(const TWide& rhs) const { return std::tie(Hi, Lo) != std::tie(rhs.Hi, rhs.Lo); }
  213. constexpr bool operator>=(const TWide& rhs) const { return std::tie(Hi, Lo) >= std::tie(rhs.Hi, rhs.Lo); }
  214. constexpr bool operator<=(const TWide& rhs) const { return std::tie(Hi, Lo) <= std::tie(rhs.Hi, rhs.Lo); }
  215. constexpr bool operator>(const TWide& rhs) const { return std::tie(Hi, Lo) > std::tie(rhs.Hi, rhs.Lo); }
  216. constexpr bool operator<(const TWide& rhs) const { return std::tie(Hi, Lo) < std::tie(rhs.Hi, rhs.Lo); }
  217. private:
  218. static constexpr TWide Mul(const TWide& lhs, const TWide& rhs) {
  219. const TPart lq[] = {GetLowerQuarter(lhs.Lo), GetUpperQuarter(lhs.Lo), GetLowerQuarter(lhs.Hi), GetUpperQuarter(lhs.Hi)};
  220. const TPart rq[] = {GetLowerQuarter(rhs.Lo), GetUpperQuarter(rhs.Lo), GetLowerQuarter(rhs.Hi), GetUpperQuarter(rhs.Hi)};
  221. const TPart prod0[] = {TPart(lq[0] * rq[0])};
  222. const TPart prod1[] = {TPart(lq[0] * rq[1]), TPart(lq[1] * rq[0])};
  223. const TPart prod2[] = {TPart(lq[0] * rq[2]), TPart(lq[1] * rq[1]), TPart(lq[2] * rq[0])};
  224. const TPart prod3[] = {TPart(lq[0] * rq[3]), TPart(lq[1] * rq[2]), TPart(lq[2] * rq[1]), TPart(lq[3] * rq[0])};
  225. const TPart fourthQ = GetLowerQuarter(prod0[0]);
  226. const TPart thirdQ = GetUpperQuarter(prod0[0])
  227. + GetLowerQuarter(prod1[0]) + GetLowerQuarter(prod1[1]);
  228. const TPart secondQ = GetUpperQuarter(thirdQ)
  229. + GetUpperQuarter(prod1[0]) + GetUpperQuarter(prod1[1])
  230. + GetLowerQuarter(prod2[0]) + GetLowerQuarter(prod2[1]) + GetLowerQuarter(prod2[2]);
  231. const TPart firstQ = GetUpperQuarter(secondQ)
  232. + GetUpperQuarter(prod2[0]) + GetUpperQuarter(prod2[1]) + GetUpperQuarter(prod2[2])
  233. + GetLowerQuarter(prod3[0]) + GetLowerQuarter(prod3[1]) + GetLowerQuarter(prod3[2]) + GetLowerQuarter(prod3[3]);
  234. return TWide((firstQ << QuarterBitSize) | GetLowerQuarter(secondQ), (thirdQ << QuarterBitSize) | fourthQ);
  235. }
  236. static constexpr std::pair<TWide, TWide> DivMod(const TWide& lhs, const TWide& rhs) {
  237. const bool nl = TIsSigned::value && lhs.Hi < 0;
  238. const bool nr = TIsSigned::value && rhs.Hi < 0;
  239. const TUnsigned l = nl ? -lhs : +lhs, r = nr ? -rhs : +rhs;
  240. TUnsigned div = 0, mod = 0;
  241. for (auto x = l.GetBits(); x;) {
  242. mod <<= 1;
  243. div <<= 1;
  244. if (--x < PartBitSize ? l.Lo & (TPart(1U) << x) : l.Hi & (TPart(1U) << x - PartBitSize)) {
  245. ++mod;
  246. }
  247. if (mod >= r) {
  248. mod -= r;
  249. ++div;
  250. }
  251. }
  252. if (nl) mod = -mod;
  253. if (nr != nl) div = -div;
  254. return {div, mod};
  255. }
  256. };
  257. template<typename T> struct THalfOf;
  258. template<> struct THalfOf<i16> { typedef i8 Type; };
  259. template<> struct THalfOf<ui16> { typedef ui8 Type; };
  260. template<> struct THalfOf<i32> { typedef i16 Type; };
  261. template<> struct THalfOf<ui32> { typedef ui16 Type; };
  262. template<> struct THalfOf<i64> { typedef i32 Type; };
  263. template<> struct THalfOf<ui64> { typedef ui32 Type; };
  264. #ifndef _win_
  265. template<> struct THalfOf<i128_t> { typedef i64 Type; };
  266. template<> struct THalfOf<ui128_t> { typedef ui64 Type; };
  267. #endif
  268. template<typename T> struct THalfOf {};
  269. template<typename T> struct TPairOf;
  270. template<> struct TPairOf<i8> { typedef i16 Type; };
  271. template<> struct TPairOf<ui8> { typedef ui16 Type; };
  272. template<> struct TPairOf<i16> { typedef i32 Type; };
  273. template<> struct TPairOf<ui16> { typedef ui32 Type; };
  274. template<> struct TPairOf<i32> { typedef i64 Type; };
  275. template<> struct TPairOf<ui32> { typedef ui64 Type; };
  276. #ifndef _win_
  277. template<> struct TPairOf<i64> { typedef i128_t Type; };
  278. template<> struct TPairOf<ui64> { typedef ui128_t Type; };
  279. #endif
  280. template<typename T> struct TPairOf {};
  281. }