GroupVarint.cpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. /*
  2. * Copyright 2012-present Facebook, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include <folly/GroupVarint.h>
  17. #include <folly/container/Array.h>
  18. #if HAVE_GROUP_VARINT
  19. namespace folly {
  20. const uint32_t GroupVarint32::kMask[] = {
  21. 0xff,
  22. 0xffff,
  23. 0xffffff,
  24. 0xffffffff,
  25. };
  26. const uint64_t GroupVarint64::kMask[] = {
  27. 0xff,
  28. 0xffff,
  29. 0xffffff,
  30. 0xffffffff,
  31. 0xffffffffffULL,
  32. 0xffffffffffffULL,
  33. 0xffffffffffffffULL,
  34. 0xffffffffffffffffULL,
  35. };
  36. namespace detail {
  37. struct group_varint_table_base_make_item {
  38. constexpr std::size_t get_d(std::size_t index, std::size_t j) const {
  39. return 1u + ((index >> (2 * j)) & 3u);
  40. }
  41. constexpr std::size_t get_offset(std::size_t index, std::size_t j) const {
  42. // clang-format off
  43. return
  44. (j > 0 ? get_d(index, 0) : 0) +
  45. (j > 1 ? get_d(index, 1) : 0) +
  46. (j > 2 ? get_d(index, 2) : 0) +
  47. (j > 3 ? get_d(index, 3) : 0) +
  48. 0;
  49. // clang-format on
  50. }
  51. };
  52. struct group_varint_table_length_make_item : group_varint_table_base_make_item {
  53. constexpr std::uint8_t operator()(std::size_t index) const {
  54. return 1u + get_offset(index, 4);
  55. }
  56. };
  57. // Reference: http://www.stepanovpapers.com/CIKM_2011.pdf
  58. //
  59. // From 17 encoded bytes, we may use between 5 and 17 bytes to encode 4
  60. // integers. The first byte is a key that indicates how many bytes each of
  61. // the 4 integers takes:
  62. //
  63. // bit 0..1: length-1 of first integer
  64. // bit 2..3: length-1 of second integer
  65. // bit 4..5: length-1 of third integer
  66. // bit 6..7: length-1 of fourth integer
  67. //
  68. // The value of the first byte is used as the index in a table which returns
  69. // a mask value for the SSSE3 PSHUFB instruction, which takes an XMM register
  70. // (16 bytes) and shuffles bytes from it into a destination XMM register
  71. // (optionally setting some of them to 0)
  72. //
  73. // For example, if the key has value 4, that means that the first integer
  74. // uses 1 byte, the second uses 2 bytes, the third and fourth use 1 byte each,
  75. // so we set the mask value so that
  76. //
  77. // r[0] = a[0]
  78. // r[1] = 0
  79. // r[2] = 0
  80. // r[3] = 0
  81. //
  82. // r[4] = a[1]
  83. // r[5] = a[2]
  84. // r[6] = 0
  85. // r[7] = 0
  86. //
  87. // r[8] = a[3]
  88. // r[9] = 0
  89. // r[10] = 0
  90. // r[11] = 0
  91. //
  92. // r[12] = a[4]
  93. // r[13] = 0
  94. // r[14] = 0
  95. // r[15] = 0
  96. struct group_varint_table_sse_mask_make_item
  97. : group_varint_table_base_make_item {
  98. constexpr auto partial_item(std::size_t d, std::size_t offset, std::size_t k)
  99. const {
  100. // if k < d, the j'th integer uses d bytes, consume them
  101. // set remaining bytes in result to 0
  102. // 0xff: set corresponding byte in result to 0
  103. return std::uint32_t((k < d ? offset + k : std::size_t(0xff)) << (8 * k));
  104. }
  105. constexpr auto item_impl(std::size_t d, std::size_t offset) const {
  106. // clang-format off
  107. return
  108. partial_item(d, offset, 0) |
  109. partial_item(d, offset, 1) |
  110. partial_item(d, offset, 2) |
  111. partial_item(d, offset, 3) |
  112. 0;
  113. // clang-format on
  114. }
  115. constexpr auto item(std::size_t index, std::size_t j) const {
  116. return item_impl(get_d(index, j), get_offset(index, j));
  117. }
  118. constexpr auto operator()(std::size_t index) const {
  119. return std::array<std::uint32_t, 4>{{
  120. item(index, 0),
  121. item(index, 1),
  122. item(index, 2),
  123. item(index, 3),
  124. }};
  125. }
  126. };
  127. #if FOLLY_SSE >= 3
  128. alignas(16) FOLLY_STORAGE_CONSTEXPR
  129. decltype(groupVarintSSEMasks) groupVarintSSEMasks =
  130. make_array_with<256>(group_varint_table_sse_mask_make_item{});
  131. #endif
  132. FOLLY_STORAGE_CONSTEXPR decltype(groupVarintLengths) groupVarintLengths =
  133. make_array_with<256>(group_varint_table_length_make_item{});
  134. } // namespace detail
  135. } // namespace folly
  136. #endif