Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
hash.h
Go to the documentation of this file.
1/*
2 This file is part of Ansel,
3 Copyright (C) 2026 Aurélien PIERRE.
4
5 Ansel is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 Ansel is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with Ansel. If not, see <http://www.gnu.org/licenses/>.
17*/
18#ifndef DT_COMMON_HASH_H
19#define DT_COMMON_HASH_H
20
21/* dt_hash(): the content-addressing primitive of the whole app (history, pipeline,
22 * caches). Pure and dependency-free on purpose: low-level compute units include this
23 * instead of darktable.h. */
24
25#include <stddef.h>
26#include <stdint.h>
27
28#ifdef __cplusplus
29extern "C" {
30#endif
31
32// Cryptographic-strength hash of `str` representing its state, with negligible
33// collision probability compared to a plain multiplicative hash.
34// This is SipHash-2-4 (Aumasson & Bernstein, https://131002.net/siphash/), a
35// keyed pseudo-random function with 64-bit output. The incoming `hash` is folded
36// in as the key material, so calls can be chained to combine several buffers:
37// hash = dt_hash(hash, a, sizeof(a));
38// hash = dt_hash(hash, b, sizeof(b));
39// `hash` should be seeded to 5381 (or any constant) on the first call, or carried
40// over from a previous dt_hash() result.
41// NOTE: the digest is computed over the raw bytes in native endianness, so it is
42// stable within a run/machine but not portable across architectures of differing
43// endianness (same constraint as the previous implementation when hashing structs).
44#define DT_SIPROUND \
45 do \
46 { \
47 v0 += v1; v1 = (v1 << 13) | (v1 >> 51); v1 ^= v0; v0 = (v0 << 32) | (v0 >> 32); \
48 v2 += v3; v3 = (v3 << 16) | (v3 >> 48); v3 ^= v2; \
49 v0 += v3; v3 = (v3 << 21) | (v3 >> 43); v3 ^= v0; \
50 v2 += v1; v1 = (v1 << 17) | (v1 >> 47); v1 ^= v2; v2 = (v2 << 32) | (v2 >> 32); \
51 } while(0)
52
53static inline uint64_t dt_hash(uint64_t hash, const char *str, size_t size)
54{
55 // Derive the 128-bit SipHash key from the chained seed so that chaining keeps
56 // mixing prior state into the new digest. The second key word is a fixed
57 // constant (fractional bits of the golden ratio) to add entropy.
58 const uint64_t k0 = hash;
59 const uint64_t k1 = 0x9e3779b97f4a7c15ULL;
60
61 uint64_t v0 = 0x736f6d6570736575ULL ^ k0;
62 uint64_t v1 = 0x646f72616e646f6dULL ^ k1;
63 uint64_t v2 = 0x6c7967656e657261ULL ^ k0;
64 uint64_t v3 = 0x7465646279746573ULL ^ k1;
65
66 const uint8_t *in = (const uint8_t *)str;
67 const size_t blocks = size & ~(size_t)7;
68 size_t i = 0;
69 for(; i < blocks; i += 8)
70 {
71 uint64_t m;
72 __builtin_memcpy(&m, in + i, sizeof(m));
73 v3 ^= m;
76 v0 ^= m;
77 }
78
79 // Tail: remaining 0..7 bytes plus the length in the top byte.
80 uint64_t b = (uint64_t)size << 56;
81 switch(size & 7)
82 {
83 case 7: b |= (uint64_t)in[i + 6] << 48; /* fall through */
84 case 6: b |= (uint64_t)in[i + 5] << 40; /* fall through */
85 case 5: b |= (uint64_t)in[i + 4] << 32; /* fall through */
86 case 4: b |= (uint64_t)in[i + 3] << 24; /* fall through */
87 case 3: b |= (uint64_t)in[i + 2] << 16; /* fall through */
88 case 2: b |= (uint64_t)in[i + 1] << 8; /* fall through */
89 case 1: b |= (uint64_t)in[i + 0]; /* fall through */
90 case 0: break;
91 }
92 v3 ^= b;
95 v0 ^= b;
96
97 // Finalization.
98 v2 ^= 0xff;
103
104 return v0 ^ v1 ^ v2 ^ v3;
105}
106#undef DT_SIPROUND
107
108#ifdef __cplusplus
109}
110#endif
111
112#endif // DT_COMMON_HASH_H
113
114// clang-format off
115// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
116// vim: shiftwidth=2 expandtab tabstop=2 cindent
117// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
118// clang-format on
#define m
Definition basecurve.c:283
#define DT_SIPROUND
Definition hash.h:44
static uint64_t dt_hash(uint64_t hash, const char *str, size_t size)
Definition hash.h:53
c< 3;c++) acc+=v_1[c] *v_2[c];return acc;}static inline float sqf(const float x){ return x *x;}static inline float euclidean_norm(const dt_aligned_pixel_t vector){ return fmaxf(sqrtf(sqf(vector[0])+sqf(vector[1])+sqf(vector[2])), 1.52587890625e-05f);}static inline void downscale_vector(dt_aligned_pixel_t vector, const float scaling){ const int valid=(scaling > 1.52587890625e-05f) &&!isnan(scaling);for(size_t c=0;c< 3;c++) vector[c]=(valid) ? vector[c]/(scaling+1.52587890625e-05f) :vector[c]/1.52587890625e-05f ;}static inline void upscale_vector(dt_aligned_pixel_t vector, const float scaling){ const int valid=(scaling > 1.52587890625e-05f) &&!isnan(scaling);for(size_t c=0;c< 3;c++) vector[c]=(valid) ? vector[c] *(scaling+1.52587890625e-05f) :vector[c] *1.52587890625e-05f ;}static inline float dt_log2f(const float f){ return logf(f)/logf(2.0f);}union float_int { float f;int k;};static inline float dt_fast_hypotf(const float x, const float y){ return sqrtf(x *x+y *y);}static inline float dt_fast_expf(const float x){ const int i1=0x3f800000u;const int i2=0x402DF854u;const int k0=i1+x *(i2 - i1);union float_int u;u.k=k0 > k0
Definition math.h:265
size_t size
Definition mipmap_cache.c:3
unsigned __int64 uint64_t
Definition strptime.c:75