interface.cc 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. // Copyright 2010 Google Inc. All rights reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // This is the only file where all details of CRC implementation are buried.
  15. #include "interface.h"
  16. #include "aligned_alloc.h"
  17. #include "crc32c_sse4.h"
  18. #include "generic_crc.h"
  19. #include "protected_crc.h"
  20. #include "rolling_crc.h"
  21. // Align all CRC tables on kAlign boundary.
  22. // Shall be exact power of 2.
  23. static size_t kAlign = 4 * 1024;
  24. using namespace crcutil;
  25. #if (!defined(__clang__) && defined(__GNUC__))
  26. // Suppress 'invalid access to non-static data member ... of NULL object'
  27. #undef offsetof
  28. #define offsetof(TYPE, MEMBER) (reinterpret_cast <size_t> \
  29. ((&reinterpret_cast <const char &>( \
  30. reinterpret_cast <const TYPE *>(1)->MEMBER))) - 1)
  31. #endif // defined(__GNUC__)
  32. namespace crcutil_interface {
  33. template<typename CrcImplementation, typename RollingCrcImplementation>
  34. class Implementation : public CRC {
  35. public:
  36. typedef typename CrcImplementation::Crc Crc;
  37. typedef Implementation<CrcImplementation, RollingCrcImplementation> Self;
  38. Implementation(const Crc &poly,
  39. size_t degree,
  40. bool canonical,
  41. const Crc &roll_start_value,
  42. size_t roll_length)
  43. : crc_(poly, degree, canonical),
  44. rolling_crc_(crc_, roll_length, roll_start_value) {
  45. }
  46. static Self *Create(const Crc &poly,
  47. size_t degree,
  48. bool canonical,
  49. const Crc &roll_start_value,
  50. size_t roll_length,
  51. const void **allocated_memory) {
  52. void *memory = AlignedAlloc(sizeof(Self),
  53. offsetof(Self, crc_),
  54. kAlign,
  55. allocated_memory);
  56. return new(memory) Self(poly,
  57. degree,
  58. canonical,
  59. roll_start_value,
  60. roll_length);
  61. }
  62. virtual void Delete() {
  63. AlignedFree(this);
  64. }
  65. void *operator new(size_t, void *p) {
  66. return p;
  67. }
  68. virtual void GeneratingPolynomial(/* OUT */ UINT64 *lo,
  69. /* OUT */ UINT64 *hi = NULL) const {
  70. SetValue(crc_.Base().GeneratingPolynomial(), lo, hi);
  71. }
  72. virtual size_t Degree() const {
  73. return crc_.Base().Degree();
  74. }
  75. virtual void CanonizeValue(/* OUT */ UINT64 *lo,
  76. /* OUT */ UINT64 *hi = NULL) const {
  77. SetValue(crc_.Base().Canonize(), lo, hi);
  78. }
  79. virtual void RollStartValue(/* OUT */ UINT64 *lo,
  80. /* OUT */ UINT64 *hi = NULL) const {
  81. SetValue(rolling_crc_.StartValue(), lo, hi);
  82. }
  83. virtual size_t RollWindowBytes() const {
  84. return rolling_crc_.WindowBytes();
  85. }
  86. virtual void SelfCheckValue(/* OUT */ UINT64 *lo,
  87. /* OUT */ UINT64 *hi = NULL) const {
  88. Crc crc = crc_.CrcDefault(&crc_, sizeof(crc_), 0);
  89. crc = crc_.CrcDefault(&rolling_crc_, sizeof(rolling_crc_), crc);
  90. SetValue(crc, lo, hi);
  91. }
  92. virtual void Compute(const void *data,
  93. size_t bytes,
  94. /* INOUT */ UINT64 *lo,
  95. /* INOUT */ UINT64 *hi = NULL) const {
  96. SetValue(crc_.CrcDefault(data, bytes, GetValue(lo, hi)), lo, hi);
  97. }
  98. virtual void RollStart(const void *data,
  99. /* INOUT */ UINT64 *lo,
  100. /* INOUT */ UINT64 *hi = NULL) const {
  101. SetValue(rolling_crc_.Start(data), lo, hi);
  102. }
  103. virtual void Roll(size_t byte_out,
  104. size_t byte_in,
  105. /* INOUT */ UINT64 *lo,
  106. /* INOUT */ UINT64 *hi = NULL) const {
  107. SetValue(rolling_crc_.Roll(GetValue(lo, hi), byte_out, byte_in), lo, hi);
  108. }
  109. virtual void CrcOfZeroes(UINT64 bytes,
  110. /* INOUT */ UINT64 *lo,
  111. /* INOUT */ UINT64 *hi = NULL) const {
  112. SetValue(crc_.Base().CrcOfZeroes(bytes, GetValue(lo, hi)), lo, hi);
  113. }
  114. virtual void ChangeStartValue(
  115. UINT64 start_old_lo, UINT64 start_old_hi,
  116. UINT64 start_new_lo, UINT64 start_new_hi,
  117. UINT64 bytes,
  118. /* INOUT */ UINT64 *lo,
  119. /* INOUT */ UINT64 *hi = NULL) const {
  120. SetValue(crc_.Base().ChangeStartValue(
  121. GetValue(lo, hi),
  122. bytes,
  123. GetValue(start_old_lo, start_old_hi),
  124. GetValue(start_new_lo, start_new_hi)),
  125. lo,
  126. hi);
  127. }
  128. virtual void Concatenate(UINT64 crcB_lo, UINT64 crcB_hi,
  129. UINT64 bytes_B,
  130. /* INOUT */ UINT64* crcA_lo,
  131. /* INOUT */ UINT64* crcA_hi = NULL) const {
  132. SetValue(crc_.Base().Concatenate(GetValue(crcA_lo, crcA_hi),
  133. GetValue(crcB_lo, crcB_hi),
  134. bytes_B),
  135. crcA_lo,
  136. crcA_hi);
  137. }
  138. virtual size_t StoreComplementaryCrc(
  139. void *dst,
  140. UINT64 message_crc_lo, UINT64 message_crc_hi,
  141. UINT64 result_crc_lo, UINT64 result_crc_hi = 0) const {
  142. return crc_.Base().StoreComplementaryCrc(
  143. dst,
  144. GetValue(message_crc_lo, message_crc_hi),
  145. GetValue(result_crc_lo, result_crc_hi));
  146. }
  147. virtual size_t StoreCrc(void *dst,
  148. UINT64 lo,
  149. UINT64 hi = 0) const {
  150. return crc_.Base().StoreCrc(dst, GetValue(lo, hi));
  151. }
  152. virtual void CrcOfCrc(/* OUT */ UINT64 *lo,
  153. /* OUT */ UINT64 *hi = NULL) const {
  154. SetValue(crc_.Base().CrcOfCrc(), lo, hi);
  155. }
  156. private:
  157. static Crc GetValue(UINT64 *lo, UINT64 *hi) {
  158. if (sizeof(Crc) <= sizeof(*lo)) {
  159. return CrcFromUint64<Crc>(*lo);
  160. } else {
  161. return CrcFromUint64<Crc>(*lo, *hi);
  162. }
  163. }
  164. static Crc GetValue(UINT64 lo, UINT64 hi) {
  165. return CrcFromUint64<Crc>(lo, hi);
  166. }
  167. static void SetValue(const Crc &crc, UINT64 *lo, UINT64 *hi) {
  168. Uint64FromCrc<Crc>(crc,
  169. reinterpret_cast<crcutil::uint64 *>(lo),
  170. reinterpret_cast<crcutil::uint64 *>(hi));
  171. }
  172. const CrcImplementation crc_;
  173. const RollingCrcImplementation rolling_crc_;
  174. const Self &operator =(const Self &) {}
  175. };
  176. #if defined(_MSC_VER)
  177. // 'use_sse4_2' : unreferenced formal parameter
  178. #pragma warning(disable: 4100)
  179. #endif // defined(_MSC_VER)
  180. bool CRC::IsSSE42Available() {
  181. #if HAVE_AMD64 || HAVE_I386
  182. return Crc32cSSE4::IsSSE42Available();
  183. #else
  184. return false;
  185. #endif // HAVE_AMD64 || HAVE_I386
  186. }
  187. CRC::~CRC() {}
  188. CRC::CRC() {}
  189. CRC *CRC::Create(UINT64 poly_lo,
  190. UINT64 poly_hi,
  191. size_t degree,
  192. bool canonical,
  193. UINT64 roll_start_value_lo,
  194. UINT64 roll_start_value_hi,
  195. size_t roll_length,
  196. bool use_sse4_2,
  197. const void **allocated_memory) {
  198. if (degree == 0) {
  199. return NULL;
  200. }
  201. if (degree > 64) {
  202. #if !HAVE_SSE2
  203. return NULL;
  204. #else
  205. if (degree > 128) {
  206. return NULL;
  207. }
  208. uint128_sse2 poly = CrcFromUint64<uint128_sse2>(poly_lo, poly_hi);
  209. if (degree != 128 && (poly >> degree) != 0) {
  210. return NULL;
  211. }
  212. uint128_sse2 roll_start_value =
  213. CrcFromUint64<uint128_sse2>(roll_start_value_lo, roll_start_value_hi);
  214. if (degree != 128 && (roll_start_value >> degree) != 0) {
  215. return NULL;
  216. }
  217. #if HAVE_I386
  218. typedef GenericCrc<uint128_sse2, uint128_sse2, crcutil::uint32, 3> Crc128;
  219. #elif defined(__GNUC__) && GCC_VERSION_AVAILABLE(4, 5)
  220. typedef GenericCrc<uint128_sse2, uint128_sse2, crcutil::uint64, 6> Crc128;
  221. #else
  222. typedef GenericCrc<uint128_sse2, uint128_sse2, crcutil::uint64, 4> Crc128;
  223. #endif // HAVE_I386
  224. return Implementation<Crc128, RollingCrc<Crc128> >::Create(
  225. poly,
  226. degree,
  227. canonical,
  228. roll_start_value,
  229. roll_length,
  230. allocated_memory);
  231. #endif // !HAVE_SSE2
  232. }
  233. #if CRCUTIL_USE_MM_CRC32 && (HAVE_I386 || HAVE_AMD64)
  234. if (use_sse4_2 &&
  235. degree == Crc32cSSE4::FixedDegree() &&
  236. poly_lo == Crc32cSSE4::FixedGeneratingPolynomial() &&
  237. poly_hi == 0) {
  238. if (roll_start_value_hi != 0 || (roll_start_value_lo >> 32) != 0) {
  239. return NULL;
  240. }
  241. return Implementation<Crc32cSSE4, RollingCrc32cSSE4>::Create(
  242. static_cast<size_t>(poly_lo),
  243. degree,
  244. canonical,
  245. static_cast<size_t>(roll_start_value_lo),
  246. static_cast<size_t>(roll_length),
  247. allocated_memory);
  248. }
  249. #endif // CRCUTIL_USE_MM_CRC32 && (HAVE_I386 || HAVE_AMD64)
  250. if (poly_hi != 0 || (degree != 64 && (poly_lo >> degree) != 0)) {
  251. return NULL;
  252. }
  253. if (roll_start_value_hi != 0 ||
  254. (degree != 64 && (roll_start_value_lo >> degree) != 0)) {
  255. return NULL;
  256. }
  257. typedef GenericCrc<crcutil::uint64, crcutil::uint64, crcutil::uint64, 4>
  258. Crc64;
  259. return Implementation<Crc64, RollingCrc<Crc64> >::Create(
  260. poly_lo,
  261. degree,
  262. canonical,
  263. roll_start_value_lo,
  264. roll_length,
  265. allocated_memory);
  266. }
  267. } // namespace crcutil_interface