├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── c_src ├── Makefile ├── xxhash.c ├── xxhash.h └── xxhash_nif.c ├── doc ├── edoc-info ├── erlang.png ├── index.html ├── modules-frame.html ├── overview-summary.html ├── packages-frame.html ├── stylesheet.css └── xxhash.html ├── priv └── edocs.css ├── rebar.config └── src ├── xxhash.app.src └── xxhash.erl /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | .ebin 3 | *.beam 4 | .DS* 5 | .eunit 6 | ebin 7 | *.so 8 | .rebar 9 | *.d 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: erlang 3 | otp_release: 4 | - 17.1 5 | - 17.5 6 | - 18.2.1 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright ©2013 Pierre Matri 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | The Software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or the use or other dealings in the Software. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # erlang-xxhash [![Build Status](https://travis-ci.org/pierreis/erlang-xxhash.svg?branch=master)](https://travis-ci.org/pierreis/erlang-xxhash) 2 | 3 | Simple Erlang wrapper for the [xxHash](http://code.google.com/p/xxhash/) algorithm. 4 | 5 | 6 | ## Usage 7 | 8 | ```erlang 9 | application:start(xxhash). 10 | Text = "test". 11 | Seed = 12345. 12 | 13 | 14 | %% Simple usage 15 | 16 | xxhash:hash32(Text, Seed). % => 3834992036 17 | xxhash:hash32(Text). % => 1042293711 18 | 19 | xxhash:hash64(Text, Seed). % => 7624679986283906467 20 | xxhash:hash64(Text). % => 5754696928334414137 21 | 22 | 23 | %% Advanced usage 24 | 25 | Handle32 = xxhash:hash32_init(Seed). 26 | xxhash:hash32_update(Handle32, Text). % => ok 27 | xxhash:hash32_digest(Handle32). % => 3834992036 (Intermediate digest) 28 | xxhash:hash32_update(Handle32, <<"Foo">>). % Support for binary values. 29 | xxhash:hash32_update(Handle32, 42). % Support for integers. 30 | xxhash:hash32_update(Handle32, 13.37). % Support for floats. 31 | xxhash:hash32_update(Handle32, moo). % Support for atoms. 32 | xxhash:hash32_digest(Handle32). % => 3243777239 33 | 34 | Handle64 = xxhash:hash64_init(Seed). 35 | xxhash:hash64_update(Handle64, Text). % => ok 36 | xxhash:hash64_digest(Handle64). % => 7624679986283906467 (Intermediate digest) 37 | xxhash:hash64_update(Handle64, <<"Foo">>). % Support for binary values. 38 | xxhash:hash64_update(Handle64, 42). % Support for integers. 39 | xxhash:hash64_update(Handle64, 13.37). % Support for floats. 40 | xxhash:hash64_update(Handle64, moo). % Support for atoms. 41 | xxhash:hash64_digest(Handle64). % => 10617254975351441063 42 | ``` 43 | 44 | 45 | ## Licenses 46 | 47 | This program is distributed under the MIT License. 48 | 49 | xxHash library is distributed under New BSD License. 50 | 51 | 52 | ## Bug reports and feature requests 53 | 54 | You are very welcome to contribute to this library. To do so, simply report bugs, submit feature requests or 55 | make pull requests on Github: https://github.com/pierresforge/erlang-xxhash. 56 | -------------------------------------------------------------------------------- /c_src/Makefile: -------------------------------------------------------------------------------- 1 | # Based on c_src.mk from erlang.mk by Loic Hoguin 2 | 3 | CURDIR := $(shell pwd) 4 | BASEDIR := $(abspath $(CURDIR)/..) 5 | 6 | PROJECT = xxhash 7 | 8 | ERTS_INCLUDE_DIR ?= $(shell erl -noshell -s init stop -eval "io:format(\"~s/erts-~s/include/\", [code:root_dir(), erlang:system_info(version)]).") 9 | ERL_INTERFACE_INCLUDE_DIR ?= $(shell erl -noshell -s init stop -eval "io:format(\"~s\", [code:lib_dir(erl_interface, include)]).") 10 | ERL_INTERFACE_LIB_DIR ?= $(shell erl -noshell -s init stop -eval "io:format(\"~s\", [code:lib_dir(erl_interface, lib)]).") 11 | 12 | C_SRC_DIR = $(CURDIR) 13 | C_SRC_OUTPUT ?= $(CURDIR)/../priv/$(PROJECT).so 14 | 15 | # System type and C compiler/flags. 16 | 17 | UNAME_SYS := $(shell uname -s) 18 | ifeq ($(UNAME_SYS), Darwin) 19 | CC ?= cc 20 | CFLAGS ?= -O3 -std=c99 -Wall -W -Wundef -Wmissing-prototypes -Wno-implicit-function-declaration 21 | CXXFLAGS ?= -O3 -Wall -W -Wundef -Wno-implicit-function-declaration 22 | LDFLAGS ?= -flat_namespace -undefined suppress 23 | else ifeq ($(UNAME_SYS), FreeBSD) 24 | CC ?= cc 25 | CFLAGS ?= -O3 -std=c99 -Wall -Wmissing-prototypes -Wno-implicit-function-declaration 26 | CXXFLAGS ?= -O3 -Wall -W -Wundef -Wno-implicit-function-declaration 27 | else ifeq ($(UNAME_SYS), Linux) 28 | CC ?= gcc 29 | CFLAGS ?= -O3 -std=c99 -Wall -Wmissing-prototypes -Wno-implicit-function-declaration 30 | CXXFLAGS ?= -O3 -Wall -W -Wundef -Wno-implicit-function-declaration 31 | endif 32 | 33 | CFLAGS += -fPIC -I $(ERTS_INCLUDE_DIR) -I $(ERL_INTERFACE_INCLUDE_DIR) 34 | CXXFLAGS += -fPIC -I $(ERTS_INCLUDE_DIR) -I $(ERL_INTERFACE_INCLUDE_DIR) 35 | 36 | LDLIBS += -L $(ERL_INTERFACE_LIB_DIR) -lei 37 | LDFLAGS += -shared 38 | 39 | # Verbosity. 40 | 41 | c_verbose_0 = @echo " C " $(?F); 42 | c_verbose = $(c_verbose_$(V)) 43 | 44 | cpp_verbose_0 = @echo " CPP " $(?F); 45 | cpp_verbose = $(cpp_verbose_$(V)) 46 | 47 | link_verbose_0 = @echo " LD " $(@F); 48 | link_verbose = $(link_verbose_$(V)) 49 | 50 | SOURCES := $(shell find $(C_SRC_DIR) -type f \( -name "*.c" -o -name "*.C" -o -name "*.cc" -o -name "*.cpp" \)) 51 | OBJECTS = $(addsuffix .o, $(basename $(SOURCES))) 52 | 53 | COMPILE_C = $(c_verbose) $(CC) $(CFLAGS) $(CPPFLAGS) -c 54 | COMPILE_CPP = $(cpp_verbose) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c 55 | 56 | $(C_SRC_OUTPUT): $(OBJECTS) 57 | @mkdir -p $(BASEDIR)/priv/ 58 | $(link_verbose) $(CC) $(OBJECTS) $(LDFLAGS) $(LDLIBS) -o $(C_SRC_OUTPUT) 59 | 60 | %.o: %.c 61 | $(COMPILE_C) $(OUTPUT_OPTION) $< 62 | 63 | %.o: %.cc 64 | $(COMPILE_CPP) $(OUTPUT_OPTION) $< 65 | 66 | %.o: %.C 67 | $(COMPILE_CPP) $(OUTPUT_OPTION) $< 68 | 69 | %.o: %.cpp 70 | $(COMPILE_CPP) $(OUTPUT_OPTION) $< 71 | 72 | clean: 73 | @rm -f $(C_SRC_OUTPUT) $(OBJECTS) 74 | -------------------------------------------------------------------------------- /c_src/xxhash.c: -------------------------------------------------------------------------------- 1 | /* 2 | * xxHash - Fast Hash algorithm 3 | * Copyright (C) 2012-2016, Yann Collet 4 | * 5 | * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are 9 | * met: 10 | * 11 | * * Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * * Redistributions in binary form must reproduce the above 14 | * copyright notice, this list of conditions and the following disclaimer 15 | * in the documentation and/or other materials provided with the 16 | * distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | * 30 | * You can contact the author at : 31 | * - xxHash homepage: http://www.xxhash.com 32 | * - xxHash source repository : https://github.com/Cyan4973/xxHash 33 | */ 34 | 35 | 36 | /* ************************************* 37 | * Tuning parameters 38 | ***************************************/ 39 | /*!XXH_FORCE_MEMORY_ACCESS : 40 | * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable. 41 | * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal. 42 | * The below switch allow to select different access method for improved performance. 43 | * Method 0 (default) : use `memcpy()`. Safe and portable. 44 | * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable). 45 | * This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`. 46 | * Method 2 : direct access. This method doesn't depend on compiler but violate C standard. 47 | * It can generate buggy code on targets which do not support unaligned memory accesses. 48 | * But in some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6) 49 | * See http://stackoverflow.com/a/32095106/646947 for details. 50 | * Prefer these methods in priority order (0 > 1 > 2) 51 | */ 52 | #ifndef XXH_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ 53 | # if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) ) 54 | # define XXH_FORCE_MEMORY_ACCESS 2 55 | # elif defined(__INTEL_COMPILER) || \ 56 | (defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) )) 57 | # define XXH_FORCE_MEMORY_ACCESS 1 58 | # endif 59 | #endif 60 | 61 | /*!XXH_ACCEPT_NULL_INPUT_POINTER : 62 | * If the input pointer is a null pointer, xxHash default behavior is to trigger a memory access error, since it is a bad pointer. 63 | * When this option is enabled, xxHash output for null input pointers will be the same as a null-length input. 64 | * By default, this option is disabled. To enable it, uncomment below define : 65 | */ 66 | /* #define XXH_ACCEPT_NULL_INPUT_POINTER 1 */ 67 | 68 | /*!XXH_FORCE_NATIVE_FORMAT : 69 | * By default, xxHash library provides endian-independent Hash values, based on little-endian convention. 70 | * Results are therefore identical for little-endian and big-endian CPU. 71 | * This comes at a performance cost for big-endian CPU, since some swapping is required to emulate little-endian format. 72 | * Should endian-independence be of no importance for your application, you may set the #define below to 1, 73 | * to improve speed for Big-endian CPU. 74 | * This option has no impact on Little_Endian CPU. 75 | */ 76 | #ifndef XXH_FORCE_NATIVE_FORMAT /* can be defined externally */ 77 | # define XXH_FORCE_NATIVE_FORMAT 0 78 | #endif 79 | 80 | /*!XXH_FORCE_ALIGN_CHECK : 81 | * This is a minor performance trick, only useful with lots of very small keys. 82 | * It means : check for aligned/unaligned input. 83 | * The check costs one initial branch per hash; 84 | * set it to 0 when the input is guaranteed to be aligned, 85 | * or when alignment doesn't matter for performance. 86 | */ 87 | #ifndef XXH_FORCE_ALIGN_CHECK /* can be defined externally */ 88 | # if defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64) 89 | # define XXH_FORCE_ALIGN_CHECK 0 90 | # else 91 | # define XXH_FORCE_ALIGN_CHECK 1 92 | # endif 93 | #endif 94 | 95 | 96 | /* ************************************* 97 | * Includes & Memory related functions 98 | ***************************************/ 99 | /*! Modify the local functions below should you wish to use some other memory routines 100 | * for malloc(), free() */ 101 | #include 102 | static void* XXH_malloc(size_t s) { return malloc(s); } 103 | static void XXH_free (void* p) { free(p); } 104 | /*! and for memcpy() */ 105 | #include 106 | static void* XXH_memcpy(void* dest, const void* src, size_t size) { return memcpy(dest,src,size); } 107 | 108 | #define XXH_STATIC_LINKING_ONLY 109 | #include "xxhash.h" 110 | 111 | 112 | /* ************************************* 113 | * Compiler Specific Options 114 | ***************************************/ 115 | #ifdef _MSC_VER /* Visual Studio */ 116 | # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ 117 | # define FORCE_INLINE static __forceinline 118 | #else 119 | # if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ 120 | # ifdef __GNUC__ 121 | # define FORCE_INLINE static inline __attribute__((always_inline)) 122 | # else 123 | # define FORCE_INLINE static inline 124 | # endif 125 | # else 126 | # define FORCE_INLINE static 127 | # endif /* __STDC_VERSION__ */ 128 | #endif 129 | 130 | 131 | /* ************************************* 132 | * Basic Types 133 | ***************************************/ 134 | #ifndef MEM_MODULE 135 | # if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) 136 | # include 137 | typedef uint8_t BYTE; 138 | typedef uint16_t U16; 139 | typedef uint32_t U32; 140 | # else 141 | typedef unsigned char BYTE; 142 | typedef unsigned short U16; 143 | typedef unsigned int U32; 144 | # endif 145 | #endif 146 | 147 | #if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2)) 148 | 149 | /* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */ 150 | static U32 XXH_read32(const void* memPtr) { return *(const U32*) memPtr; } 151 | 152 | #elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1)) 153 | 154 | /* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */ 155 | /* currently only defined for gcc and icc */ 156 | typedef union { U32 u32; } __attribute__((packed)) unalign; 157 | static U32 XXH_read32(const void* ptr) { return ((const unalign*)ptr)->u32; } 158 | 159 | #else 160 | 161 | /* portable and safe solution. Generally efficient. 162 | * see : http://stackoverflow.com/a/32095106/646947 163 | */ 164 | static U32 XXH_read32(const void* memPtr) 165 | { 166 | U32 val; 167 | memcpy(&val, memPtr, sizeof(val)); 168 | return val; 169 | } 170 | 171 | #endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */ 172 | 173 | 174 | /* **************************************** 175 | * Compiler-specific Functions and Macros 176 | ******************************************/ 177 | #define XXH_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) 178 | 179 | /* Note : although _rotl exists for minGW (GCC under windows), performance seems poor */ 180 | #if defined(_MSC_VER) 181 | # define XXH_rotl32(x,r) _rotl(x,r) 182 | # define XXH_rotl64(x,r) _rotl64(x,r) 183 | #else 184 | # define XXH_rotl32(x,r) ((x << r) | (x >> (32 - r))) 185 | # define XXH_rotl64(x,r) ((x << r) | (x >> (64 - r))) 186 | #endif 187 | 188 | #if defined(_MSC_VER) /* Visual Studio */ 189 | # define XXH_swap32 _byteswap_ulong 190 | #elif XXH_GCC_VERSION >= 403 191 | # define XXH_swap32 __builtin_bswap32 192 | #else 193 | static U32 XXH_swap32 (U32 x) 194 | { 195 | return ((x << 24) & 0xff000000 ) | 196 | ((x << 8) & 0x00ff0000 ) | 197 | ((x >> 8) & 0x0000ff00 ) | 198 | ((x >> 24) & 0x000000ff ); 199 | } 200 | #endif 201 | 202 | 203 | /* ************************************* 204 | * Architecture Macros 205 | ***************************************/ 206 | typedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianess; 207 | 208 | /* XXH_CPU_LITTLE_ENDIAN can be defined externally, for example on the compiler command line */ 209 | #ifndef XXH_CPU_LITTLE_ENDIAN 210 | static const int g_one = 1; 211 | # define XXH_CPU_LITTLE_ENDIAN (*(const char*)(&g_one)) 212 | #endif 213 | 214 | 215 | /* *************************** 216 | * Memory reads 217 | *****************************/ 218 | typedef enum { XXH_aligned, XXH_unaligned } XXH_alignment; 219 | 220 | FORCE_INLINE U32 XXH_readLE32_align(const void* ptr, XXH_endianess endian, XXH_alignment align) 221 | { 222 | if (align==XXH_unaligned) 223 | return endian==XXH_littleEndian ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr)); 224 | else 225 | return endian==XXH_littleEndian ? *(const U32*)ptr : XXH_swap32(*(const U32*)ptr); 226 | } 227 | 228 | FORCE_INLINE U32 XXH_readLE32(const void* ptr, XXH_endianess endian) 229 | { 230 | return XXH_readLE32_align(ptr, endian, XXH_unaligned); 231 | } 232 | 233 | static U32 XXH_readBE32(const void* ptr) 234 | { 235 | return XXH_CPU_LITTLE_ENDIAN ? XXH_swap32(XXH_read32(ptr)) : XXH_read32(ptr); 236 | } 237 | 238 | 239 | /* ************************************* 240 | * Macros 241 | ***************************************/ 242 | #define XXH_STATIC_ASSERT(c) { enum { XXH_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */ 243 | XXH_PUBLIC_API unsigned XXH_versionNumber (void) { return XXH_VERSION_NUMBER; } 244 | 245 | 246 | /* ******************************************************************* 247 | * 32-bits hash functions 248 | *********************************************************************/ 249 | static const U32 PRIME32_1 = 2654435761U; 250 | static const U32 PRIME32_2 = 2246822519U; 251 | static const U32 PRIME32_3 = 3266489917U; 252 | static const U32 PRIME32_4 = 668265263U; 253 | static const U32 PRIME32_5 = 374761393U; 254 | 255 | static U32 XXH32_round(U32 seed, U32 input) 256 | { 257 | seed += input * PRIME32_2; 258 | seed = XXH_rotl32(seed, 13); 259 | seed *= PRIME32_1; 260 | return seed; 261 | } 262 | 263 | FORCE_INLINE U32 XXH32_endian_align(const void* input, size_t len, U32 seed, XXH_endianess endian, XXH_alignment align) 264 | { 265 | const BYTE* p = (const BYTE*)input; 266 | const BYTE* bEnd = p + len; 267 | U32 h32; 268 | #define XXH_get32bits(p) XXH_readLE32_align(p, endian, align) 269 | 270 | #ifdef XXH_ACCEPT_NULL_INPUT_POINTER 271 | if (p==NULL) { 272 | len=0; 273 | bEnd=p=(const BYTE*)(size_t)16; 274 | } 275 | #endif 276 | 277 | if (len>=16) { 278 | const BYTE* const limit = bEnd - 16; 279 | U32 v1 = seed + PRIME32_1 + PRIME32_2; 280 | U32 v2 = seed + PRIME32_2; 281 | U32 v3 = seed + 0; 282 | U32 v4 = seed - PRIME32_1; 283 | 284 | do { 285 | v1 = XXH32_round(v1, XXH_get32bits(p)); p+=4; 286 | v2 = XXH32_round(v2, XXH_get32bits(p)); p+=4; 287 | v3 = XXH32_round(v3, XXH_get32bits(p)); p+=4; 288 | v4 = XXH32_round(v4, XXH_get32bits(p)); p+=4; 289 | } while (p<=limit); 290 | 291 | h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18); 292 | } else { 293 | h32 = seed + PRIME32_5; 294 | } 295 | 296 | h32 += (U32) len; 297 | 298 | while (p+4<=bEnd) { 299 | h32 += XXH_get32bits(p) * PRIME32_3; 300 | h32 = XXH_rotl32(h32, 17) * PRIME32_4 ; 301 | p+=4; 302 | } 303 | 304 | while (p> 15; 311 | h32 *= PRIME32_2; 312 | h32 ^= h32 >> 13; 313 | h32 *= PRIME32_3; 314 | h32 ^= h32 >> 16; 315 | 316 | return h32; 317 | } 318 | 319 | 320 | XXH_PUBLIC_API unsigned int XXH32 (const void* input, size_t len, unsigned int seed) 321 | { 322 | #if 0 323 | /* Simple version, good for code maintenance, but unfortunately slow for small inputs */ 324 | XXH32_state_t state; 325 | XXH32_reset(&state, seed); 326 | XXH32_update(&state, input, len); 327 | return XXH32_digest(&state); 328 | #else 329 | XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; 330 | 331 | if (XXH_FORCE_ALIGN_CHECK) { 332 | if ((((size_t)input) & 3) == 0) { /* Input is 4-bytes aligned, leverage the speed benefit */ 333 | if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) 334 | return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned); 335 | else 336 | return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned); 337 | } } 338 | 339 | if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) 340 | return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned); 341 | else 342 | return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned); 343 | #endif 344 | } 345 | 346 | 347 | 348 | /*====== Hash streaming ======*/ 349 | 350 | XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void) 351 | { 352 | return (XXH32_state_t*)XXH_malloc(sizeof(XXH32_state_t)); 353 | } 354 | XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr) 355 | { 356 | XXH_free(statePtr); 357 | return XXH_OK; 358 | } 359 | 360 | XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dstState, const XXH32_state_t* srcState) 361 | { 362 | memcpy(dstState, srcState, sizeof(*dstState)); 363 | } 364 | 365 | XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, unsigned int seed) 366 | { 367 | XXH32_state_t state; /* using a local state to memcpy() in order to avoid strict-aliasing warnings */ 368 | memset(&state, 0, sizeof(state)-4); /* do not write into reserved, for future removal */ 369 | state.v1 = seed + PRIME32_1 + PRIME32_2; 370 | state.v2 = seed + PRIME32_2; 371 | state.v3 = seed + 0; 372 | state.v4 = seed - PRIME32_1; 373 | memcpy(statePtr, &state, sizeof(state)); 374 | return XXH_OK; 375 | } 376 | 377 | 378 | FORCE_INLINE XXH_errorcode XXH32_update_endian (XXH32_state_t* state, const void* input, size_t len, XXH_endianess endian) 379 | { 380 | const BYTE* p = (const BYTE*)input; 381 | const BYTE* const bEnd = p + len; 382 | 383 | #ifdef XXH_ACCEPT_NULL_INPUT_POINTER 384 | if (input==NULL) return XXH_ERROR; 385 | #endif 386 | 387 | state->total_len_32 += (unsigned)len; 388 | state->large_len |= (len>=16) | (state->total_len_32>=16); 389 | 390 | if (state->memsize + len < 16) { /* fill in tmp buffer */ 391 | XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, len); 392 | state->memsize += (unsigned)len; 393 | return XXH_OK; 394 | } 395 | 396 | if (state->memsize) { /* some data left from previous update */ 397 | XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, 16-state->memsize); 398 | { const U32* p32 = state->mem32; 399 | state->v1 = XXH32_round(state->v1, XXH_readLE32(p32, endian)); p32++; 400 | state->v2 = XXH32_round(state->v2, XXH_readLE32(p32, endian)); p32++; 401 | state->v3 = XXH32_round(state->v3, XXH_readLE32(p32, endian)); p32++; 402 | state->v4 = XXH32_round(state->v4, XXH_readLE32(p32, endian)); 403 | } 404 | p += 16-state->memsize; 405 | state->memsize = 0; 406 | } 407 | 408 | if (p <= bEnd-16) { 409 | const BYTE* const limit = bEnd - 16; 410 | U32 v1 = state->v1; 411 | U32 v2 = state->v2; 412 | U32 v3 = state->v3; 413 | U32 v4 = state->v4; 414 | 415 | do { 416 | v1 = XXH32_round(v1, XXH_readLE32(p, endian)); p+=4; 417 | v2 = XXH32_round(v2, XXH_readLE32(p, endian)); p+=4; 418 | v3 = XXH32_round(v3, XXH_readLE32(p, endian)); p+=4; 419 | v4 = XXH32_round(v4, XXH_readLE32(p, endian)); p+=4; 420 | } while (p<=limit); 421 | 422 | state->v1 = v1; 423 | state->v2 = v2; 424 | state->v3 = v3; 425 | state->v4 = v4; 426 | } 427 | 428 | if (p < bEnd) { 429 | XXH_memcpy(state->mem32, p, (size_t)(bEnd-p)); 430 | state->memsize = (unsigned)(bEnd-p); 431 | } 432 | 433 | return XXH_OK; 434 | } 435 | 436 | XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* state_in, const void* input, size_t len) 437 | { 438 | XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; 439 | 440 | if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) 441 | return XXH32_update_endian(state_in, input, len, XXH_littleEndian); 442 | else 443 | return XXH32_update_endian(state_in, input, len, XXH_bigEndian); 444 | } 445 | 446 | 447 | 448 | FORCE_INLINE U32 XXH32_digest_endian (const XXH32_state_t* state, XXH_endianess endian) 449 | { 450 | const BYTE * p = (const BYTE*)state->mem32; 451 | const BYTE* const bEnd = (const BYTE*)(state->mem32) + state->memsize; 452 | U32 h32; 453 | 454 | if (state->large_len) { 455 | h32 = XXH_rotl32(state->v1, 1) + XXH_rotl32(state->v2, 7) + XXH_rotl32(state->v3, 12) + XXH_rotl32(state->v4, 18); 456 | } else { 457 | h32 = state->v3 /* == seed */ + PRIME32_5; 458 | } 459 | 460 | h32 += state->total_len_32; 461 | 462 | while (p+4<=bEnd) { 463 | h32 += XXH_readLE32(p, endian) * PRIME32_3; 464 | h32 = XXH_rotl32(h32, 17) * PRIME32_4; 465 | p+=4; 466 | } 467 | 468 | while (p> 15; 475 | h32 *= PRIME32_2; 476 | h32 ^= h32 >> 13; 477 | h32 *= PRIME32_3; 478 | h32 ^= h32 >> 16; 479 | 480 | return h32; 481 | } 482 | 483 | 484 | XXH_PUBLIC_API unsigned int XXH32_digest (const XXH32_state_t* state_in) 485 | { 486 | XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; 487 | 488 | if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) 489 | return XXH32_digest_endian(state_in, XXH_littleEndian); 490 | else 491 | return XXH32_digest_endian(state_in, XXH_bigEndian); 492 | } 493 | 494 | 495 | /*====== Canonical representation ======*/ 496 | 497 | /*! Default XXH result types are basic unsigned 32 and 64 bits. 498 | * The canonical representation follows human-readable write convention, aka big-endian (large digits first). 499 | * These functions allow transformation of hash result into and from its canonical format. 500 | * This way, hash values can be written into a file or buffer, and remain comparable across different systems and programs. 501 | */ 502 | 503 | XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash) 504 | { 505 | XXH_STATIC_ASSERT(sizeof(XXH32_canonical_t) == sizeof(XXH32_hash_t)); 506 | if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap32(hash); 507 | memcpy(dst, &hash, sizeof(*dst)); 508 | } 509 | 510 | XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src) 511 | { 512 | return XXH_readBE32(src); 513 | } 514 | 515 | 516 | #ifndef XXH_NO_LONG_LONG 517 | 518 | /* ******************************************************************* 519 | * 64-bits hash functions 520 | *********************************************************************/ 521 | 522 | /*====== Memory access ======*/ 523 | 524 | #ifndef MEM_MODULE 525 | # define MEM_MODULE 526 | # if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) 527 | # include 528 | typedef uint64_t U64; 529 | # else 530 | typedef unsigned long long U64; /* if your compiler doesn't support unsigned long long, replace by another 64-bit type here. Note that xxhash.h will also need to be updated. */ 531 | # endif 532 | #endif 533 | 534 | 535 | #if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2)) 536 | 537 | /* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */ 538 | static U64 XXH_read64(const void* memPtr) { return *(const U64*) memPtr; } 539 | 540 | #elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1)) 541 | 542 | /* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */ 543 | /* currently only defined for gcc and icc */ 544 | typedef union { U32 u32; U64 u64; } __attribute__((packed)) unalign64; 545 | static U64 XXH_read64(const void* ptr) { return ((const unalign64*)ptr)->u64; } 546 | 547 | #else 548 | 549 | /* portable and safe solution. Generally efficient. 550 | * see : http://stackoverflow.com/a/32095106/646947 551 | */ 552 | 553 | static U64 XXH_read64(const void* memPtr) 554 | { 555 | U64 val; 556 | memcpy(&val, memPtr, sizeof(val)); 557 | return val; 558 | } 559 | 560 | #endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */ 561 | 562 | #if defined(_MSC_VER) /* Visual Studio */ 563 | # define XXH_swap64 _byteswap_uint64 564 | #elif XXH_GCC_VERSION >= 403 565 | # define XXH_swap64 __builtin_bswap64 566 | #else 567 | static U64 XXH_swap64 (U64 x) 568 | { 569 | return ((x << 56) & 0xff00000000000000ULL) | 570 | ((x << 40) & 0x00ff000000000000ULL) | 571 | ((x << 24) & 0x0000ff0000000000ULL) | 572 | ((x << 8) & 0x000000ff00000000ULL) | 573 | ((x >> 8) & 0x00000000ff000000ULL) | 574 | ((x >> 24) & 0x0000000000ff0000ULL) | 575 | ((x >> 40) & 0x000000000000ff00ULL) | 576 | ((x >> 56) & 0x00000000000000ffULL); 577 | } 578 | #endif 579 | 580 | FORCE_INLINE U64 XXH_readLE64_align(const void* ptr, XXH_endianess endian, XXH_alignment align) 581 | { 582 | if (align==XXH_unaligned) 583 | return endian==XXH_littleEndian ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr)); 584 | else 585 | return endian==XXH_littleEndian ? *(const U64*)ptr : XXH_swap64(*(const U64*)ptr); 586 | } 587 | 588 | FORCE_INLINE U64 XXH_readLE64(const void* ptr, XXH_endianess endian) 589 | { 590 | return XXH_readLE64_align(ptr, endian, XXH_unaligned); 591 | } 592 | 593 | static U64 XXH_readBE64(const void* ptr) 594 | { 595 | return XXH_CPU_LITTLE_ENDIAN ? XXH_swap64(XXH_read64(ptr)) : XXH_read64(ptr); 596 | } 597 | 598 | 599 | /*====== xxh64 ======*/ 600 | 601 | static const U64 PRIME64_1 = 11400714785074694791ULL; 602 | static const U64 PRIME64_2 = 14029467366897019727ULL; 603 | static const U64 PRIME64_3 = 1609587929392839161ULL; 604 | static const U64 PRIME64_4 = 9650029242287828579ULL; 605 | static const U64 PRIME64_5 = 2870177450012600261ULL; 606 | 607 | static U64 XXH64_round(U64 acc, U64 input) 608 | { 609 | acc += input * PRIME64_2; 610 | acc = XXH_rotl64(acc, 31); 611 | acc *= PRIME64_1; 612 | return acc; 613 | } 614 | 615 | static U64 XXH64_mergeRound(U64 acc, U64 val) 616 | { 617 | val = XXH64_round(0, val); 618 | acc ^= val; 619 | acc = acc * PRIME64_1 + PRIME64_4; 620 | return acc; 621 | } 622 | 623 | FORCE_INLINE U64 XXH64_endian_align(const void* input, size_t len, U64 seed, XXH_endianess endian, XXH_alignment align) 624 | { 625 | const BYTE* p = (const BYTE*)input; 626 | const BYTE* bEnd = p + len; 627 | U64 h64; 628 | #define XXH_get64bits(p) XXH_readLE64_align(p, endian, align) 629 | 630 | #ifdef XXH_ACCEPT_NULL_INPUT_POINTER 631 | if (p==NULL) { 632 | len=0; 633 | bEnd=p=(const BYTE*)(size_t)32; 634 | } 635 | #endif 636 | 637 | if (len>=32) { 638 | const BYTE* const limit = bEnd - 32; 639 | U64 v1 = seed + PRIME64_1 + PRIME64_2; 640 | U64 v2 = seed + PRIME64_2; 641 | U64 v3 = seed + 0; 642 | U64 v4 = seed - PRIME64_1; 643 | 644 | do { 645 | v1 = XXH64_round(v1, XXH_get64bits(p)); p+=8; 646 | v2 = XXH64_round(v2, XXH_get64bits(p)); p+=8; 647 | v3 = XXH64_round(v3, XXH_get64bits(p)); p+=8; 648 | v4 = XXH64_round(v4, XXH_get64bits(p)); p+=8; 649 | } while (p<=limit); 650 | 651 | h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18); 652 | h64 = XXH64_mergeRound(h64, v1); 653 | h64 = XXH64_mergeRound(h64, v2); 654 | h64 = XXH64_mergeRound(h64, v3); 655 | h64 = XXH64_mergeRound(h64, v4); 656 | 657 | } else { 658 | h64 = seed + PRIME64_5; 659 | } 660 | 661 | h64 += (U64) len; 662 | 663 | while (p+8<=bEnd) { 664 | U64 const k1 = XXH64_round(0, XXH_get64bits(p)); 665 | h64 ^= k1; 666 | h64 = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4; 667 | p+=8; 668 | } 669 | 670 | if (p+4<=bEnd) { 671 | h64 ^= (U64)(XXH_get32bits(p)) * PRIME64_1; 672 | h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3; 673 | p+=4; 674 | } 675 | 676 | while (p> 33; 683 | h64 *= PRIME64_2; 684 | h64 ^= h64 >> 29; 685 | h64 *= PRIME64_3; 686 | h64 ^= h64 >> 32; 687 | 688 | return h64; 689 | } 690 | 691 | 692 | XXH_PUBLIC_API unsigned long long XXH64 (const void* input, size_t len, unsigned long long seed) 693 | { 694 | #if 0 695 | /* Simple version, good for code maintenance, but unfortunately slow for small inputs */ 696 | XXH64_state_t state; 697 | XXH64_reset(&state, seed); 698 | XXH64_update(&state, input, len); 699 | return XXH64_digest(&state); 700 | #else 701 | XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; 702 | 703 | if (XXH_FORCE_ALIGN_CHECK) { 704 | if ((((size_t)input) & 7)==0) { /* Input is aligned, let's leverage the speed advantage */ 705 | if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) 706 | return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned); 707 | else 708 | return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned); 709 | } } 710 | 711 | if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) 712 | return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned); 713 | else 714 | return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned); 715 | #endif 716 | } 717 | 718 | /*====== Hash Streaming ======*/ 719 | 720 | XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void) 721 | { 722 | return (XXH64_state_t*)XXH_malloc(sizeof(XXH64_state_t)); 723 | } 724 | XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr) 725 | { 726 | XXH_free(statePtr); 727 | return XXH_OK; 728 | } 729 | 730 | XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dstState, const XXH64_state_t* srcState) 731 | { 732 | memcpy(dstState, srcState, sizeof(*dstState)); 733 | } 734 | 735 | XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH64_state_t* statePtr, unsigned long long seed) 736 | { 737 | XXH64_state_t state; /* using a local state to memcpy() in order to avoid strict-aliasing warnings */ 738 | memset(&state, 0, sizeof(state)-8); /* do not write into reserved, for future removal */ 739 | state.v1 = seed + PRIME64_1 + PRIME64_2; 740 | state.v2 = seed + PRIME64_2; 741 | state.v3 = seed + 0; 742 | state.v4 = seed - PRIME64_1; 743 | memcpy(statePtr, &state, sizeof(state)); 744 | return XXH_OK; 745 | } 746 | 747 | FORCE_INLINE XXH_errorcode XXH64_update_endian (XXH64_state_t* state, const void* input, size_t len, XXH_endianess endian) 748 | { 749 | const BYTE* p = (const BYTE*)input; 750 | const BYTE* const bEnd = p + len; 751 | 752 | #ifdef XXH_ACCEPT_NULL_INPUT_POINTER 753 | if (input==NULL) return XXH_ERROR; 754 | #endif 755 | 756 | state->total_len += len; 757 | 758 | if (state->memsize + len < 32) { /* fill in tmp buffer */ 759 | XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, len); 760 | state->memsize += (U32)len; 761 | return XXH_OK; 762 | } 763 | 764 | if (state->memsize) { /* tmp buffer is full */ 765 | XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, 32-state->memsize); 766 | state->v1 = XXH64_round(state->v1, XXH_readLE64(state->mem64+0, endian)); 767 | state->v2 = XXH64_round(state->v2, XXH_readLE64(state->mem64+1, endian)); 768 | state->v3 = XXH64_round(state->v3, XXH_readLE64(state->mem64+2, endian)); 769 | state->v4 = XXH64_round(state->v4, XXH_readLE64(state->mem64+3, endian)); 770 | p += 32-state->memsize; 771 | state->memsize = 0; 772 | } 773 | 774 | if (p+32 <= bEnd) { 775 | const BYTE* const limit = bEnd - 32; 776 | U64 v1 = state->v1; 777 | U64 v2 = state->v2; 778 | U64 v3 = state->v3; 779 | U64 v4 = state->v4; 780 | 781 | do { 782 | v1 = XXH64_round(v1, XXH_readLE64(p, endian)); p+=8; 783 | v2 = XXH64_round(v2, XXH_readLE64(p, endian)); p+=8; 784 | v3 = XXH64_round(v3, XXH_readLE64(p, endian)); p+=8; 785 | v4 = XXH64_round(v4, XXH_readLE64(p, endian)); p+=8; 786 | } while (p<=limit); 787 | 788 | state->v1 = v1; 789 | state->v2 = v2; 790 | state->v3 = v3; 791 | state->v4 = v4; 792 | } 793 | 794 | if (p < bEnd) { 795 | XXH_memcpy(state->mem64, p, (size_t)(bEnd-p)); 796 | state->memsize = (unsigned)(bEnd-p); 797 | } 798 | 799 | return XXH_OK; 800 | } 801 | 802 | XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* state_in, const void* input, size_t len) 803 | { 804 | XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; 805 | 806 | if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) 807 | return XXH64_update_endian(state_in, input, len, XXH_littleEndian); 808 | else 809 | return XXH64_update_endian(state_in, input, len, XXH_bigEndian); 810 | } 811 | 812 | FORCE_INLINE U64 XXH64_digest_endian (const XXH64_state_t* state, XXH_endianess endian) 813 | { 814 | const BYTE * p = (const BYTE*)state->mem64; 815 | const BYTE* const bEnd = (const BYTE*)state->mem64 + state->memsize; 816 | U64 h64; 817 | 818 | if (state->total_len >= 32) { 819 | U64 const v1 = state->v1; 820 | U64 const v2 = state->v2; 821 | U64 const v3 = state->v3; 822 | U64 const v4 = state->v4; 823 | 824 | h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18); 825 | h64 = XXH64_mergeRound(h64, v1); 826 | h64 = XXH64_mergeRound(h64, v2); 827 | h64 = XXH64_mergeRound(h64, v3); 828 | h64 = XXH64_mergeRound(h64, v4); 829 | } else { 830 | h64 = state->v3 + PRIME64_5; 831 | } 832 | 833 | h64 += (U64) state->total_len; 834 | 835 | while (p+8<=bEnd) { 836 | U64 const k1 = XXH64_round(0, XXH_readLE64(p, endian)); 837 | h64 ^= k1; 838 | h64 = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4; 839 | p+=8; 840 | } 841 | 842 | if (p+4<=bEnd) { 843 | h64 ^= (U64)(XXH_readLE32(p, endian)) * PRIME64_1; 844 | h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3; 845 | p+=4; 846 | } 847 | 848 | while (p> 33; 855 | h64 *= PRIME64_2; 856 | h64 ^= h64 >> 29; 857 | h64 *= PRIME64_3; 858 | h64 ^= h64 >> 32; 859 | 860 | return h64; 861 | } 862 | 863 | XXH_PUBLIC_API unsigned long long XXH64_digest (const XXH64_state_t* state_in) 864 | { 865 | XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; 866 | 867 | if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) 868 | return XXH64_digest_endian(state_in, XXH_littleEndian); 869 | else 870 | return XXH64_digest_endian(state_in, XXH_bigEndian); 871 | } 872 | 873 | 874 | /*====== Canonical representation ======*/ 875 | 876 | XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash) 877 | { 878 | XXH_STATIC_ASSERT(sizeof(XXH64_canonical_t) == sizeof(XXH64_hash_t)); 879 | if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap64(hash); 880 | memcpy(dst, &hash, sizeof(*dst)); 881 | } 882 | 883 | XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src) 884 | { 885 | return XXH_readBE64(src); 886 | } 887 | 888 | #endif /* XXH_NO_LONG_LONG */ 889 | -------------------------------------------------------------------------------- /c_src/xxhash.h: -------------------------------------------------------------------------------- 1 | /* 2 | xxHash - Extremely Fast Hash algorithm 3 | Header File 4 | Copyright (C) 2012-2016, Yann Collet. 5 | 6 | BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are 10 | met: 11 | 12 | * Redistributions of source code must retain the above copyright 13 | notice, this list of conditions and the following disclaimer. 14 | * Redistributions in binary form must reproduce the above 15 | copyright notice, this list of conditions and the following disclaimer 16 | in the documentation and/or other materials provided with the 17 | distribution. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | You can contact the author at : 32 | - xxHash source repository : https://github.com/Cyan4973/xxHash 33 | */ 34 | 35 | /* Notice extracted from xxHash homepage : 36 | 37 | xxHash is an extremely fast Hash algorithm, running at RAM speed limits. 38 | It also successfully passes all tests from the SMHasher suite. 39 | 40 | Comparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2 Duo @3GHz) 41 | 42 | Name Speed Q.Score Author 43 | xxHash 5.4 GB/s 10 44 | CrapWow 3.2 GB/s 2 Andrew 45 | MumurHash 3a 2.7 GB/s 10 Austin Appleby 46 | SpookyHash 2.0 GB/s 10 Bob Jenkins 47 | SBox 1.4 GB/s 9 Bret Mulvey 48 | Lookup3 1.2 GB/s 9 Bob Jenkins 49 | SuperFastHash 1.2 GB/s 1 Paul Hsieh 50 | CityHash64 1.05 GB/s 10 Pike & Alakuijala 51 | FNV 0.55 GB/s 5 Fowler, Noll, Vo 52 | CRC32 0.43 GB/s 9 53 | MD5-32 0.33 GB/s 10 Ronald L. Rivest 54 | SHA1-32 0.28 GB/s 10 55 | 56 | Q.Score is a measure of quality of the hash function. 57 | It depends on successfully passing SMHasher test set. 58 | 10 is a perfect score. 59 | 60 | A 64-bits version, named XXH64, is available since r35. 61 | It offers much better speed, but for 64-bits applications only. 62 | Name Speed on 64 bits Speed on 32 bits 63 | XXH64 13.8 GB/s 1.9 GB/s 64 | XXH32 6.8 GB/s 6.0 GB/s 65 | */ 66 | 67 | #ifndef XXHASH_H_5627135585666179 68 | #define XXHASH_H_5627135585666179 1 69 | 70 | #if defined (__cplusplus) 71 | extern "C" { 72 | #endif 73 | 74 | 75 | /* **************************** 76 | * Definitions 77 | ******************************/ 78 | #include /* size_t */ 79 | typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode; 80 | 81 | 82 | /* **************************** 83 | * API modifier 84 | ******************************/ 85 | /** XXH_PRIVATE_API 86 | * This is useful to include xxhash functions in `static` mode 87 | * in order to inline them, and remove their symbol from the public list. 88 | * Methodology : 89 | * #define XXH_PRIVATE_API 90 | * #include "xxhash.h" 91 | * `xxhash.c` is automatically included. 92 | * It's not useful to compile and link it as a separate module. 93 | */ 94 | #ifdef XXH_PRIVATE_API 95 | # ifndef XXH_STATIC_LINKING_ONLY 96 | # define XXH_STATIC_LINKING_ONLY 97 | # endif 98 | # if defined(__GNUC__) 99 | # define XXH_PUBLIC_API static __inline __attribute__((unused)) 100 | # elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) 101 | # define XXH_PUBLIC_API static inline 102 | # elif defined(_MSC_VER) 103 | # define XXH_PUBLIC_API static __inline 104 | # else 105 | # define XXH_PUBLIC_API static /* this version may generate warnings for unused static functions; disable the relevant warning */ 106 | # endif 107 | #else 108 | # define XXH_PUBLIC_API /* do nothing */ 109 | #endif /* XXH_PRIVATE_API */ 110 | 111 | /*!XXH_NAMESPACE, aka Namespace Emulation : 112 | 113 | If you want to include _and expose_ xxHash functions from within your own library, 114 | but also want to avoid symbol collisions with other libraries which may also include xxHash, 115 | 116 | you can use XXH_NAMESPACE, to automatically prefix any public symbol from xxhash library 117 | with the value of XXH_NAMESPACE (therefore, avoid NULL and numeric values). 118 | 119 | Note that no change is required within the calling program as long as it includes `xxhash.h` : 120 | regular symbol name will be automatically translated by this header. 121 | */ 122 | #ifdef XXH_NAMESPACE 123 | # define XXH_CAT(A,B) A##B 124 | # define XXH_NAME2(A,B) XXH_CAT(A,B) 125 | # define XXH_versionNumber XXH_NAME2(XXH_NAMESPACE, XXH_versionNumber) 126 | # define XXH32 XXH_NAME2(XXH_NAMESPACE, XXH32) 127 | # define XXH32_createState XXH_NAME2(XXH_NAMESPACE, XXH32_createState) 128 | # define XXH32_freeState XXH_NAME2(XXH_NAMESPACE, XXH32_freeState) 129 | # define XXH32_reset XXH_NAME2(XXH_NAMESPACE, XXH32_reset) 130 | # define XXH32_update XXH_NAME2(XXH_NAMESPACE, XXH32_update) 131 | # define XXH32_digest XXH_NAME2(XXH_NAMESPACE, XXH32_digest) 132 | # define XXH32_copyState XXH_NAME2(XXH_NAMESPACE, XXH32_copyState) 133 | # define XXH32_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH32_canonicalFromHash) 134 | # define XXH32_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH32_hashFromCanonical) 135 | # define XXH64 XXH_NAME2(XXH_NAMESPACE, XXH64) 136 | # define XXH64_createState XXH_NAME2(XXH_NAMESPACE, XXH64_createState) 137 | # define XXH64_freeState XXH_NAME2(XXH_NAMESPACE, XXH64_freeState) 138 | # define XXH64_reset XXH_NAME2(XXH_NAMESPACE, XXH64_reset) 139 | # define XXH64_update XXH_NAME2(XXH_NAMESPACE, XXH64_update) 140 | # define XXH64_digest XXH_NAME2(XXH_NAMESPACE, XXH64_digest) 141 | # define XXH64_copyState XXH_NAME2(XXH_NAMESPACE, XXH64_copyState) 142 | # define XXH64_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH64_canonicalFromHash) 143 | # define XXH64_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH64_hashFromCanonical) 144 | #endif 145 | 146 | 147 | /* ************************************* 148 | * Version 149 | ***************************************/ 150 | #define XXH_VERSION_MAJOR 0 151 | #define XXH_VERSION_MINOR 6 152 | #define XXH_VERSION_RELEASE 2 153 | #define XXH_VERSION_NUMBER (XXH_VERSION_MAJOR *100*100 + XXH_VERSION_MINOR *100 + XXH_VERSION_RELEASE) 154 | XXH_PUBLIC_API unsigned XXH_versionNumber (void); 155 | 156 | 157 | /*-********************************************************************** 158 | * 32-bits hash 159 | ************************************************************************/ 160 | typedef unsigned int XXH32_hash_t; 161 | 162 | /*! XXH32() : 163 | Calculate the 32-bits hash of sequence "length" bytes stored at memory address "input". 164 | The memory between input & input+length must be valid (allocated and read-accessible). 165 | "seed" can be used to alter the result predictably. 166 | Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark) : 5.4 GB/s */ 167 | XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t length, unsigned int seed); 168 | 169 | /*====== Streaming ======*/ 170 | typedef struct XXH32_state_s XXH32_state_t; /* incomplete type */ 171 | XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void); 172 | XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr); 173 | XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dst_state, const XXH32_state_t* src_state); 174 | 175 | XXH_PUBLIC_API XXH_errorcode XXH32_reset (XXH32_state_t* statePtr, unsigned int seed); 176 | XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length); 177 | XXH_PUBLIC_API XXH32_hash_t XXH32_digest (const XXH32_state_t* statePtr); 178 | 179 | /* 180 | These functions generate the xxHash of an input provided in multiple segments. 181 | Note that, for small input, they are slower than single-call functions, due to state management. 182 | For small input, prefer `XXH32()` and `XXH64()` . 183 | 184 | XXH state must first be allocated, using XXH*_createState() . 185 | 186 | Start a new hash by initializing state with a seed, using XXH*_reset(). 187 | 188 | Then, feed the hash state by calling XXH*_update() as many times as necessary. 189 | Obviously, input must be allocated and read accessible. 190 | The function returns an error code, with 0 meaning OK, and any other value meaning there is an error. 191 | 192 | Finally, a hash value can be produced anytime, by using XXH*_digest(). 193 | This function returns the nn-bits hash as an int or long long. 194 | 195 | It's still possible to continue inserting input into the hash state after a digest, 196 | and generate some new hashes later on, by calling again XXH*_digest(). 197 | 198 | When done, free XXH state space if it was allocated dynamically. 199 | */ 200 | 201 | /*====== Canonical representation ======*/ 202 | 203 | typedef struct { unsigned char digest[4]; } XXH32_canonical_t; 204 | XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash); 205 | XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src); 206 | 207 | /* Default result type for XXH functions are primitive unsigned 32 and 64 bits. 208 | * The canonical representation uses human-readable write convention, aka big-endian (large digits first). 209 | * These functions allow transformation of hash result into and from its canonical format. 210 | * This way, hash values can be written into a file / memory, and remain comparable on different systems and programs. 211 | */ 212 | 213 | 214 | #ifndef XXH_NO_LONG_LONG 215 | /*-********************************************************************** 216 | * 64-bits hash 217 | ************************************************************************/ 218 | typedef unsigned long long XXH64_hash_t; 219 | 220 | /*! XXH64() : 221 | Calculate the 64-bits hash of sequence of length "len" stored at memory address "input". 222 | "seed" can be used to alter the result predictably. 223 | This function runs faster on 64-bits systems, but slower on 32-bits systems (see benchmark). 224 | */ 225 | XXH_PUBLIC_API XXH64_hash_t XXH64 (const void* input, size_t length, unsigned long long seed); 226 | 227 | /*====== Streaming ======*/ 228 | typedef struct XXH64_state_s XXH64_state_t; /* incomplete type */ 229 | XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void); 230 | XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr); 231 | XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dst_state, const XXH64_state_t* src_state); 232 | 233 | XXH_PUBLIC_API XXH_errorcode XXH64_reset (XXH64_state_t* statePtr, unsigned long long seed); 234 | XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* statePtr, const void* input, size_t length); 235 | XXH_PUBLIC_API XXH64_hash_t XXH64_digest (const XXH64_state_t* statePtr); 236 | 237 | /*====== Canonical representation ======*/ 238 | typedef struct { unsigned char digest[8]; } XXH64_canonical_t; 239 | XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash); 240 | XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src); 241 | #endif /* XXH_NO_LONG_LONG */ 242 | 243 | 244 | #ifdef XXH_STATIC_LINKING_ONLY 245 | 246 | /* ================================================================================================ 247 | This section contains definitions which are not guaranteed to remain stable. 248 | They may change in future versions, becoming incompatible with a different version of the library. 249 | They shall only be used with static linking. 250 | Never use these definitions in association with dynamic linking ! 251 | =================================================================================================== */ 252 | 253 | /* These definitions are only meant to make possible 254 | static allocation of XXH state, on stack or in a struct for example. 255 | Never use members directly. */ 256 | 257 | struct XXH32_state_s { 258 | unsigned total_len_32; 259 | unsigned large_len; 260 | unsigned v1; 261 | unsigned v2; 262 | unsigned v3; 263 | unsigned v4; 264 | unsigned mem32[4]; /* buffer defined as U32 for alignment */ 265 | unsigned memsize; 266 | unsigned reserved; /* never read nor write, will be removed in a future version */ 267 | }; /* typedef'd to XXH32_state_t */ 268 | 269 | #ifndef XXH_NO_LONG_LONG /* remove 64-bits support */ 270 | struct XXH64_state_s { 271 | unsigned long long total_len; 272 | unsigned long long v1; 273 | unsigned long long v2; 274 | unsigned long long v3; 275 | unsigned long long v4; 276 | unsigned long long mem64[4]; /* buffer defined as U64 for alignment */ 277 | unsigned memsize; 278 | unsigned reserved[2]; /* never read nor write, will be removed in a future version */ 279 | }; /* typedef'd to XXH64_state_t */ 280 | #endif 281 | 282 | #ifdef XXH_PRIVATE_API 283 | # include "xxhash.c" /* include xxhash function bodies as `static`, for inlining */ 284 | #endif 285 | 286 | #endif /* XXH_STATIC_LINKING_ONLY */ 287 | 288 | 289 | #if defined (__cplusplus) 290 | } 291 | #endif 292 | 293 | #endif /* XXHASH_H_5627135585666179 */ 294 | -------------------------------------------------------------------------------- /c_src/xxhash_nif.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "erl_nif.h" 4 | #define XXH_STATIC_LINKING_ONLY 5 | #include "xxhash.h" 6 | 7 | #define UNUSED(x) (void)(x) 8 | 9 | 10 | // Misc. definitions 11 | 12 | void xxhash_cleanup(ErlNifEnv *env, void *p); 13 | 14 | 15 | // Erlang terms and exports. 16 | 17 | static ERL_NIF_TERM nif_hash32(ErlNifEnv *env, int argc, 18 | const ERL_NIF_TERM argv[]); 19 | static ERL_NIF_TERM nif_hash32_init(ErlNifEnv *env, int argc, 20 | const ERL_NIF_TERM argv[]); 21 | static ERL_NIF_TERM nif_hash32_update(ErlNifEnv *env, int argc, 22 | const ERL_NIF_TERM argv[]); 23 | static ERL_NIF_TERM nif_hash32_digest(ErlNifEnv *env, int argc, 24 | const ERL_NIF_TERM argv[]); 25 | static ERL_NIF_TERM nif_hash64(ErlNifEnv *env, int argc, 26 | const ERL_NIF_TERM argv[]); 27 | static ERL_NIF_TERM nif_hash64_init(ErlNifEnv *env, int argc, 28 | const ERL_NIF_TERM argv[]); 29 | static ERL_NIF_TERM nif_hash64_update(ErlNifEnv *env, int argc, 30 | const ERL_NIF_TERM argv[]); 31 | static ERL_NIF_TERM nif_hash64_digest(ErlNifEnv *env, int argc, 32 | const ERL_NIF_TERM argv[]); 33 | 34 | static ERL_NIF_TERM atom_ok; 35 | 36 | static ErlNifFunc nif_funcs[] = { 37 | {"hash32_impl", 2, nif_hash32, 0}, 38 | {"hash32_init_impl", 1, nif_hash32_init, 0}, 39 | {"hash32_update_impl", 2, nif_hash32_update, 0}, 40 | {"hash32_digest_impl", 1, nif_hash32_digest, 0}, 41 | {"hash64_impl", 2, nif_hash64, 0}, 42 | {"hash64_init_impl", 1, nif_hash64_init, 0}, 43 | {"hash64_update_impl", 2, nif_hash64_update, 0}, 44 | {"hash64_digest_impl", 1, nif_hash64_digest, 0} 45 | }; 46 | 47 | static ErlNifResourceType *xxhash_handle; 48 | 49 | 50 | // Hash32. 51 | 52 | static ERL_NIF_TERM 53 | nif_hash32(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { 54 | ErlNifBinary src_bin; 55 | unsigned int hash; 56 | unsigned int seed; 57 | UNUSED(argc); 58 | 59 | if (!enif_inspect_binary(env, argv[0], &src_bin) || 60 | !enif_get_uint(env, argv[1], &seed)) { 61 | return enif_make_badarg(env); 62 | } 63 | 64 | hash = XXH32(src_bin.data, src_bin.size, seed); 65 | 66 | return enif_make_uint(env, hash); 67 | } 68 | 69 | 70 | static ERL_NIF_TERM 71 | nif_hash32_init(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { 72 | XXH32_state_t *state = enif_alloc_resource(xxhash_handle, sizeof(XXH32_state_t)); 73 | unsigned int seed; 74 | ERL_NIF_TERM term; 75 | UNUSED(argc); 76 | if (!enif_get_uint(env, argv[0], &seed)) { 77 | return enif_make_badarg(env); 78 | } 79 | XXH32_reset(state, seed); 80 | term = enif_make_resource(env, state); 81 | enif_release_resource(state); 82 | return term; 83 | } 84 | 85 | static ERL_NIF_TERM 86 | nif_hash32_update(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { 87 | XXH32_state_t *state; 88 | ErlNifBinary src_bin; 89 | UNUSED(argc); 90 | if (!enif_get_resource(env, argv[0], xxhash_handle, (void **) &state) || 91 | !enif_inspect_binary(env, argv[1], &src_bin)) { 92 | return enif_make_badarg(env); 93 | } 94 | XXH32_update(state, src_bin.data, src_bin.size); 95 | return atom_ok; 96 | } 97 | 98 | static ERL_NIF_TERM 99 | nif_hash32_digest(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { 100 | XXH32_state_t *state; 101 | unsigned int hash; 102 | UNUSED(argc); 103 | if (!enif_get_resource(env, argv[0], xxhash_handle, (void **) &state)) { 104 | return enif_make_badarg(env); 105 | } 106 | hash = XXH32_digest(state); 107 | return enif_make_uint(env, hash); 108 | } 109 | 110 | 111 | // Hash64. 112 | 113 | static ERL_NIF_TERM 114 | nif_hash64(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { 115 | ErlNifBinary src_bin; 116 | uint64_t hash; 117 | ErlNifUInt64 seed; 118 | UNUSED(argc); 119 | 120 | if (!enif_inspect_binary(env, argv[0], &src_bin) || 121 | !enif_get_uint64(env, argv[1], (ErlNifUInt64 *) &seed)) { 122 | return enif_make_badarg(env); 123 | } 124 | 125 | hash = XXH64(src_bin.data, src_bin.size, seed); 126 | 127 | return enif_make_uint64(env, hash); 128 | } 129 | 130 | 131 | static ERL_NIF_TERM 132 | nif_hash64_init(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { 133 | XXH64_state_t *state = enif_alloc_resource(xxhash_handle, sizeof(XXH64_state_t)); 134 | ErlNifUInt64 seed; 135 | ERL_NIF_TERM term; 136 | UNUSED(argc); 137 | if (!enif_get_uint64(env, argv[0], &seed)) { 138 | return enif_make_badarg(env); 139 | } 140 | XXH64_reset(state, seed); 141 | term = enif_make_resource(env, state); 142 | enif_release_resource(state); 143 | return term; 144 | } 145 | 146 | static ERL_NIF_TERM 147 | nif_hash64_update(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { 148 | XXH64_state_t *state; 149 | ErlNifBinary src_bin; 150 | UNUSED(argc); 151 | if (!enif_get_resource(env, argv[0], xxhash_handle, (void **) &state) || 152 | !enif_inspect_binary(env, argv[1], &src_bin)) { 153 | return enif_make_badarg(env); 154 | } 155 | XXH64_update(state, src_bin.data, src_bin.size); 156 | return atom_ok; 157 | } 158 | 159 | static ERL_NIF_TERM 160 | nif_hash64_digest(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { 161 | XXH64_state_t *state; 162 | uint64_t hash; 163 | UNUSED(argc); 164 | if (!enif_get_resource(env, argv[0], xxhash_handle, (void **) &state)) { 165 | return enif_make_badarg(env); 166 | } 167 | hash = XXH64_digest(state); 168 | return enif_make_uint64(env, hash); 169 | } 170 | 171 | 172 | // Loading and cleaning stuff. 173 | 174 | static int init(ErlNifEnv *env, void* *priv_data, ERL_NIF_TERM load_info) { 175 | UNUSED(priv_data); 176 | UNUSED(load_info); 177 | atom_ok = enif_make_atom(env, "ok"); 178 | if ((xxhash_handle = enif_open_resource_type(env, "xxhash", "xxhash_handle", &xxhash_cleanup, 179 | ERL_NIF_RT_CREATE | ERL_NIF_RT_TAKEOVER, NULL)) == NULL) { 180 | return -1; 181 | } 182 | return 0; 183 | } 184 | 185 | void xxhash_cleanup(ErlNifEnv *env, void *obj) { 186 | UNUSED(env); 187 | enif_release_resource(obj); 188 | } 189 | 190 | 191 | // Init stuff. 192 | 193 | ERL_NIF_INIT(xxhash, nif_funcs, &init, NULL, NULL, NULL); 194 | -------------------------------------------------------------------------------- /doc/edoc-info: -------------------------------------------------------------------------------- 1 | %% encoding: UTF-8 2 | {application,xxhash}. 3 | {packages,[]}. 4 | {modules,[xxhash]}. 5 | -------------------------------------------------------------------------------- /doc/erlang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierreis/erlang-xxhash/92fcfe57a74d3ea1fe794ccdfdf62ce4a036c01b/doc/erlang.png -------------------------------------------------------------------------------- /doc/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The xxhash application 5 | 6 | 7 | 8 | 9 | 10 | 11 | <h2>This page uses frames</h2> 12 | <p>Your browser does not accept frames. 13 | <br>You should go to the <a href="overview-summary.html">non-frame version</a> instead. 14 | </p> 15 | 16 | 17 | -------------------------------------------------------------------------------- /doc/modules-frame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The xxhash application 5 | 6 | 7 | 8 |

