Line data Source code
1 : // Copyright (c) 2019-2025 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/prinbee
4 : // contact@m2osw.com
5 : //
6 : // This program is free software: you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation, either version 3 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License
17 : // along with this program. If not, see <https://www.gnu.org/licenses/>.
18 :
19 : // self
20 : //
21 : #include "catch_main.h"
22 :
23 :
24 : // prinbee
25 : //
26 : #include <prinbee/file/hash.h>
27 :
28 :
29 : // advgetopt
30 : //
31 : #include <advgetopt/options.h>
32 :
33 :
34 : // last include
35 : //
36 : #include <snapdev/poison.h>
37 :
38 :
39 :
40 : namespace
41 : {
42 :
43 :
44 :
45 : // hash function taken from: https://github.com/ArashPartow/bloom
46 : //
47 51785 : prinbee::hash_t compute_hash(uint8_t const * v, std::size_t size, prinbee::hash_t const seed)
48 : {
49 51785 : prinbee::hash_t hash(seed);
50 51785 : prinbee::hash_t loop(0);
51 :
52 231909882 : for(; size >= 8; v += 8, size -= 8)
53 : {
54 231858097 : prinbee::hash_t i1((v[0] << 24) + (v[1] << 16) + (v[2] << 8) + v[3]);
55 231858097 : prinbee::hash_t i2((v[4] << 24) + (v[5] << 16) + (v[6] << 8) + v[7]);
56 :
57 231858097 : hash ^= (hash << 7) ^ i1 * (hash >> 3) ^
58 231858097 : (~((hash << 11) + (i2 ^ (hash >> 5))));
59 : }
60 :
61 51785 : if(size >= 4)
62 : {
63 25706 : prinbee::hash_t i((v[0] << 24) + (v[1] << 16) + (v[2] << 8) + v[3]);
64 25706 : hash ^= (~((hash << 11) + (i ^ (hash >> 5))));
65 25706 : ++loop;
66 25706 : size -= 4;
67 25706 : v += 4;
68 : }
69 :
70 51785 : if(size >= 2)
71 : {
72 25971 : prinbee::hash_t i((v[0] << 8) + v[1]);
73 25971 : if(loop != 0)
74 : {
75 12908 : hash ^= (hash << 7) ^ i * (hash >> 3);
76 : }
77 : else
78 : {
79 13063 : hash ^= (~((hash << 11) + (i ^ (hash >> 5))));
80 : }
81 25971 : ++loop;
82 25971 : size -= 2;
83 25971 : v += 2;
84 : }
85 :
86 51785 : if(size > 0)
87 : {
88 25856 : hash += (v[0] ^ (hash * 0xA5A5A5A5)) + loop;
89 : }
90 :
91 51785 : return hash;
92 : }
93 :
94 :
95 :
96 : }
97 : // no name namespace
98 :
99 :
100 1 : CATCH_TEST_CASE("hash", "[hash] [valid]")
101 : {
102 3 : CATCH_START_SECTION("hash: 100x verifications")
103 : {
104 101 : for(int count(0); count < 100; ++count)
105 : {
106 100 : std::size_t const size(rand() % 65536 + 32768);
107 :
108 300 : std::vector<std::uint8_t> buffer(size);
109 6622356 : for(std::size_t idx(0); idx < size; ++idx)
110 : {
111 6622256 : buffer[idx] = rand();
112 : }
113 :
114 : // try hash entire buffer at once
115 : {
116 100 : prinbee::hash_t const seed(rand());
117 100 : prinbee::hash_t const expected(compute_hash(buffer.data(), size, seed));
118 100 : prinbee::hash h(seed);
119 100 : h.add(buffer.data(), size);
120 100 : CATCH_REQUIRE(h.get() == expected);
121 : }
122 :
123 : // try a little at a time
124 : {
125 100 : prinbee::hash_t const seed(rand());
126 100 : prinbee::hash h(seed);
127 100 : CATCH_REQUIRE(h.size() == 0);
128 100 : std::size_t processed(0);
129 51785 : while(processed < size)
130 : {
131 51685 : std::size_t incr(rand() % 256 + 1);
132 51685 : if(processed + incr > size)
133 : {
134 100 : incr = size - processed;
135 : }
136 51685 : h.add(buffer.data() + processed, incr);
137 51685 : processed += incr;
138 51685 : CATCH_REQUIRE(h.size() == processed);
139 51685 : prinbee::hash_t const expected(compute_hash(buffer.data(), processed, seed));
140 :
141 51685 : prinbee::hash once(seed);
142 51685 : once.add(buffer.data(), processed);
143 51685 : CATCH_REQUIRE(once.get() == expected);
144 :
145 51685 : CATCH_REQUIRE(h.get() == expected);
146 : }
147 : }
148 :
149 : //hash_t compute_hash(uint8_t const * v, std::size_t size, hash_t hash)
150 : //
151 : // hash(hash_t seed);
152 : //void add(std::uint8_t const * v, std::size_t size);
153 : //hash_t get() const;
154 :
155 100 : }
156 : }
157 2 : CATCH_END_SECTION()
158 1 : }
159 :
160 :
161 :
162 : // vim: ts=4 sw=4 et
|