cdcontainers  0.1.1
Library of data containers and collections for C programming language.
hash.h
Go to the documentation of this file.
1 // The MIT License (MIT)
2 // Copyright (c) 2018 Maksim Andrianov
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to
6 // deal in the Software without restriction, including without limitation the
7 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 // sell copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20 // IN THE SOFTWARE.
29 #ifndef CDCONTAINERS_INCLUDE_CDCONTAINERS_HASH_H
30 #define CDCONTAINERS_INCLUDE_CDCONTAINERS_HASH_H
31 
32 #include <cdcontainers/casts.h>
33 #include <float.h>
34 #include <limits.h>
35 #include <stddef.h>
36 #include <string.h>
37 
38 typedef size_t (*cdc_hash_fn_t)(void const *);
39 
40 #define CDC_DIGITS_CHAR (CHAR_BIT - (CHAR_MIN < 0))
41 #define CDC_DIGITS_SCHAR (CHAR_BIT - 1)
42 #define CDC_DIGITS_UCHAR (CHAR_BIT)
43 #define CDC_DIGITS_SHORT (CHAR_BIT * sizeof(short) - 1)
44 #define CDC_DIGITS_USHORT (CHAR_BIT * sizeof(short))
45 #define CDC_DIGITS_INT (CHAR_BIT * sizeof(int) - 1)
46 #define CDC_DIGITS_UINT (CHAR_BIT * sizeof(int))
47 #define CDC_DIGITS_LONG (CHAR_BIT * sizeof(long) - 1)
48 #define CDC_DIGITS_ULONG (CHAR_BIT * sizeof(long))
49 #define CDC_DIGITS_SIZE (CHAR_BIT * sizeof(size_t))
50 
51 #define MAKE_SIGNED_HASH(T, DIGITS, NAME) \
52  static inline size_t cdc_hash_##NAME(T val) \
53  { \
54  const unsigned int size_t_bits = CDC_DIGITS_SIZE; \
55  const int length = (DIGITS - 1) / (int)(size_t_bits); \
56  unsigned int i; \
57  size_t seed = 0; \
58  T positive = val < 0 ? -1 - val : val; \
59  for (i = length * size_t_bits; i > 0; i -= size_t_bits) \
60  seed ^= (size_t)(positive >> i) + (seed << 6) + (seed >> 2); \
61  seed ^= (size_t)val + (seed << 6) + (seed >> 2); \
62  return seed; \
63  }
64 
65 #define MAKE_UNSIGNED_HASH(T, DIGITS, NAME) \
66  static inline size_t cdc_hash_##NAME(T val) \
67  { \
68  const unsigned int size_t_bits = CDC_DIGITS_SIZE; \
69  const int length = (DIGITS - 1) / (int)(size_t_bits); \
70  unsigned int i; \
71  size_t seed = 0; \
72  for (i = length * size_t_bits; i > 0; i -= size_t_bits) \
73  seed ^= (size_t)(seed >> i) + (seed << 6) + (seed >> 2); \
74  seed ^= (size_t)val + (seed << 6) + (seed >> 2); \
75  return seed; \
76  }
77 
78 static inline size_t cdc_hash_float_combine(size_t seed, size_t value)
79 {
80  seed ^= value + (seed << 6) + (seed >> 2);
81  return seed;
82 }
83 
84 static inline size_t cdc_hash_binary(char *ptr, size_t length)
85 {
86  size_t seed = 0;
87 
88  if (length >= sizeof(size_t)) {
89  memcpy(&seed, ptr, sizeof(size_t));
90  length -= sizeof(size_t);
91  ptr += sizeof(size_t);
92 
93  while (length >= sizeof(size_t)) {
94  size_t buffer = 0;
95  memcpy(&buffer, ptr, sizeof(size_t));
96  seed = cdc_hash_float_combine(seed, buffer);
97  length -= sizeof(size_t);
98  ptr += sizeof(size_t);
99  }
100  }
101 
102  if (length > 0) {
103  size_t buffer = 0;
104  memcpy(&buffer, ptr, length);
105  seed = cdc_hash_float_combine(seed, buffer);
106  }
107 
108  return seed;
109 }
110 
111 #define MAKE_FLOAT_HASH(T, NAME) \
112  static inline size_t cdc_hash_##NAME(T val) \
113  { \
114  return cdc_hash_binary((char *)&val, sizeof(T)); \
115  }
116 
117 MAKE_SIGNED_HASH(signed char, CDC_DIGITS_SCHAR, schar)
118 MAKE_SIGNED_HASH(short, CDC_DIGITS_SHORT, short)
121 
122 MAKE_FLOAT_HASH(float, float)
123 MAKE_FLOAT_HASH(double, double)
124 MAKE_FLOAT_HASH(long double, ldouble)
125 
126 MAKE_UNSIGNED_HASH(unsigned char, CDC_DIGITS_UCHAR, uchar)
127 MAKE_UNSIGNED_HASH(unsigned short, CDC_DIGITS_USHORT, ushort)
128 MAKE_UNSIGNED_HASH(unsigned int, CDC_DIGITS_UINT, uint)
129 MAKE_UNSIGNED_HASH(unsigned long, CDC_DIGITS_ULONG, ulong)
130 
131 #if CHAR_MIN < 0
133 #else
135 #endif
136 
137 #define MAKE_POINTER_DATA_HASH(T, NAME, CAST_FUNC) \
138  static inline size_t cdc_pdhash_##NAME(void *val) \
139  { \
140  T t = CAST_FUNC(val); \
141  return cdc_hash_##NAME(t); \
142  }
143 
145 MAKE_POINTER_DATA_HASH(signed char, schar, CDC_TO_SCHAR)
146 MAKE_POINTER_DATA_HASH(unsigned char, uchar, CDC_TO_UCHAR)
148 MAKE_POINTER_DATA_HASH(unsigned short, ushort, CDC_TO_USHORT)
150 MAKE_POINTER_DATA_HASH(unsigned int, uint, CDC_TO_UINT)
151 
152 #ifdef CDC_LONG_CAST
154 MAKE_POINTER_DATA_HASH(unsigned long, ulong, CDC_TO_ULONG)
155 #endif
156 #ifdef CDC_FLOAT_CAST
157 MAKE_POINTER_DATA_HASH(float, float, CDC_TO_FLOAT)
158 #endif
159 #ifdef CDC_DOUBLE_CAST
160 MAKE_POINTER_DATA_HASH(double, double, CDC_TO_DOUBLE)
161 #endif
162 
163 #endif // CDCONTAINERS_INCLUDE_CDCONTAINERS_HASH_H
#define CDC_TO_INT(p)
Definition: casts.h:44
#define CDC_TO_USHORT(p)
Definition: casts.h:41
#define MAKE_UNSIGNED_HASH(T, DIGITS, NAME)
Definition: hash.h:65
#define MAKE_SIGNED_HASH(T, DIGITS, NAME)
Definition: hash.h:51
#define CDC_TO_UCHAR(p)
Definition: casts.h:35
#define MAKE_FLOAT_HASH(T, NAME)
Definition: hash.h:111
#define CDC_TO_CHAR(p)
Definition: casts.h:29
#define CDC_DIGITS_LONG
Definition: hash.h:47
#define CDC_DIGITS_CHAR
Definition: hash.h:40
#define CDC_DIGITS_UINT
Definition: hash.h:46
#define CDC_DIGITS_UCHAR
Definition: hash.h:42
#define CDC_TO_UINT(p)
Definition: casts.h:47
#define CDC_DIGITS_INT
Definition: hash.h:45
size_t(* cdc_hash_fn_t)(void const *)
Definition: hash.h:38
#define CDC_TO_LONG(p)
Definition: casts.h:54
static size_t cdc_hash_float_combine(size_t seed, size_t value)
Definition: hash.h:78
static size_t cdc_hash_binary(char *ptr, size_t length)
Definition: hash.h:84
#define CDC_TO_SCHAR(p)
Definition: casts.h:32
#define MAKE_POINTER_DATA_HASH(T, NAME, CAST_FUNC)
Definition: hash.h:137
#define CDC_DIGITS_SHORT
Definition: hash.h:43
#define CDC_TO_ULONG(p)
Definition: casts.h:58
#define CDC_TO_SHORT(p)
Definition: casts.h:38
#define CDC_DIGITS_ULONG
Definition: hash.h:48
#define CDC_DIGITS_SCHAR
Definition: hash.h:41
#define CDC_DIGITS_USHORT
Definition: hash.h:44