Modules

9 | 10 |
xxhash
11 | 12 | -------------------------------------------------------------------------------- /doc/overview-summary.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | The xxhash application 6 | 7 | 8 | 9 | 10 |

The xxhash application

11 | 12 |
13 | 14 |

Generated by EDoc, May 13 2015, 22:18:08.

15 | 16 | 17 | -------------------------------------------------------------------------------- /doc/packages-frame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The xxhash application 5 | 6 | 7 | 8 |

Packages

9 |
10 | 11 | -------------------------------------------------------------------------------- /doc/stylesheet.css: -------------------------------------------------------------------------------- 1 | /* Baseline rhythm */ 2 | body { 3 | font-size: 16px; 4 | font-family: Helvetica, sans-serif; 5 | margin: 8px; 6 | } 7 | 8 | p { 9 | font-size: 1em; /* 16px */ 10 | line-height: 1.5em; /* 24px */ 11 | margin: 0 0 1.5em 0; 12 | } 13 | 14 | h1 { 15 | font-size: 1.5em; /* 24px */ 16 | line-height: 1em; /* 24px */ 17 | margin-top: 1em; 18 | margin-bottom: 0em; 19 | } 20 | 21 | h2 { 22 | font-size: 1.375em; /* 22px */ 23 | line-height: 1.0909em; /* 24px */ 24 | margin-top: 1.0909em; 25 | margin-bottom: 0em; 26 | } 27 | 28 | h3 { 29 | font-size: 1.25em; /* 20px */ 30 | line-height: 1.2em; /* 24px */ 31 | margin-top: 1.2em; 32 | margin-bottom: 0em; 33 | } 34 | 35 | h4 { 36 | font-size: 1.125em; /* 18px */ 37 | line-height: 1.3333em; /* 24px */ 38 | margin-top: 1.3333em; 39 | margin-bottom: 0em; 40 | } 41 | 42 | .class-for-16px { 43 | font-size: 1em; /* 16px */ 44 | line-height: 1.5em; /* 24px */ 45 | margin-top: 1.5em; 46 | margin-bottom: 0em; 47 | } 48 | 49 | .class-for-14px { 50 | font-size: 0.875em; /* 14px */ 51 | line-height: 1.7143em; /* 24px */ 52 | margin-top: 1.7143em; 53 | margin-bottom: 0em; 54 | } 55 | 56 | ul { 57 | margin: 0 0 1.5em 0; 58 | } 59 | 60 | /* Customizations */ 61 | body { 62 | color: #333; 63 | } 64 | 65 | tt, code, pre { 66 | font-family: "Andale Mono", "Inconsolata", "Monaco", "DejaVu Sans Mono", monospaced; 67 | } 68 | 69 | tt, code { font-size: 0.875em } 70 | 71 | pre { 72 | font-size: 0.875em; /* 14px */ 73 | line-height: 1.7143em; /* 24px */ 74 | margin: 0 1em 1.7143em; 75 | padding: 0 1em; 76 | background: #eee; 77 | } 78 | 79 | .navbar img, hr { display: none } 80 | 81 | table { 82 | border-collapse: collapse; 83 | } 84 | 85 | h1 { 86 | border-left: 0.5em solid #fa0; 87 | padding-left: 0.5em; 88 | } 89 | 90 | h2.indextitle { 91 | font-size: 1.25em; /* 20px */ 92 | line-height: 1.2em; /* 24px */ 93 | margin: -8px -8px 0.6em; 94 | background-color: #fa0; 95 | color: white; 96 | padding: 0.3em; 97 | } 98 | 99 | ul.index { 100 | list-style: none; 101 | margin-left: 0em; 102 | padding-left: 0; 103 | } 104 | 105 | ul.index li { 106 | display: inline; 107 | padding-right: 0.75em 108 | } 109 | 110 | div.spec p { 111 | margin-bottom: 0; 112 | padding-left: 1.25em; 113 | background-color: #eee; 114 | } 115 | 116 | h3.function { 117 | border-left: 0.5em solid #fa0; 118 | padding-left: 0.5em; 119 | background: #fc9; 120 | } 121 | a, a:visited, a:hover, a:active { color: #C60 } 122 | h2 a, h3 a { color: #333 } 123 | 124 | i { 125 | font-size: 0.875em; /* 14px */ 126 | line-height: 1.7143em; /* 24px */ 127 | margin-top: 1.7143em; 128 | margin-bottom: 0em; 129 | font-style: normal; 130 | } -------------------------------------------------------------------------------- /doc/xxhash.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Module xxhash 6 | 7 | 8 | 9 | 10 |
11 | 12 |

Module xxhash

13 | 14 |

Copyright © 2013 Pierre Matri, All rights reserved. Open source, MIT License.

15 | 16 |

Version: 0.1.0

17 |

Authors: Pierre Matri (pierre@matri.me).

18 | 19 |

Data Types

20 | 21 |

hash_digest()

22 |

hash_digest() = non_neg_integer()

23 | 24 | 25 |

hash_handle()

26 |

hash_handle() = binary()

27 | 28 | 29 |

hash_input()

30 |

hash_input() = binary() | atom() | number() | list()

31 | 32 | 33 |

hash_seed()

34 |

hash_seed() = non_neg_integer()

35 | 36 | 37 |

Function Index

38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 |
hash32/1Hash Data with a default seed value, and return the digest.
hash32/2Hash Data with Seed value, and return the digest.
hash32_digest/1Calculates a digest of all the passed data to the Handle hasher.
hash32_init/0Initialize a hasher with a default seed value, and return an handle.
hash32_init/1Initialize a hasher with Seed value, and return an handle.
hash32_update/2Update the Handle hasher content with the given Data.
hash64/1Hash Data with a default seed value, and return the digest.
hash64/2Hash Data with Seed value, and return the digest.
hash64_digest/1Calculates a digest of all the passed data to the Handle hasher.
hash64_init/0Initialize a hasher with a default seed value, and return an handle.
hash64_init/1Initialize a hasher with Seed value, and return an handle.
hash64_update/2Update the Handle hasher content with the given Data.
51 | 52 |

Function Details

53 | 54 |

hash32/1

55 |
56 |

hash32(Data::hash_input()) -> hash_digest()

57 |

Hash Data with a default seed value, and return the digest.

58 |

See also: hash32/2.

59 | 60 |

hash32/2

61 |
62 |

hash32(Data::hash_input(), Seed::hash_seed()) -> hash_digest()

63 |

Hash Data with Seed value, and return the digest.

64 |

See also: hash32/1.

65 | 66 |

hash32_digest/1

67 |
68 |

hash32_digest(Handle::hash_handle()) -> hash_digest()

69 |

Calculates a digest of all the passed data to the Handle hasher.

70 | 71 |

hash32_init/0

72 |
73 |

hash32_init() -> hash_handle()

74 |

Initialize a hasher with a default seed value, and return an handle.

75 |

See also: hash32_init/1.

76 | 77 |

hash32_init/1

78 |
79 |

hash32_init(Seed::hash_seed()) -> hash_handle()

80 |

Initialize a hasher with Seed value, and return an handle.

81 |

See also: hash32_init/0.

82 | 83 |

hash32_update/2

84 |
85 |

hash32_update(Handle::hash_handle(), Data::hash_input()) -> ok

86 |

Update the Handle hasher content with the given Data. This can be 87 | called many times with new data as it is streamed.

88 | 89 |

hash64/1

90 |
91 |

hash64(Data::hash_input()) -> hash_digest()

92 |

Hash Data with a default seed value, and return the digest.

93 |

See also: hash64/2.

94 | 95 |

hash64/2

96 |
97 |

hash64(Data::hash_input(), Seed::hash_seed()) -> hash_digest()

98 |

Hash Data with Seed value, and return the digest.

99 |

See also: hash64/1.

100 | 101 |

hash64_digest/1

102 |
103 |

hash64_digest(Handle::hash_handle()) -> hash_digest()

104 |

Calculates a digest of all the passed data to the Handle hasher.

105 | 106 |

hash64_init/0

107 |
108 |

hash64_init() -> hash_handle()

109 |

Initialize a hasher with a default seed value, and return an handle.

110 |

See also: hash64_init/1.

111 | 112 |

hash64_init/1

113 |
114 |

hash64_init(Seed::hash_seed()) -> hash_handle()

115 |

Initialize a hasher with Seed value, and return an handle.

116 |

See also: hash64_init/0.

117 | 118 |

hash64_update/2

119 |
120 |

hash64_update(Handle::hash_handle(), Data::hash_input()) -> ok

121 |

Update the Handle hasher content with the given Data. This can be 122 | called many times with new data as it is streamed.

123 |
124 | 125 | 126 |

Generated by EDoc, May 13 2015, 22:18:08.

127 | 128 | 129 | -------------------------------------------------------------------------------- /priv/edocs.css: -------------------------------------------------------------------------------- 1 | /* Baseline rhythm */ 2 | body { 3 | font-size: 16px; 4 | font-family: Helvetica, sans-serif; 5 | margin: 8px; 6 | } 7 | 8 | p { 9 | font-size: 1em; /* 16px */ 10 | line-height: 1.5em; /* 24px */ 11 | margin: 0 0 1.5em 0; 12 | } 13 | 14 | h1 { 15 | font-size: 1.5em; /* 24px */ 16 | line-height: 1em; /* 24px */ 17 | margin-top: 1em; 18 | margin-bottom: 0em; 19 | } 20 | 21 | h2 { 22 | font-size: 1.375em; /* 22px */ 23 | line-height: 1.0909em; /* 24px */ 24 | margin-top: 1.0909em; 25 | margin-bottom: 0em; 26 | } 27 | 28 | h3 { 29 | font-size: 1.25em; /* 20px */ 30 | line-height: 1.2em; /* 24px */ 31 | margin-top: 1.2em; 32 | margin-bottom: 0em; 33 | } 34 | 35 | h4 { 36 | font-size: 1.125em; /* 18px */ 37 | line-height: 1.3333em; /* 24px */ 38 | margin-top: 1.3333em; 39 | margin-bottom: 0em; 40 | } 41 | 42 | .class-for-16px { 43 | font-size: 1em; /* 16px */ 44 | line-height: 1.5em; /* 24px */ 45 | margin-top: 1.5em; 46 | margin-bottom: 0em; 47 | } 48 | 49 | .class-for-14px { 50 | font-size: 0.875em; /* 14px */ 51 | line-height: 1.7143em; /* 24px */ 52 | margin-top: 1.7143em; 53 | margin-bottom: 0em; 54 | } 55 | 56 | ul { 57 | margin: 0 0 1.5em 0; 58 | } 59 | 60 | /* Customizations */ 61 | body { 62 | color: #333; 63 | } 64 | 65 | tt, code, pre { 66 | font-family: "Andale Mono", "Inconsolata", "Monaco", "DejaVu Sans Mono", monospaced; 67 | } 68 | 69 | tt, code { font-size: 0.875em } 70 | 71 | pre { 72 | font-size: 0.875em; /* 14px */ 73 | line-height: 1.7143em; /* 24px */ 74 | margin: 0 1em 1.7143em; 75 | padding: 0 1em; 76 | background: #eee; 77 | } 78 | 79 | .navbar img, hr { display: none } 80 | 81 | table { 82 | border-collapse: collapse; 83 | } 84 | 85 | h1 { 86 | border-left: 0.5em solid #fa0; 87 | padding-left: 0.5em; 88 | } 89 | 90 | h2.indextitle { 91 | font-size: 1.25em; /* 20px */ 92 | line-height: 1.2em; /* 24px */ 93 | margin: -8px -8px 0.6em; 94 | background-color: #fa0; 95 | color: white; 96 | padding: 0.3em; 97 | } 98 | 99 | ul.index { 100 | list-style: none; 101 | margin-left: 0em; 102 | padding-left: 0; 103 | } 104 | 105 | ul.index li { 106 | display: inline; 107 | padding-right: 0.75em 108 | } 109 | 110 | div.spec p { 111 | margin-bottom: 0; 112 | padding-left: 1.25em; 113 | background-color: #eee; 114 | } 115 | 116 | h3.function { 117 | border-left: 0.5em solid #fa0; 118 | padding-left: 0.5em; 119 | background: #fc9; 120 | } 121 | a, a:visited, a:hover, a:active { color: #C60 } 122 | h2 a, h3 a { color: #333 } 123 | 124 | i { 125 | font-size: 0.875em; /* 14px */ 126 | line-height: 1.7143em; /* 24px */ 127 | margin-top: 1.7143em; 128 | margin-bottom: 0em; 129 | font-style: normal; 130 | } -------------------------------------------------------------------------------- /rebar.config: -------------------------------------------------------------------------------- 1 | {erl_opts, [warnings_as_errors, {w, all}, warn_export_all]}. 2 | 3 | {clean_files, [".eunit", 4 | "ebin/*.beam"]}. 5 | 6 | {eunit_opts, [verbose]}. 7 | 8 | {xref_checks, [fail_on_warning, undefined_function_calls]}. 9 | 10 | {edoc_opts, [{stylesheet_file, "./priv/edocs.css"}]}. 11 | 12 | {cover_enabled, true}. 13 | 14 | {pre_hooks, [{"(linux|darwin|solaris)", compile, "make -C c_src"}, 15 | {"(freebsd|openbsd)", compile, "gmake -C c_src"} 16 | ]}. 17 | 18 | {post_hooks, [{"(linux|darwin|solaris)", clean, "make -C c_src clean"}, 19 | {"(freebsd|openbsd)", clean, "gmake -C c_src clean"} 20 | ]}. 21 | -------------------------------------------------------------------------------- /src/xxhash.app.src: -------------------------------------------------------------------------------- 1 | {application, xxhash, 2 | [ 3 | {description, "xxHash for Erlang."}, 4 | {vsn, "0.2.0"}, 5 | {registered, []}, 6 | {applications, [kernel, 7 | stdlib]}, 8 | {modules, [xxhash]}, 9 | {env, []} 10 | ] 11 | }. 12 | -------------------------------------------------------------------------------- /src/xxhash.erl: -------------------------------------------------------------------------------- 1 | %%% @author Pierre Matri 2 | %%% 3 | %%% @copyright 2013 Pierre Matri, All rights reserved. Open source, MIT License. 4 | %%% @version 0.1.0 5 | 6 | -module(xxhash). 7 | -version(0.1). 8 | 9 | -define(DEFAULT_SEED, 0). 10 | 11 | -export([hash32/1, hash32/2, 12 | hash32_init/0, hash32_init/1, 13 | hash32_update/2, hash32_digest/1, 14 | hash64/1, hash64/2, 15 | hash64_init/0, hash64_init/1, 16 | hash64_update/2, hash64_digest/1]). 17 | 18 | -on_load(init/0). 19 | 20 | -define(nif_stub, nif_stub_error(?LINE)). 21 | 22 | -type hash_input() :: binary() | atom() | number() | list(). 23 | -type hash_handle() :: binary(). 24 | -type hash_digest() :: non_neg_integer(). 25 | -type hash_seed() :: non_neg_integer(). 26 | 27 | 28 | nif_stub_error(Line) -> 29 | erlang:nif_error({nif_not_loaded, module, ?MODULE, line, Line}). 30 | 31 | 32 | %%%============================================================================= 33 | %%% Initializer 34 | %%%============================================================================= 35 | 36 | 37 | -spec init() -> ok | {error, any()}. 38 | 39 | init() -> 40 | PrivDir = case code:priv_dir(?MODULE) of 41 | {error, bad_name} -> 42 | EbinDir = filename:dirname(code:which(?MODULE)), 43 | AppPath = filename:dirname(EbinDir), 44 | filename:join(AppPath, "priv"); 45 | Path -> 46 | Path 47 | end, 48 | 49 | erlang:load_nif(filename:join(PrivDir, xxhash), 0). 50 | 51 | 52 | %%%============================================================================= 53 | %%% Nif functions 54 | %%%============================================================================= 55 | 56 | hash32_impl(_Data, _Seed) -> 57 | ?nif_stub. 58 | 59 | hash32_init_impl(_Seed) -> 60 | ?nif_stub. 61 | 62 | hash32_update_impl(_Handle, _Data) -> 63 | ?nif_stub. 64 | 65 | hash32_digest_impl(_Handle) -> 66 | ?nif_stub. 67 | 68 | hash64_impl(_Data, _Seed) -> 69 | ?nif_stub. 70 | 71 | hash64_init_impl(_Seed) -> 72 | ?nif_stub. 73 | 74 | hash64_update_impl(_Handle, _Data) -> 75 | ?nif_stub. 76 | 77 | hash64_digest_impl(_Handle) -> 78 | ?nif_stub. 79 | 80 | 81 | %%%============================================================================= 82 | %%% Exports 83 | %%%============================================================================= 84 | 85 | %% @doc Hash `Data' with a default seed value, and return the digest. 86 | %% @see hash32/2 87 | 88 | -spec hash32(Data::hash_input()) -> hash_digest(). 89 | 90 | hash32(Data) -> 91 | hash32(Data, ?DEFAULT_SEED). 92 | 93 | 94 | %% @doc Hash `Data' with `Seed' value, and return the digest. 95 | %% @see hash32/1 96 | 97 | -spec hash32(Data::hash_input(), Seed::hash_seed()) -> hash_digest(). 98 | 99 | hash32(Data, Seed) when is_integer(Seed) -> 100 | hash32_impl(supported_to_binary(Data), Seed). 101 | 102 | 103 | %% @doc Initialize a hasher with a default seed value, and return an handle. 104 | %% @see hash32_init/1 105 | 106 | -spec hash32_init() -> hash_handle(). 107 | 108 | hash32_init() -> 109 | hash32_init(?DEFAULT_SEED). 110 | 111 | 112 | %% @doc Initialize a hasher with `Seed' value, and return an handle. 113 | %% @see hash32_init/0 114 | 115 | -spec hash32_init(Seed::hash_seed()) -> hash_handle(). 116 | 117 | hash32_init(Seed) when is_integer(Seed) -> 118 | hash32_init_impl(Seed). 119 | 120 | 121 | %% @doc Update the `Handle' hasher content with the given `Data'. This can be 122 | %% called many times with new data as it is streamed. 123 | 124 | -spec hash32_update(Handle::hash_handle(), Data::hash_input()) -> ok. 125 | 126 | hash32_update(Handle, Data) when is_binary(Handle) -> 127 | hash32_update_impl(Handle, supported_to_binary(Data)). 128 | 129 | 130 | %% @doc Calculates a digest of all the passed data to the `Handle' hasher. 131 | 132 | -spec hash32_digest(Handle::hash_handle()) -> hash_digest(). 133 | 134 | hash32_digest(Handle) when is_binary(Handle) -> 135 | hash32_digest_impl(Handle). 136 | 137 | 138 | %% @doc Hash `Data' with a default seed value, and return the digest. 139 | %% @see hash64/2 140 | 141 | -spec hash64(Data::hash_input()) -> hash_digest(). 142 | 143 | hash64(Data) -> 144 | hash64(Data, ?DEFAULT_SEED). 145 | 146 | 147 | %% @doc Hash `Data' with `Seed' value, and return the digest. 148 | %% @see hash64/1 149 | 150 | -spec hash64(Data::hash_input(), Seed::hash_seed()) -> hash_digest(). 151 | 152 | hash64(Data, Seed) when is_integer(Seed) -> 153 | hash64_impl(supported_to_binary(Data), Seed). 154 | 155 | 156 | %% @doc Initialize a hasher with a default seed value, and return an handle. 157 | %% @see hash64_init/1 158 | 159 | -spec hash64_init() -> hash_handle(). 160 | 161 | hash64_init() -> 162 | hash64_init(?DEFAULT_SEED). 163 | 164 | 165 | %% @doc Initialize a hasher with `Seed' value, and return an handle. 166 | %% @see hash64_init/0 167 | 168 | -spec hash64_init(Seed::hash_seed()) -> hash_handle(). 169 | 170 | hash64_init(Seed) when is_integer(Seed) -> 171 | hash64_init_impl(Seed). 172 | 173 | 174 | %% @doc Update the `Handle' hasher content with the given `Data'. This can be 175 | %% called many times with new data as it is streamed. 176 | 177 | -spec hash64_update(Handle::hash_handle(), Data::hash_input()) -> ok. 178 | 179 | hash64_update(Handle, Data) when is_binary(Handle) -> 180 | hash64_update_impl(Handle, supported_to_binary(Data)). 181 | 182 | 183 | %% @doc Calculates a digest of all the passed data to the `Handle' hasher. 184 | 185 | -spec hash64_digest(Handle::hash_handle()) -> hash_digest(). 186 | 187 | hash64_digest(Handle) when is_binary(Handle) -> 188 | hash64_digest_impl(Handle). 189 | 190 | 191 | %%%============================================================================= 192 | %%% Helpers 193 | %%%============================================================================= 194 | 195 | supported_to_binary(Data) when is_binary(Data) -> 196 | Data; 197 | supported_to_binary(Data) when is_list(Data) -> 198 | list_to_binary(Data); 199 | supported_to_binary(Data) when is_atom(Data) -> 200 | term_to_binary(Data); 201 | supported_to_binary(Data) when is_integer(Data) -> 202 | list_to_binary(integer_to_list(Data)); 203 | supported_to_binary(Data) when is_float(Data) -> 204 | <>. 205 | 206 | 207 | %%%============================================================================= 208 | %%% Tests 209 | %%%============================================================================= 210 | 211 | -ifdef(TEST). 212 | 213 | -include_lib("eunit/include/eunit.hrl"). 214 | 215 | hash32_test() -> 216 | Hash1 = hash32(<<"FooBar">>), 217 | Handle = hash32_init(), 218 | ok = hash32_update(Handle, <<"Foo">>), 219 | ok = hash32_update(Handle, <<"Bar">>), 220 | Hash2 = hash32_digest(Handle), 221 | ?assertEqual(Hash1, Hash2). 222 | 223 | hash32_seed_test() -> 224 | Hash1 = hash32(<<"FooBar">>, 50), 225 | Handle = hash32_init(50), 226 | ok = hash32_update(Handle, <<"Foo">>), 227 | ok = hash32_update(Handle, <<"Bar">>), 228 | Hash2 = hash32_digest(Handle), 229 | ?assertEqual(Hash1, Hash2). 230 | 231 | hash32_intermediate_result_test() -> 232 | Handle = hash32_init(50), 233 | ok = hash32_update(Handle, <<"Foo">>), 234 | Hash1 = hash32_digest(Handle), 235 | ok = hash32_update(Handle, <<"Bar">>), 236 | Hash2 = hash32_digest(Handle), 237 | ?assertNot(Hash1 == Hash2). 238 | 239 | hash32_overlapping_handles_test() -> 240 | Handle1 = hash32_init(50), 241 | Handle2 = hash32_init(50), 242 | ok = hash32_update(Handle1, <<"Foo">>), 243 | Hash1 = hash32_digest(Handle1), 244 | Hash2 = hash32_digest(Handle2), 245 | ?assertNot(Hash1 == Hash2), 246 | ok = hash32_update(Handle2, <<"Foo">>), 247 | Hash3 = hash32_digest(Handle2), 248 | ?assertEqual(Hash1, Hash3). 249 | 250 | hash32_seed2_test() -> 251 | Hash1 = hash32(<<"FooBar">>, 50), 252 | Hash2 = hash32(<<"FooBar">>), 253 | ?assertNot(Hash1 == Hash2). 254 | 255 | hash32_list_test() -> 256 | Hash1 = hash32([1, 42]), 257 | Hash2 = hash32([1, 220]), 258 | ?assertNot(Hash1 == Hash2). 259 | 260 | hash32_atom_test() -> 261 | Hash1 = hash32(foo), 262 | Hash2 = hash32(bar), 263 | ?assertNot(Hash1 == Hash2). 264 | 265 | hash32_int_test() -> 266 | Hash1 = hash32(42), 267 | Hash2 = hash32(67), 268 | ?assertNot(Hash1 == Hash2). 269 | 270 | hash32_float_test() -> 271 | Hash1 = hash32(5.98), 272 | Hash2 = hash32(5.97), 273 | ?assertNot(Hash1 == Hash2). 274 | 275 | hash64_test() -> 276 | Hash1 = hash64(<<"FooBar">>), 277 | Handle = hash64_init(), 278 | ok = hash64_update(Handle, <<"Foo">>), 279 | ok = hash64_update(Handle, <<"Bar">>), 280 | Hash2 = hash64_digest(Handle), 281 | ?assertEqual(Hash1, Hash2). 282 | 283 | hash64_seed_test() -> 284 | Hash1 = hash64(<<"FooBar">>, 50), 285 | Handle = hash64_init(50), 286 | ok = hash64_update(Handle, <<"Foo">>), 287 | ok = hash64_update(Handle, <<"Bar">>), 288 | Hash2 = hash64_digest(Handle), 289 | ?assertEqual(Hash1, Hash2). 290 | 291 | hash64_intermediate_result_test() -> 292 | Handle = hash64_init(50), 293 | ok = hash64_update(Handle, <<"Foo">>), 294 | Hash1 = hash64_digest(Handle), 295 | ok = hash64_update(Handle, <<"Bar">>), 296 | Hash2 = hash64_digest(Handle), 297 | ?assertNot(Hash1 == Hash2). 298 | 299 | hash64_overlapping_handles_test() -> 300 | Handle1 = hash64_init(50), 301 | Handle2 = hash64_init(50), 302 | ok = hash64_update(Handle1, <<"Foo">>), 303 | Hash1 = hash64_digest(Handle1), 304 | Hash2 = hash64_digest(Handle2), 305 | ?assertNot(Hash1 == Hash2), 306 | ok = hash64_update(Handle2, <<"Foo">>), 307 | Hash3 = hash64_digest(Handle2), 308 | ?assertEqual(Hash1, Hash3). 309 | 310 | hash64_seed2_test() -> 311 | Hash1 = hash64(<<"FooBar">>, 50), 312 | Hash2 = hash64(<<"FooBar">>), 313 | ?assertNot(Hash1 == Hash2). 314 | 315 | hash64_list_test() -> 316 | Hash1 = hash64([1, 42]), 317 | Hash2 = hash64([1, 220]), 318 | ?assertNot(Hash1 == Hash2). 319 | 320 | hash64_atom_test() -> 321 | Hash1 = hash64(foo), 322 | Hash2 = hash64(bar), 323 | ?assertNot(Hash1 == Hash2). 324 | 325 | hash64_int_test() -> 326 | Hash1 = hash64(42), 327 | Hash2 = hash64(67), 328 | ?assertNot(Hash1 == Hash2). 329 | 330 | hash64_float_test() -> 331 | Hash1 = hash64(5.98), 332 | Hash2 = hash64(5.97), 333 | ?assertNot(Hash1 == Hash2). 334 | 335 | -endif. 336 | --------------------------------------------------------------------------------