text: /*
   * librdkafka - Apache Kafka C library
   *
   * Copyright (c) 2012-2015, Magnus Edenhill
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions are met:
   *
   * 1. Redistributions of source code must retain the above copyright notice,
   *    this list of conditions and the following disclaimer.
   * 2. Redistributions in binary form must reproduce the above copyright notice,
   *    this list of conditions and the following disclaimer in the documentation
   *    and/or other materials provided with the distribution.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   * POSSIBILITY OF SUCH DAMAGE.
   */
  #ifdef __OS400__
  #pragma convert(819)
  #endif
  
  #include "rd.h"
  #include "rdunittest.h"
  #include "rdmurmur2.h"
  #include "rdendian.h"
  
  
  /* MurmurHash2, by Austin Appleby
   *
   * With librdkafka modifications combinining aligned/unaligned variants
   * into the same function.
   */
  
  #define MM_MIX(h,k,m) { k *= m; k ^= k >> r; k *= m; h *= m; h ^= k; }
  
  /*-----------------------------------------------------------------------------
  // Based on MurmurHashNeutral2, by Austin Appleby
  //
  // Same as MurmurHash2, but endian- and alignment-neutral.
  // Half the speed though, alas.
  //
  */
  uint32_t rd_murmur2 (const void *key, size_t len) {
          const uint32_t seed = 0x9747b28c;
          const uint32_t m = 0x5bd1e995;
          const int r = 24;
          uint32_t h = seed ^ (uint32_t)len;
          const unsigned char *tail;
  
  #ifndef __OS400__
          if (likely(((intptr_t)key & 0x3) == 0)) {
  #else
          if(0) { /* we'll try to use OS400 builtin implementation later */
  #endif
                  /* Input is 32-bit word aligned. */
                  const uint32_t *data = (const uint32_t *)key;
  
                  while (len >= 4) {
                          uint32_t k = htole32(*(uint32_t *)data);
  
                          MM_MIX(h,k,m);
  
                          data++;
                          len -= 4;
                  }
  
                  tail = (const unsigned char *)data;
  
          } else {
                  /* Unaligned slower variant */
                  const unsigned char *data = (const unsigned char *)key;
  
                  while (len >= 4) {
                          uint32_t k;
  
                          k  = data[0];
                          k |= data[1] << 8;
                          k |= data[2] << 16;
                          k |= data[3] << 24;
  
                          MM_MIX(h,k,m);
  
                          data += 4;
                          len -= 4;
                  }
  
                  tail = data;
          }
  
          /* Read remaining sub-word */
          switch(len)
          {
          case 3: h ^= tail[2] << 16;
          case 2: h ^= tail[1] << 8;
          case 1: h ^= tail[0];
                  h *= m;
          };
  
          h ^= h >> 13;
          h *= m;
          h ^= h >> 15;
  
          /* Last bit is set to 0 because the java implementation uses int_32
           * and then sets to positive number flipping last bit to 1. */
          return h;
  }
  
  
  /**
   * @brief Unittest for rd_murmur2()
   */
  int unittest_murmur2 (void) {
          const char *short_unaligned = "1234";
          const char *unaligned = "PreAmbleWillBeRemoved,ThePrePartThatIs";
          const char *keysToTest[] = {
                  "kafka",
                  "giberish123456789",
                  short_unaligned,
                  short_unaligned+1,
                  short_unaligned+2,
                  short_unaligned+3,
                  unaligned,
                  unaligned+1,
                  unaligned+2,
                  unaligned+3,
                  "",
                  NULL,
          };
  
          const int32_t java_murmur2_results[] = {
                  0xd067cf64, // kafka
                  0x8f552b0c, // giberish123456789
                  0x9fc97b14, // short_unaligned
                  0xe7c009ca, // short_unaligned+1
                  0x873930da, // short_unaligned+2
                  0x5a4b5ca1, // short_unaligned+3
                  0x78424f1c, // unaligned
                  0x4a62b377, // unaligned+1
                  0xe0e4e09e, // unaligned+2
                  0x62b8b43f, // unaligned+3
                  0x106e08d9, // ""
                  0x106e08d9, // NULL
          };
  
          size_t i;
          for (i = 0; i < RD_ARRAYSIZE(keysToTest); i++) {
                  uint32_t h = rd_murmur2(keysToTest[i],
                                          keysToTest[i] ?
                                          strlen(keysToTest[i]) : 0);
                  RD_UT_ASSERT((int32_t)h == java_murmur2_results[i],
                               "Calculated murmur2 hash 0x%x for \"%s\", "
                               "expected 0x%x",
                               h, keysToTest[i], java_murmur2_results[i]);
          }
          RD_UT_PASS();
  }
  