tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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_