snappy-stubs-internal.h (17334B)
1 // Copyright 2011 Google Inc. All Rights Reserved. 2 // 3 // Redistribution and use in source and binary forms, with or without 4 // modification, are permitted provided that the following conditions are 5 // met: 6 // 7 // * Redistributions of source code must retain the above copyright 8 // notice, this list of conditions and the following disclaimer. 9 // * Redistributions in binary form must reproduce the above 10 // copyright notice, this list of conditions and the following disclaimer 11 // in the documentation and/or other materials provided with the 12 // distribution. 13 // * Neither the name of Google Inc. nor the names of its 14 // contributors may be used to endorse or promote products derived from 15 // this software without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 // 29 // Various stubs for the open-source version of Snappy. 30 31 #ifndef THIRD_PARTY_SNAPPY_OPENSOURCE_SNAPPY_STUBS_INTERNAL_H_ 32 #define THIRD_PARTY_SNAPPY_OPENSOURCE_SNAPPY_STUBS_INTERNAL_H_ 33 34 #if HAVE_CONFIG_H 35 #include "config.h" 36 #endif 37 38 #include <stdint.h> 39 40 #include <cassert> 41 #include <cstdlib> 42 #include <cstring> 43 #include <limits> 44 #include <string> 45 46 #if HAVE_SYS_MMAN_H 47 #include <sys/mman.h> 48 #endif 49 50 #if HAVE_UNISTD_H 51 #include <unistd.h> 52 #endif 53 54 #if defined(_MSC_VER) 55 #include <intrin.h> 56 #endif // defined(_MSC_VER) 57 58 #ifndef __has_feature 59 #define __has_feature(x) 0 60 #endif 61 62 #if __has_feature(memory_sanitizer) 63 #include <sanitizer/msan_interface.h> 64 #define SNAPPY_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \ 65 __msan_unpoison((address), (size)) 66 #else 67 #define SNAPPY_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) /* empty */ 68 #endif // __has_feature(memory_sanitizer) 69 70 #include "snappy-stubs-public.h" 71 72 // Used to enable 64-bit optimized versions of some routines. 73 #if defined(__PPC64__) || defined(__powerpc64__) 74 #define ARCH_PPC 1 75 #elif defined(__aarch64__) || defined(_M_ARM64) 76 #define ARCH_ARM 1 77 #endif 78 79 // Needed by OS X, among others. 80 #ifndef MAP_ANONYMOUS 81 #define MAP_ANONYMOUS MAP_ANON 82 #endif 83 84 // The size of an array, if known at compile-time. 85 // Will give unexpected results if used on a pointer. 86 // We undefine it first, since some compilers already have a definition. 87 #ifdef ARRAYSIZE 88 #undef ARRAYSIZE 89 #endif 90 #define ARRAYSIZE(a) int{sizeof(a) / sizeof(*(a))} 91 92 // Static prediction hints. 93 #if HAVE_BUILTIN_EXPECT 94 #define SNAPPY_PREDICT_FALSE(x) (__builtin_expect(x, 0)) 95 #define SNAPPY_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1)) 96 #else 97 #define SNAPPY_PREDICT_FALSE(x) x 98 #define SNAPPY_PREDICT_TRUE(x) x 99 #endif // HAVE_BUILTIN_EXPECT 100 101 // Inlining hints. 102 #if HAVE_ATTRIBUTE_ALWAYS_INLINE 103 #define SNAPPY_ATTRIBUTE_ALWAYS_INLINE __attribute__((always_inline)) 104 #else 105 #define SNAPPY_ATTRIBUTE_ALWAYS_INLINE 106 #endif // HAVE_ATTRIBUTE_ALWAYS_INLINE 107 108 #if HAVE_BUILTIN_PREFETCH 109 #define SNAPPY_PREFETCH(ptr) __builtin_prefetch(ptr, 0, 3) 110 #else 111 #define SNAPPY_PREFETCH(ptr) (void)(ptr) 112 #endif 113 114 // Stubbed version of ABSL_FLAG. 115 // 116 // In the open source version, flags can only be changed at compile time. 117 #define SNAPPY_FLAG(flag_type, flag_name, default_value, help) \ 118 flag_type FLAGS_ ## flag_name = default_value 119 120 namespace snappy { 121 122 // Stubbed version of absl::GetFlag(). 123 template <typename T> 124 inline T GetFlag(T flag) { return flag; } 125 126 static const uint32_t kuint32max = std::numeric_limits<uint32_t>::max(); 127 static const int64_t kint64max = std::numeric_limits<int64_t>::max(); 128 129 // Potentially unaligned loads and stores. 130 131 inline uint16_t UNALIGNED_LOAD16(const void *p) { 132 // Compiles to a single movzx/ldrh on clang/gcc/msvc. 133 uint16_t v; 134 std::memcpy(&v, p, sizeof(v)); 135 return v; 136 } 137 138 inline uint32_t UNALIGNED_LOAD32(const void *p) { 139 // Compiles to a single mov/ldr on clang/gcc/msvc. 140 uint32_t v; 141 std::memcpy(&v, p, sizeof(v)); 142 return v; 143 } 144 145 inline uint64_t UNALIGNED_LOAD64(const void *p) { 146 // Compiles to a single mov/ldr on clang/gcc/msvc. 147 uint64_t v; 148 std::memcpy(&v, p, sizeof(v)); 149 return v; 150 } 151 152 inline void UNALIGNED_STORE16(void *p, uint16_t v) { 153 // Compiles to a single mov/strh on clang/gcc/msvc. 154 std::memcpy(p, &v, sizeof(v)); 155 } 156 157 inline void UNALIGNED_STORE32(void *p, uint32_t v) { 158 // Compiles to a single mov/str on clang/gcc/msvc. 159 std::memcpy(p, &v, sizeof(v)); 160 } 161 162 inline void UNALIGNED_STORE64(void *p, uint64_t v) { 163 // Compiles to a single mov/str on clang/gcc/msvc. 164 std::memcpy(p, &v, sizeof(v)); 165 } 166 167 // Convert to little-endian storage, opposite of network format. 168 // Convert x from host to little endian: x = LittleEndian.FromHost(x); 169 // convert x from little endian to host: x = LittleEndian.ToHost(x); 170 // 171 // Store values into unaligned memory converting to little endian order: 172 // LittleEndian.Store16(p, x); 173 // 174 // Load unaligned values stored in little endian converting to host order: 175 // x = LittleEndian.Load16(p); 176 class LittleEndian { 177 public: 178 // Functions to do unaligned loads and stores in little-endian order. 179 static inline uint16_t Load16(const void *ptr) { 180 // Compiles to a single mov/str on recent clang and gcc. 181 #if SNAPPY_IS_BIG_ENDIAN 182 const uint8_t* const buffer = reinterpret_cast<const uint8_t*>(ptr); 183 return (static_cast<uint16_t>(buffer[0])) | 184 (static_cast<uint16_t>(buffer[1]) << 8); 185 #else 186 // memcpy() turns into a single instruction early in the optimization 187 // pipeline (relatively to a series of byte accesses). So, using memcpy 188 // instead of byte accesses may lead to better decisions in more stages of 189 // the optimization pipeline. 190 uint16_t value; 191 std::memcpy(&value, ptr, 2); 192 return value; 193 #endif 194 } 195 196 static inline uint32_t Load32(const void *ptr) { 197 // Compiles to a single mov/str on recent clang and gcc. 198 #if SNAPPY_IS_BIG_ENDIAN 199 const uint8_t* const buffer = reinterpret_cast<const uint8_t*>(ptr); 200 return (static_cast<uint32_t>(buffer[0])) | 201 (static_cast<uint32_t>(buffer[1]) << 8) | 202 (static_cast<uint32_t>(buffer[2]) << 16) | 203 (static_cast<uint32_t>(buffer[3]) << 24); 204 #else 205 // See Load16() for the rationale of using memcpy(). 206 uint32_t value; 207 std::memcpy(&value, ptr, 4); 208 return value; 209 #endif 210 } 211 212 static inline uint64_t Load64(const void *ptr) { 213 // Compiles to a single mov/str on recent clang and gcc. 214 #if SNAPPY_IS_BIG_ENDIAN 215 const uint8_t* const buffer = reinterpret_cast<const uint8_t*>(ptr); 216 return (static_cast<uint64_t>(buffer[0])) | 217 (static_cast<uint64_t>(buffer[1]) << 8) | 218 (static_cast<uint64_t>(buffer[2]) << 16) | 219 (static_cast<uint64_t>(buffer[3]) << 24) | 220 (static_cast<uint64_t>(buffer[4]) << 32) | 221 (static_cast<uint64_t>(buffer[5]) << 40) | 222 (static_cast<uint64_t>(buffer[6]) << 48) | 223 (static_cast<uint64_t>(buffer[7]) << 56); 224 #else 225 // See Load16() for the rationale of using memcpy(). 226 uint64_t value; 227 std::memcpy(&value, ptr, 8); 228 return value; 229 #endif 230 } 231 232 static inline void Store16(void *dst, uint16_t value) { 233 // Compiles to a single mov/str on recent clang and gcc. 234 #if SNAPPY_IS_BIG_ENDIAN 235 uint8_t* const buffer = reinterpret_cast<uint8_t*>(dst); 236 buffer[0] = static_cast<uint8_t>(value); 237 buffer[1] = static_cast<uint8_t>(value >> 8); 238 #else 239 // See Load16() for the rationale of using memcpy(). 240 std::memcpy(dst, &value, 2); 241 #endif 242 } 243 244 static void Store32(void *dst, uint32_t value) { 245 // Compiles to a single mov/str on recent clang and gcc. 246 #if SNAPPY_IS_BIG_ENDIAN 247 uint8_t* const buffer = reinterpret_cast<uint8_t*>(dst); 248 buffer[0] = static_cast<uint8_t>(value); 249 buffer[1] = static_cast<uint8_t>(value >> 8); 250 buffer[2] = static_cast<uint8_t>(value >> 16); 251 buffer[3] = static_cast<uint8_t>(value >> 24); 252 #else 253 // See Load16() for the rationale of using memcpy(). 254 std::memcpy(dst, &value, 4); 255 #endif 256 } 257 258 static void Store64(void* dst, uint64_t value) { 259 // Compiles to a single mov/str on recent clang and gcc. 260 #if SNAPPY_IS_BIG_ENDIAN 261 uint8_t* const buffer = reinterpret_cast<uint8_t*>(dst); 262 buffer[0] = static_cast<uint8_t>(value); 263 buffer[1] = static_cast<uint8_t>(value >> 8); 264 buffer[2] = static_cast<uint8_t>(value >> 16); 265 buffer[3] = static_cast<uint8_t>(value >> 24); 266 buffer[4] = static_cast<uint8_t>(value >> 32); 267 buffer[5] = static_cast<uint8_t>(value >> 40); 268 buffer[6] = static_cast<uint8_t>(value >> 48); 269 buffer[7] = static_cast<uint8_t>(value >> 56); 270 #else 271 // See Load16() for the rationale of using memcpy(). 272 std::memcpy(dst, &value, 8); 273 #endif 274 } 275 276 static inline constexpr bool IsLittleEndian() { 277 #if SNAPPY_IS_BIG_ENDIAN 278 return false; 279 #else 280 return true; 281 #endif // SNAPPY_IS_BIG_ENDIAN 282 } 283 }; 284 285 // Some bit-manipulation functions. 286 class Bits { 287 public: 288 // Return floor(log2(n)) for positive integer n. 289 static int Log2FloorNonZero(uint32_t n); 290 291 // Return floor(log2(n)) for positive integer n. Returns -1 iff n == 0. 292 static int Log2Floor(uint32_t n); 293 294 // Return the first set least / most significant bit, 0-indexed. Returns an 295 // undefined value if n == 0. FindLSBSetNonZero() is similar to ffs() except 296 // that it's 0-indexed. 297 static int FindLSBSetNonZero(uint32_t n); 298 299 static int FindLSBSetNonZero64(uint64_t n); 300 301 private: 302 // No copying 303 Bits(const Bits&); 304 void operator=(const Bits&); 305 }; 306 307 #if HAVE_BUILTIN_CTZ 308 309 inline int Bits::Log2FloorNonZero(uint32_t n) { 310 assert(n != 0); 311 // (31 ^ x) is equivalent to (31 - x) for x in [0, 31]. An easy proof 312 // represents subtraction in base 2 and observes that there's no carry. 313 // 314 // GCC and Clang represent __builtin_clz on x86 as 31 ^ _bit_scan_reverse(x). 315 // Using "31 ^" here instead of "31 -" allows the optimizer to strip the 316 // function body down to _bit_scan_reverse(x). 317 return 31 ^ __builtin_clz(n); 318 } 319 320 inline int Bits::Log2Floor(uint32_t n) { 321 return (n == 0) ? -1 : Bits::Log2FloorNonZero(n); 322 } 323 324 inline int Bits::FindLSBSetNonZero(uint32_t n) { 325 assert(n != 0); 326 return __builtin_ctz(n); 327 } 328 329 #elif defined(_MSC_VER) 330 331 inline int Bits::Log2FloorNonZero(uint32_t n) { 332 assert(n != 0); 333 // NOLINTNEXTLINE(runtime/int): The MSVC intrinsic demands unsigned long. 334 unsigned long where; 335 _BitScanReverse(&where, n); 336 return static_cast<int>(where); 337 } 338 339 inline int Bits::Log2Floor(uint32_t n) { 340 // NOLINTNEXTLINE(runtime/int): The MSVC intrinsic demands unsigned long. 341 unsigned long where; 342 if (_BitScanReverse(&where, n)) 343 return static_cast<int>(where); 344 return -1; 345 } 346 347 inline int Bits::FindLSBSetNonZero(uint32_t n) { 348 assert(n != 0); 349 // NOLINTNEXTLINE(runtime/int): The MSVC intrinsic demands unsigned long. 350 unsigned long where; 351 if (_BitScanForward(&where, n)) 352 return static_cast<int>(where); 353 return 32; 354 } 355 356 #else // Portable versions. 357 358 inline int Bits::Log2FloorNonZero(uint32_t n) { 359 assert(n != 0); 360 361 int log = 0; 362 uint32_t value = n; 363 for (int i = 4; i >= 0; --i) { 364 int shift = (1 << i); 365 uint32_t x = value >> shift; 366 if (x != 0) { 367 value = x; 368 log += shift; 369 } 370 } 371 assert(value == 1); 372 return log; 373 } 374 375 inline int Bits::Log2Floor(uint32_t n) { 376 return (n == 0) ? -1 : Bits::Log2FloorNonZero(n); 377 } 378 379 inline int Bits::FindLSBSetNonZero(uint32_t n) { 380 assert(n != 0); 381 382 int rc = 31; 383 for (int i = 4, shift = 1 << 4; i >= 0; --i) { 384 const uint32_t x = n << shift; 385 if (x != 0) { 386 n = x; 387 rc -= shift; 388 } 389 shift >>= 1; 390 } 391 return rc; 392 } 393 394 #endif // End portable versions. 395 396 #if HAVE_BUILTIN_CTZ 397 398 inline int Bits::FindLSBSetNonZero64(uint64_t n) { 399 assert(n != 0); 400 return __builtin_ctzll(n); 401 } 402 403 #elif defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64)) 404 // _BitScanForward64() is only available on x64 and ARM64. 405 406 inline int Bits::FindLSBSetNonZero64(uint64_t n) { 407 assert(n != 0); 408 // NOLINTNEXTLINE(runtime/int): The MSVC intrinsic demands unsigned long. 409 unsigned long where; 410 if (_BitScanForward64(&where, n)) 411 return static_cast<int>(where); 412 return 64; 413 } 414 415 #else // Portable version. 416 417 // FindLSBSetNonZero64() is defined in terms of FindLSBSetNonZero(). 418 inline int Bits::FindLSBSetNonZero64(uint64_t n) { 419 assert(n != 0); 420 421 const uint32_t bottombits = static_cast<uint32_t>(n); 422 if (bottombits == 0) { 423 // Bottom bits are zero, so scan the top bits. 424 return 32 + FindLSBSetNonZero(static_cast<uint32_t>(n >> 32)); 425 } else { 426 return FindLSBSetNonZero(bottombits); 427 } 428 } 429 430 #endif // HAVE_BUILTIN_CTZ 431 432 // Variable-length integer encoding. 433 class Varint { 434 public: 435 // Maximum lengths of varint encoding of uint32_t. 436 static const int kMax32 = 5; 437 438 // Attempts to parse a varint32 from a prefix of the bytes in [ptr,limit-1]. 439 // Never reads a character at or beyond limit. If a valid/terminated varint32 440 // was found in the range, stores it in *OUTPUT and returns a pointer just 441 // past the last byte of the varint32. Else returns NULL. On success, 442 // "result <= limit". 443 static const char* Parse32WithLimit(const char* ptr, const char* limit, 444 uint32_t* OUTPUT); 445 446 // REQUIRES "ptr" points to a buffer of length sufficient to hold "v". 447 // EFFECTS Encodes "v" into "ptr" and returns a pointer to the 448 // byte just past the last encoded byte. 449 static char* Encode32(char* ptr, uint32_t v); 450 451 // EFFECTS Appends the varint representation of "value" to "*s". 452 static void Append32(std::string* s, uint32_t value); 453 }; 454 455 inline const char* Varint::Parse32WithLimit(const char* p, 456 const char* l, 457 uint32_t* OUTPUT) { 458 const unsigned char* ptr = reinterpret_cast<const unsigned char*>(p); 459 const unsigned char* limit = reinterpret_cast<const unsigned char*>(l); 460 uint32_t b, result; 461 if (ptr >= limit) return NULL; 462 b = *(ptr++); result = b & 127; if (b < 128) goto done; 463 if (ptr >= limit) return NULL; 464 b = *(ptr++); result |= (b & 127) << 7; if (b < 128) goto done; 465 if (ptr >= limit) return NULL; 466 b = *(ptr++); result |= (b & 127) << 14; if (b < 128) goto done; 467 if (ptr >= limit) return NULL; 468 b = *(ptr++); result |= (b & 127) << 21; if (b < 128) goto done; 469 if (ptr >= limit) return NULL; 470 b = *(ptr++); result |= (b & 127) << 28; if (b < 16) goto done; 471 return NULL; // Value is too long to be a varint32 472 done: 473 *OUTPUT = result; 474 return reinterpret_cast<const char*>(ptr); 475 } 476 477 inline char* Varint::Encode32(char* sptr, uint32_t v) { 478 // Operate on characters as unsigneds 479 uint8_t* ptr = reinterpret_cast<uint8_t*>(sptr); 480 static const uint8_t B = 128; 481 if (v < (1 << 7)) { 482 *(ptr++) = static_cast<uint8_t>(v); 483 } else if (v < (1 << 14)) { 484 *(ptr++) = static_cast<uint8_t>(v | B); 485 *(ptr++) = static_cast<uint8_t>(v >> 7); 486 } else if (v < (1 << 21)) { 487 *(ptr++) = static_cast<uint8_t>(v | B); 488 *(ptr++) = static_cast<uint8_t>((v >> 7) | B); 489 *(ptr++) = static_cast<uint8_t>(v >> 14); 490 } else if (v < (1 << 28)) { 491 *(ptr++) = static_cast<uint8_t>(v | B); 492 *(ptr++) = static_cast<uint8_t>((v >> 7) | B); 493 *(ptr++) = static_cast<uint8_t>((v >> 14) | B); 494 *(ptr++) = static_cast<uint8_t>(v >> 21); 495 } else { 496 *(ptr++) = static_cast<uint8_t>(v | B); 497 *(ptr++) = static_cast<uint8_t>((v>>7) | B); 498 *(ptr++) = static_cast<uint8_t>((v>>14) | B); 499 *(ptr++) = static_cast<uint8_t>((v>>21) | B); 500 *(ptr++) = static_cast<uint8_t>(v >> 28); 501 } 502 return reinterpret_cast<char*>(ptr); 503 } 504 505 // If you know the internal layout of the std::string in use, you can 506 // replace this function with one that resizes the string without 507 // filling the new space with zeros (if applicable) -- 508 // it will be non-portable but faster. 509 inline void STLStringResizeUninitialized(std::string* s, size_t new_size) { 510 s->resize(new_size); 511 } 512 513 // Return a mutable char* pointing to a string's internal buffer, 514 // which may not be null-terminated. Writing through this pointer will 515 // modify the string. 516 // 517 // string_as_array(&str)[i] is valid for 0 <= i < str.size() until the 518 // next call to a string method that invalidates iterators. 519 // 520 // As of 2006-04, there is no standard-blessed way of getting a 521 // mutable reference to a string's internal buffer. However, issue 530 522 // (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-defects.html#530) 523 // proposes this as the method. It will officially be part of the standard 524 // for C++0x. This should already work on all current implementations. 525 inline char* string_as_array(std::string* str) { 526 return str->empty() ? NULL : &*str->begin(); 527 } 528 529 } // namespace snappy 530 531 #endif // THIRD_PARTY_SNAPPY_OPENSOURCE_SNAPPY_STUBS_INTERNAL_H_