Merge lp:~pedronis/ubuntu-push/gethosts into lp:ubuntu-push
- gethosts
- Merge into trunk
Proposed by
Samuele Pedroni
Status: | Merged |
---|---|
Approved by: | Samuele Pedroni |
Approved revision: | 92 |
Merged at revision: | 89 |
Proposed branch: | lp:~pedronis/ubuntu-push/gethosts |
Merge into: | lp:ubuntu-push |
Diff against target: |
1015 lines (+952/-0) 11 files modified
client/gethosts/gethost.go (+92/-0) client/gethosts/gethost_test.go (+102/-0) debian/copyright (+4/-0) external/README (+3/-0) external/murmur3/LICENSE (+24/-0) external/murmur3/README.md (+49/-0) external/murmur3/murmur.go (+65/-0) external/murmur3/murmur128.go (+189/-0) external/murmur3/murmur32.go (+154/-0) external/murmur3/murmur64.go (+45/-0) external/murmur3/murmur_test.go (+225/-0) |
To merge this branch: | bzr merge lp:~pedronis/ubuntu-push/gethosts |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
John Lenton (community) | Approve | ||
Review via email: mp+212463@code.launchpad.net |
Commit message
introduce package gethosts implementing finding hosts to connect to for delivery of notifications
Description of the change
introduce package gethosts implementing finding hosts to connect to for delivery of notifications
vendorize an impl of murmur3
To post a comment you must log in.
- 91. By Samuele Pedroni
-
newline
- 92. By Samuele Pedroni
-
remove .gitignore
Revision history for this message
John Lenton (chipaca) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added directory 'client/gethosts' | |||
2 | === added file 'client/gethosts/gethost.go' | |||
3 | --- client/gethosts/gethost.go 1970-01-01 00:00:00 +0000 | |||
4 | +++ client/gethosts/gethost.go 2014-03-24 15:37:31 +0000 | |||
5 | @@ -0,0 +1,92 @@ | |||
6 | 1 | /* | ||
7 | 2 | Copyright 2013-2014 Canonical Ltd. | ||
8 | 3 | |||
9 | 4 | This program is free software: you can redistribute it and/or modify it | ||
10 | 5 | under the terms of the GNU General Public License version 3, as published | ||
11 | 6 | by the Free Software Foundation. | ||
12 | 7 | |||
13 | 8 | This program is distributed in the hope that it will be useful, but | ||
14 | 9 | WITHOUT ANY WARRANTY; without even the implied warranties of | ||
15 | 10 | MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR | ||
16 | 11 | PURPOSE. See the GNU General Public License for more details. | ||
17 | 12 | |||
18 | 13 | You should have received a copy of the GNU General Public License along | ||
19 | 14 | with this program. If not, see <http://www.gnu.org/licenses/>. | ||
20 | 15 | */ | ||
21 | 16 | |||
22 | 17 | // Package gethosts implements finding hosts to connect to for delivery of notifications. | ||
23 | 18 | package gethosts | ||
24 | 19 | |||
25 | 20 | import ( | ||
26 | 21 | "encoding/json" | ||
27 | 22 | "errors" | ||
28 | 23 | "fmt" | ||
29 | 24 | "io/ioutil" | ||
30 | 25 | "net/http" | ||
31 | 26 | "time" | ||
32 | 27 | |||
33 | 28 | "launchpad.net/ubuntu-push/external/murmur3" | ||
34 | 29 | http13 "launchpad.net/ubuntu-push/http13client" | ||
35 | 30 | ) | ||
36 | 31 | |||
37 | 32 | // GetHost implements finding hosts to connect to consulting a remote endpoint providing a hash of the device identifier. | ||
38 | 33 | type GetHost struct { | ||
39 | 34 | hash string | ||
40 | 35 | endpointUrl string | ||
41 | 36 | cli *http13.Client | ||
42 | 37 | } | ||
43 | 38 | |||
44 | 39 | // New makes a GetHost. | ||
45 | 40 | func New(deviceId, endpointUrl string, timeout time.Duration) *GetHost { | ||
46 | 41 | hash := murmur3.Sum64([]byte(deviceId)) | ||
47 | 42 | return &GetHost{ | ||
48 | 43 | hash: fmt.Sprintf("%x", hash), | ||
49 | 44 | endpointUrl: endpointUrl, | ||
50 | 45 | cli: &http13.Client{ | ||
51 | 46 | Transport: &http13.Transport{TLSHandshakeTimeout: timeout}, | ||
52 | 47 | Timeout: timeout, | ||
53 | 48 | }, | ||
54 | 49 | } | ||
55 | 50 | } | ||
56 | 51 | |||
57 | 52 | type expected struct { | ||
58 | 53 | Hosts []string | ||
59 | 54 | } | ||
60 | 55 | |||
61 | 56 | var ( | ||
62 | 57 | ErrRequest = errors.New("request was not accepted") | ||
63 | 58 | ErrInternal = errors.New("remote had an internal error") | ||
64 | 59 | ErrTemporary = errors.New("remote had a temporary error") | ||
65 | 60 | ) | ||
66 | 61 | |||
67 | 62 | // Get gets a list of hosts consulting the endpoint. | ||
68 | 63 | func (gh *GetHost) Get() ([]string, error) { | ||
69 | 64 | resp, err := gh.cli.Get(gh.endpointUrl + "?h=" + gh.hash) | ||
70 | 65 | if err != nil { | ||
71 | 66 | return nil, err | ||
72 | 67 | } | ||
73 | 68 | defer resp.Body.Close() | ||
74 | 69 | if resp.StatusCode != http.StatusOK { | ||
75 | 70 | switch { | ||
76 | 71 | case resp.StatusCode == http.StatusInternalServerError: | ||
77 | 72 | return nil, ErrInternal | ||
78 | 73 | case resp.StatusCode > http.StatusInternalServerError: | ||
79 | 74 | return nil, ErrTemporary | ||
80 | 75 | default: | ||
81 | 76 | return nil, ErrRequest | ||
82 | 77 | } | ||
83 | 78 | } | ||
84 | 79 | body, err := ioutil.ReadAll(resp.Body) | ||
85 | 80 | if err != nil { | ||
86 | 81 | return nil, err | ||
87 | 82 | } | ||
88 | 83 | var parsed expected | ||
89 | 84 | err = json.Unmarshal(body, &parsed) | ||
90 | 85 | if err != nil { | ||
91 | 86 | return nil, ErrTemporary | ||
92 | 87 | } | ||
93 | 88 | if len(parsed.Hosts) == 0 { | ||
94 | 89 | return nil, ErrTemporary | ||
95 | 90 | } | ||
96 | 91 | return parsed.Hosts, nil | ||
97 | 92 | } | ||
98 | 0 | 93 | ||
99 | === added file 'client/gethosts/gethost_test.go' | |||
100 | --- client/gethosts/gethost_test.go 1970-01-01 00:00:00 +0000 | |||
101 | +++ client/gethosts/gethost_test.go 2014-03-24 15:37:31 +0000 | |||
102 | @@ -0,0 +1,102 @@ | |||
103 | 1 | /* | ||
104 | 2 | Copyright 2013-2014 Canonical Ltd. | ||
105 | 3 | |||
106 | 4 | This program is free software: you can redistribute it and/or modify it | ||
107 | 5 | under the terms of the GNU General Public License version 3, as published | ||
108 | 6 | by the Free Software Foundation. | ||
109 | 7 | |||
110 | 8 | This program is distributed in the hope that it will be useful, but | ||
111 | 9 | WITHOUT ANY WARRANTY; without even the implied warranties of | ||
112 | 10 | MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR | ||
113 | 11 | PURPOSE. See the GNU General Public License for more details. | ||
114 | 12 | |||
115 | 13 | You should have received a copy of the GNU General Public License along | ||
116 | 14 | with this program. If not, see <http://www.gnu.org/licenses/>. | ||
117 | 15 | */ | ||
118 | 16 | |||
119 | 17 | package gethosts | ||
120 | 18 | |||
121 | 19 | import ( | ||
122 | 20 | "encoding/json" | ||
123 | 21 | "fmt" | ||
124 | 22 | "net/http" | ||
125 | 23 | "net/http/httptest" | ||
126 | 24 | "testing" | ||
127 | 25 | "time" | ||
128 | 26 | |||
129 | 27 | . "launchpad.net/gocheck" | ||
130 | 28 | |||
131 | 29 | "launchpad.net/ubuntu-push/external/murmur3" | ||
132 | 30 | ) | ||
133 | 31 | |||
134 | 32 | func TestGetHosts(t *testing.T) { TestingT(t) } | ||
135 | 33 | |||
136 | 34 | type getHostsSuite struct{} | ||
137 | 35 | |||
138 | 36 | var _ = Suite(&getHostsSuite{}) | ||
139 | 37 | |||
140 | 38 | func (s *getHostsSuite) TestNew(c *C) { | ||
141 | 39 | gh := New("foobar", "http://where/hosts", 10*time.Second) | ||
142 | 40 | c.Check(gh.hash, Equals, fmt.Sprintf("%x", murmur3.Sum64([]byte("foobar")))) | ||
143 | 41 | c.Check(gh.endpointUrl, Equals, "http://where/hosts") | ||
144 | 42 | } | ||
145 | 43 | |||
146 | 44 | func (s *getHostsSuite) TestGet(c *C) { | ||
147 | 45 | ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
148 | 46 | x := r.FormValue("h") | ||
149 | 47 | b, err := json.Marshal(map[string]interface{}{ | ||
150 | 48 | "hosts": []string{"http://" + x}, | ||
151 | 49 | }) | ||
152 | 50 | if err != nil { | ||
153 | 51 | panic(err) | ||
154 | 52 | } | ||
155 | 53 | w.Header().Set("Content-Type", "application/json") | ||
156 | 54 | w.Write(b) | ||
157 | 55 | })) | ||
158 | 56 | defer ts.Close() | ||
159 | 57 | gh := New("foobar", ts.URL, 1*time.Second) | ||
160 | 58 | res, err := gh.Get() | ||
161 | 59 | c.Assert(err, IsNil) | ||
162 | 60 | c.Check(res, DeepEquals, []string{"http://c1130408a700afe0"}) | ||
163 | 61 | } | ||
164 | 62 | |||
165 | 63 | func (s *getHostsSuite) TestGetTimeout(c *C) { | ||
166 | 64 | finish := make(chan bool, 1) | ||
167 | 65 | ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
168 | 66 | <-finish | ||
169 | 67 | })) | ||
170 | 68 | defer func() { | ||
171 | 69 | time.Sleep(100 * time.Millisecond) // work around -race issue | ||
172 | 70 | ts.Close() | ||
173 | 71 | }() | ||
174 | 72 | defer func() { | ||
175 | 73 | finish <- true | ||
176 | 74 | }() | ||
177 | 75 | gh := New("foobar", ts.URL, 1*time.Second) | ||
178 | 76 | _, err := gh.Get() | ||
179 | 77 | c.Check(err, ErrorMatches, ".*closed.*") | ||
180 | 78 | } | ||
181 | 79 | |||
182 | 80 | func (s *getHostsSuite) TestGetErrorScenarios(c *C) { | ||
183 | 81 | status := make(chan int, 1) | ||
184 | 82 | body := make(chan string, 1) | ||
185 | 83 | ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
186 | 84 | w.WriteHeader(<-status) | ||
187 | 85 | fmt.Fprintf(w, "%s", <-body) | ||
188 | 86 | })) | ||
189 | 87 | defer ts.Close() | ||
190 | 88 | gh := New("foobar", ts.URL, 1*time.Second) | ||
191 | 89 | scenario := func(st int, bdy string, expectedErr error) { | ||
192 | 90 | status <- st | ||
193 | 91 | body <- bdy | ||
194 | 92 | _, err := gh.Get() | ||
195 | 93 | c.Check(err, Equals, expectedErr) | ||
196 | 94 | } | ||
197 | 95 | |||
198 | 96 | scenario(http.StatusBadRequest, "", ErrRequest) | ||
199 | 97 | scenario(http.StatusInternalServerError, "", ErrInternal) | ||
200 | 98 | scenario(http.StatusGatewayTimeout, "", ErrTemporary) | ||
201 | 99 | |||
202 | 100 | scenario(http.StatusOK, "{", ErrTemporary) | ||
203 | 101 | scenario(http.StatusOK, "{}", ErrTemporary) | ||
204 | 102 | } | ||
205 | 0 | 103 | ||
206 | === modified file 'debian/copyright' | |||
207 | --- debian/copyright 2014-03-21 11:21:30 +0000 | |||
208 | +++ debian/copyright 2014-03-24 15:37:31 +0000 | |||
209 | @@ -10,6 +10,10 @@ | |||
210 | 10 | Copyright: 2009-2013 The Go Authors | 10 | Copyright: 2009-2013 The Go Authors |
211 | 11 | License: BSD-3-clause | 11 | License: BSD-3-clause |
212 | 12 | 12 | ||
213 | 13 | Files: external/murmur3/* | ||
214 | 14 | Copyright: 2013 Sébastien Paolacci | ||
215 | 15 | License: BSD-3-clause | ||
216 | 16 | |||
217 | 13 | License: GPL-3.0 | 17 | License: GPL-3.0 |
218 | 14 | This program is free software: you can redistribute it and/or modify | 18 | This program is free software: you can redistribute it and/or modify |
219 | 15 | it under the terms of the GNU General Public License as published by | 19 | it under the terms of the GNU General Public License as published by |
220 | 16 | 20 | ||
221 | === added directory 'external' | |||
222 | === added file 'external/README' | |||
223 | --- external/README 1970-01-01 00:00:00 +0000 | |||
224 | +++ external/README 2014-03-24 15:37:31 +0000 | |||
225 | @@ -0,0 +1,3 @@ | |||
226 | 1 | Directly included vendorized small packages. | ||
227 | 2 | |||
228 | 3 | * murmor3 comes from import at lp:~ubuntu-push-hackers/ubuntu-push/murmur at revno 10 | ||
229 | 0 | 4 | ||
230 | === added directory 'external/murmur3' | |||
231 | === added file 'external/murmur3/LICENSE' | |||
232 | --- external/murmur3/LICENSE 1970-01-01 00:00:00 +0000 | |||
233 | +++ external/murmur3/LICENSE 2014-03-24 15:37:31 +0000 | |||
234 | @@ -0,0 +1,24 @@ | |||
235 | 1 | Copyright 2013, Sébastien Paolacci. | ||
236 | 2 | All rights reserved. | ||
237 | 3 | |||
238 | 4 | Redistribution and use in source and binary forms, with or without | ||
239 | 5 | modification, are permitted provided that the following conditions are met: | ||
240 | 6 | * Redistributions of source code must retain the above copyright | ||
241 | 7 | notice, this list of conditions and the following disclaimer. | ||
242 | 8 | * Redistributions in binary form must reproduce the above copyright | ||
243 | 9 | notice, this list of conditions and the following disclaimer in the | ||
244 | 10 | documentation and/or other materials provided with the distribution. | ||
245 | 11 | * Neither the name of the library nor the | ||
246 | 12 | names of its contributors may be used to endorse or promote products | ||
247 | 13 | derived from this software without specific prior written permission. | ||
248 | 14 | |||
249 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||
250 | 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
251 | 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
252 | 18 | DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY | ||
253 | 19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
254 | 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
255 | 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
256 | 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
257 | 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
258 | 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
259 | 0 | 25 | ||
260 | === added file 'external/murmur3/README.md' | |||
261 | --- external/murmur3/README.md 1970-01-01 00:00:00 +0000 | |||
262 | +++ external/murmur3/README.md 2014-03-24 15:37:31 +0000 | |||
263 | @@ -0,0 +1,49 @@ | |||
264 | 1 | murmur3 | ||
265 | 2 | ======= | ||
266 | 3 | |||
267 | 4 | Native Go implementation of Austin Appleby's third MurmurHash revision (aka | ||
268 | 5 | MurmurHash3). | ||
269 | 6 | |||
270 | 7 | Reference algorithm has been slightly hacked as to support the streaming mode | ||
271 | 8 | required by Go's standard [Hash interface](http://golang.org/pkg/hash/#Hash). | ||
272 | 9 | |||
273 | 10 | |||
274 | 11 | Benchmarks | ||
275 | 12 | ---------- | ||
276 | 13 | |||
277 | 14 | Go tip as of 2013-03-11 (i.e almost go1.1), core i7 @ 3.4 Ghz. All runs | ||
278 | 15 | include hasher instanciation and sequence finalization. | ||
279 | 16 | |||
280 | 17 | <pre> | ||
281 | 18 | |||
282 | 19 | Benchmark32_1 200000000 8.4 ns/op 119.39 MB/s | ||
283 | 20 | Benchmark32_2 200000000 9.5 ns/op 211.69 MB/s | ||
284 | 21 | Benchmark32_4 500000000 7.9 ns/op 506.24 MB/s | ||
285 | 22 | Benchmark32_8 200000000 9.4 ns/op 853.40 MB/s | ||
286 | 23 | Benchmark32_16 100000000 12.1 ns/op 1324.19 MB/s | ||
287 | 24 | Benchmark32_32 100000000 18.2 ns/op 1760.81 MB/s | ||
288 | 25 | Benchmark32_64 50000000 31.2 ns/op 2051.59 MB/s | ||
289 | 26 | Benchmark32_128 50000000 58.7 ns/op 2180.34 MB/s | ||
290 | 27 | Benchmark32_256 20000000 116.0 ns/op 2194.85 MB/s | ||
291 | 28 | Benchmark32_512 10000000 227.0 ns/op 2247.43 MB/s | ||
292 | 29 | Benchmark32_1024 5000000 449.0 ns/op 2276.88 MB/s | ||
293 | 30 | Benchmark32_2048 2000000 894.0 ns/op 2289.87 MB/s | ||
294 | 31 | Benchmark32_4096 1000000 1792.0 ns/op 2284.64 MB/s | ||
295 | 32 | Benchmark32_8192 500000 3559.0 ns/op 2301.33 MB/s | ||
296 | 33 | |||
297 | 34 | Benchmark128_1 50000000 33.2 ns/op 30.15 MB/s | ||
298 | 35 | Benchmark128_2 50000000 33.3 ns/op 59.99 MB/s | ||
299 | 36 | Benchmark128_4 50000000 35.4 ns/op 112.88 MB/s | ||
300 | 37 | Benchmark128_8 50000000 36.6 ns/op 218.30 MB/s | ||
301 | 38 | Benchmark128_16 50000000 35.5 ns/op 450.86 MB/s | ||
302 | 39 | Benchmark128_32 50000000 35.3 ns/op 905.84 MB/s | ||
303 | 40 | Benchmark128_64 50000000 44.3 ns/op 1443.76 MB/s | ||
304 | 41 | Benchmark128_128 50000000 58.2 ns/op 2201.02 MB/s | ||
305 | 42 | Benchmark128_256 20000000 85.3 ns/op 2999.88 MB/s | ||
306 | 43 | Benchmark128_512 10000000 142.0 ns/op 3592.97 MB/s | ||
307 | 44 | Benchmark128_1024 10000000 258.0 ns/op 3963.74 MB/s | ||
308 | 45 | Benchmark128_2048 5000000 494.0 ns/op 4144.65 MB/s | ||
309 | 46 | Benchmark128_4096 2000000 955.0 ns/op 4285.80 MB/s | ||
310 | 47 | Benchmark128_8192 1000000 1884.0 ns/op 4347.12 MB/s | ||
311 | 48 | |||
312 | 49 | </pre> | ||
313 | 0 | 50 | ||
314 | === added file 'external/murmur3/murmur.go' | |||
315 | --- external/murmur3/murmur.go 1970-01-01 00:00:00 +0000 | |||
316 | +++ external/murmur3/murmur.go 2014-03-24 15:37:31 +0000 | |||
317 | @@ -0,0 +1,65 @@ | |||
318 | 1 | // Copyright 2013, Sébastien Paolacci. All rights reserved. | ||
319 | 2 | // Use of this source code is governed by a BSD-style | ||
320 | 3 | // license that can be found in the LICENSE file. | ||
321 | 4 | |||
322 | 5 | /* | ||
323 | 6 | Native (and fast) implementation of Austin Appleby's MurmurHash3. | ||
324 | 7 | |||
325 | 8 | Package murmur3 implements Austin Appleby's non-cryptographic MurmurHash3. | ||
326 | 9 | |||
327 | 10 | Reference implementation: | ||
328 | 11 | http://code.google.com/p/smhasher/wiki/MurmurHash3 | ||
329 | 12 | |||
330 | 13 | History, characteristics and (legacy) perfs: | ||
331 | 14 | https://sites.google.com/site/murmurhash/ | ||
332 | 15 | https://sites.google.com/site/murmurhash/statistics | ||
333 | 16 | */ | ||
334 | 17 | package murmur3 | ||
335 | 18 | |||
336 | 19 | type bmixer interface { | ||
337 | 20 | bmix(p []byte) (tail []byte) | ||
338 | 21 | Size() (n int) | ||
339 | 22 | reset() | ||
340 | 23 | } | ||
341 | 24 | |||
342 | 25 | type digest struct { | ||
343 | 26 | clen int // Digested input cumulative length. | ||
344 | 27 | tail []byte // 0 to Size()-1 bytes view of `buf'. | ||
345 | 28 | buf [16]byte // Expected (but not required) to be Size() large. | ||
346 | 29 | bmixer | ||
347 | 30 | } | ||
348 | 31 | |||
349 | 32 | func (d *digest) BlockSize() int { return 1 } | ||
350 | 33 | |||
351 | 34 | func (d *digest) Write(p []byte) (n int, err error) { | ||
352 | 35 | n = len(p) | ||
353 | 36 | d.clen += n | ||
354 | 37 | |||
355 | 38 | if len(d.tail) > 0 { | ||
356 | 39 | // Stick back pending bytes. | ||
357 | 40 | nfree := d.Size() - len(d.tail) // nfree ∈ [1, d.Size()-1]. | ||
358 | 41 | if nfree < len(p) { | ||
359 | 42 | // One full block can be formed. | ||
360 | 43 | block := append(d.tail, p[:nfree]...) | ||
361 | 44 | p = p[nfree:] | ||
362 | 45 | _ = d.bmix(block) // No tail. | ||
363 | 46 | } else { | ||
364 | 47 | // Tail's buf is large enough to prevent reallocs. | ||
365 | 48 | p = append(d.tail, p...) | ||
366 | 49 | } | ||
367 | 50 | } | ||
368 | 51 | |||
369 | 52 | d.tail = d.bmix(p) | ||
370 | 53 | |||
371 | 54 | // Keep own copy of the 0 to Size()-1 pending bytes. | ||
372 | 55 | nn := copy(d.buf[:], d.tail) | ||
373 | 56 | d.tail = d.buf[:nn] | ||
374 | 57 | |||
375 | 58 | return n, nil | ||
376 | 59 | } | ||
377 | 60 | |||
378 | 61 | func (d *digest) Reset() { | ||
379 | 62 | d.clen = 0 | ||
380 | 63 | d.tail = nil | ||
381 | 64 | d.bmixer.reset() | ||
382 | 65 | } | ||
383 | 0 | 66 | ||
384 | === added file 'external/murmur3/murmur128.go' | |||
385 | --- external/murmur3/murmur128.go 1970-01-01 00:00:00 +0000 | |||
386 | +++ external/murmur3/murmur128.go 2014-03-24 15:37:31 +0000 | |||
387 | @@ -0,0 +1,189 @@ | |||
388 | 1 | package murmur3 | ||
389 | 2 | |||
390 | 3 | import ( | ||
391 | 4 | //"encoding/binary" | ||
392 | 5 | "hash" | ||
393 | 6 | "unsafe" | ||
394 | 7 | ) | ||
395 | 8 | |||
396 | 9 | const ( | ||
397 | 10 | c1_128 = 0x87c37b91114253d5 | ||
398 | 11 | c2_128 = 0x4cf5ad432745937f | ||
399 | 12 | ) | ||
400 | 13 | |||
401 | 14 | // Make sure interfaces are correctly implemented. | ||
402 | 15 | var ( | ||
403 | 16 | _ hash.Hash = new(digest128) | ||
404 | 17 | _ Hash128 = new(digest128) | ||
405 | 18 | _ bmixer = new(digest128) | ||
406 | 19 | ) | ||
407 | 20 | |||
408 | 21 | // Hack: the standard api doesn't define any Hash128 interface. | ||
409 | 22 | type Hash128 interface { | ||
410 | 23 | hash.Hash | ||
411 | 24 | Sum128() (uint64, uint64) | ||
412 | 25 | } | ||
413 | 26 | |||
414 | 27 | // digest128 represents a partial evaluation of a 128 bites hash. | ||
415 | 28 | type digest128 struct { | ||
416 | 29 | digest | ||
417 | 30 | h1 uint64 // Unfinalized running hash part 1. | ||
418 | 31 | h2 uint64 // Unfinalized running hash part 2. | ||
419 | 32 | } | ||
420 | 33 | |||
421 | 34 | func New128() Hash128 { | ||
422 | 35 | d := new(digest128) | ||
423 | 36 | d.bmixer = d | ||
424 | 37 | d.Reset() | ||
425 | 38 | return d | ||
426 | 39 | } | ||
427 | 40 | |||
428 | 41 | func (d *digest128) Size() int { return 16 } | ||
429 | 42 | |||
430 | 43 | func (d *digest128) reset() { d.h1, d.h2 = 1, 1 } | ||
431 | 44 | |||
432 | 45 | func (d *digest128) Sum(b []byte) []byte { | ||
433 | 46 | h1, h2 := d.h1, d.h2 | ||
434 | 47 | return append(b, | ||
435 | 48 | byte(h1>>56), byte(h1>>48), byte(h1>>40), byte(h1>>32), | ||
436 | 49 | byte(h1>>24), byte(h1>>16), byte(h1>>8), byte(h1), | ||
437 | 50 | |||
438 | 51 | byte(h2>>56), byte(h2>>48), byte(h2>>40), byte(h2>>32), | ||
439 | 52 | byte(h2>>24), byte(h2>>16), byte(h2>>8), byte(h2), | ||
440 | 53 | ) | ||
441 | 54 | } | ||
442 | 55 | |||
443 | 56 | func (d *digest128) bmix(p []byte) (tail []byte) { | ||
444 | 57 | h1, h2 := d.h1, d.h2 | ||
445 | 58 | |||
446 | 59 | nblocks := len(p) / 16 | ||
447 | 60 | for i := 0; i < nblocks; i++ { | ||
448 | 61 | t := (*[2]uint64)(unsafe.Pointer(&p[i*16])) | ||
449 | 62 | k1, k2 := t[0], t[1] | ||
450 | 63 | |||
451 | 64 | k1 *= c1_128 | ||
452 | 65 | k1 = (k1 << 31) | (k1 >> 33) // rotl64(k1, 31) | ||
453 | 66 | k1 *= c2_128 | ||
454 | 67 | h1 ^= k1 | ||
455 | 68 | |||
456 | 69 | h1 = (h1 << 27) | (h1 >> 37) // rotl64(h1, 27) | ||
457 | 70 | h1 += h2 | ||
458 | 71 | h1 = h1*5 + 0x52dce729 | ||
459 | 72 | |||
460 | 73 | k2 *= c2_128 | ||
461 | 74 | k2 = (k2 << 33) | (k2 >> 31) // rotl64(k2, 33) | ||
462 | 75 | k2 *= c1_128 | ||
463 | 76 | h2 ^= k2 | ||
464 | 77 | |||
465 | 78 | h2 = (h2 << 31) | (h2 >> 33) // rotl64(h2, 31) | ||
466 | 79 | h2 += h1 | ||
467 | 80 | h2 = h2*5 + 0x38495ab5 | ||
468 | 81 | } | ||
469 | 82 | d.h1, d.h2 = h1, h2 | ||
470 | 83 | return p[nblocks*d.Size():] | ||
471 | 84 | } | ||
472 | 85 | |||
473 | 86 | func (d *digest128) Sum128() (h1, h2 uint64) { | ||
474 | 87 | |||
475 | 88 | h1, h2 = d.h1, d.h2 | ||
476 | 89 | |||
477 | 90 | var k1, k2 uint64 | ||
478 | 91 | switch len(d.tail) & 15 { | ||
479 | 92 | case 15: | ||
480 | 93 | k2 ^= uint64(d.tail[14]) << 48 | ||
481 | 94 | fallthrough | ||
482 | 95 | case 14: | ||
483 | 96 | k2 ^= uint64(d.tail[13]) << 40 | ||
484 | 97 | fallthrough | ||
485 | 98 | case 13: | ||
486 | 99 | k2 ^= uint64(d.tail[12]) << 32 | ||
487 | 100 | fallthrough | ||
488 | 101 | case 12: | ||
489 | 102 | k2 ^= uint64(d.tail[11]) << 24 | ||
490 | 103 | fallthrough | ||
491 | 104 | case 11: | ||
492 | 105 | k2 ^= uint64(d.tail[10]) << 16 | ||
493 | 106 | fallthrough | ||
494 | 107 | case 10: | ||
495 | 108 | k2 ^= uint64(d.tail[9]) << 8 | ||
496 | 109 | fallthrough | ||
497 | 110 | case 9: | ||
498 | 111 | k2 ^= uint64(d.tail[8]) << 0 | ||
499 | 112 | |||
500 | 113 | k2 *= c2_128 | ||
501 | 114 | k2 = (k2 << 33) | (k2 >> 31) // rotl64(k2, 33) | ||
502 | 115 | k2 *= c1_128 | ||
503 | 116 | h2 ^= k2 | ||
504 | 117 | |||
505 | 118 | fallthrough | ||
506 | 119 | |||
507 | 120 | case 8: | ||
508 | 121 | k1 ^= uint64(d.tail[7]) << 56 | ||
509 | 122 | fallthrough | ||
510 | 123 | case 7: | ||
511 | 124 | k1 ^= uint64(d.tail[6]) << 48 | ||
512 | 125 | fallthrough | ||
513 | 126 | case 6: | ||
514 | 127 | k1 ^= uint64(d.tail[5]) << 40 | ||
515 | 128 | fallthrough | ||
516 | 129 | case 5: | ||
517 | 130 | k1 ^= uint64(d.tail[4]) << 32 | ||
518 | 131 | fallthrough | ||
519 | 132 | case 4: | ||
520 | 133 | k1 ^= uint64(d.tail[3]) << 24 | ||
521 | 134 | fallthrough | ||
522 | 135 | case 3: | ||
523 | 136 | k1 ^= uint64(d.tail[2]) << 16 | ||
524 | 137 | fallthrough | ||
525 | 138 | case 2: | ||
526 | 139 | k1 ^= uint64(d.tail[1]) << 8 | ||
527 | 140 | fallthrough | ||
528 | 141 | case 1: | ||
529 | 142 | k1 ^= uint64(d.tail[0]) << 0 | ||
530 | 143 | k1 *= c1_128 | ||
531 | 144 | k1 = (k1 << 31) | (k1 >> 33) // rotl64(k1, 31) | ||
532 | 145 | k1 *= c2_128 | ||
533 | 146 | h1 ^= k1 | ||
534 | 147 | } | ||
535 | 148 | |||
536 | 149 | h1 ^= uint64(d.clen) | ||
537 | 150 | h2 ^= uint64(d.clen) | ||
538 | 151 | |||
539 | 152 | h1 += h2 | ||
540 | 153 | h2 += h1 | ||
541 | 154 | |||
542 | 155 | h1 = fmix64(h1) | ||
543 | 156 | h2 = fmix64(h2) | ||
544 | 157 | |||
545 | 158 | h1 += h2 | ||
546 | 159 | h2 += h1 | ||
547 | 160 | |||
548 | 161 | return h1, h2 | ||
549 | 162 | } | ||
550 | 163 | |||
551 | 164 | func fmix64(k uint64) uint64 { | ||
552 | 165 | k ^= k >> 33 | ||
553 | 166 | k *= 0xff51afd7ed558ccd | ||
554 | 167 | k ^= k >> 33 | ||
555 | 168 | k *= 0xc4ceb9fe1a85ec53 | ||
556 | 169 | k ^= k >> 33 | ||
557 | 170 | return k | ||
558 | 171 | } | ||
559 | 172 | |||
560 | 173 | /* | ||
561 | 174 | func rotl64(x uint64, r byte) uint64 { | ||
562 | 175 | return (x << r) | (x >> (64 - r)) | ||
563 | 176 | } | ||
564 | 177 | */ | ||
565 | 178 | |||
566 | 179 | // Sum128 returns the MurmurHash3 sum of data. It is equivalent to the | ||
567 | 180 | // following sequence (without the extra burden and the extra allocation): | ||
568 | 181 | // hasher := New128() | ||
569 | 182 | // hasher.Write(data) | ||
570 | 183 | // return hasher.Sum128() | ||
571 | 184 | func Sum128(data []byte) (h1 uint64, h2 uint64) { | ||
572 | 185 | d := &digest128{h1: 1, h2: 1} | ||
573 | 186 | d.tail = d.bmix(data) | ||
574 | 187 | d.clen = len(data) | ||
575 | 188 | return d.Sum128() | ||
576 | 189 | } | ||
577 | 0 | 190 | ||
578 | === added file 'external/murmur3/murmur32.go' | |||
579 | --- external/murmur3/murmur32.go 1970-01-01 00:00:00 +0000 | |||
580 | +++ external/murmur3/murmur32.go 2014-03-24 15:37:31 +0000 | |||
581 | @@ -0,0 +1,154 @@ | |||
582 | 1 | package murmur3 | ||
583 | 2 | |||
584 | 3 | // http://code.google.com/p/guava-libraries/source/browse/guava/src/com/google/common/hash/Murmur3_32HashFunction.java | ||
585 | 4 | |||
586 | 5 | import ( | ||
587 | 6 | "hash" | ||
588 | 7 | "unsafe" | ||
589 | 8 | ) | ||
590 | 9 | |||
591 | 10 | // Make sure interfaces are correctly implemented. | ||
592 | 11 | var ( | ||
593 | 12 | _ hash.Hash = new(digest32) | ||
594 | 13 | _ hash.Hash32 = new(digest32) | ||
595 | 14 | ) | ||
596 | 15 | |||
597 | 16 | const ( | ||
598 | 17 | c1_32 uint32 = 0xcc9e2d51 | ||
599 | 18 | c2_32 uint32 = 0x1b873593 | ||
600 | 19 | ) | ||
601 | 20 | |||
602 | 21 | // digest32 represents a partial evaluation of a 32 bites hash. | ||
603 | 22 | type digest32 struct { | ||
604 | 23 | digest | ||
605 | 24 | h1 uint32 // Unfinalized running hash. | ||
606 | 25 | } | ||
607 | 26 | |||
608 | 27 | func New32() hash.Hash32 { | ||
609 | 28 | d := new(digest32) | ||
610 | 29 | d.bmixer = d | ||
611 | 30 | d.Reset() | ||
612 | 31 | return d | ||
613 | 32 | } | ||
614 | 33 | |||
615 | 34 | func (d *digest32) Size() int { return 4 } | ||
616 | 35 | |||
617 | 36 | func (d *digest32) reset() { d.h1 = 1 } | ||
618 | 37 | |||
619 | 38 | func (d *digest32) Sum(b []byte) []byte { | ||
620 | 39 | h := d.h1 | ||
621 | 40 | return append(b, byte(h>>24), byte(h>>16), byte(h>>8), byte(h)) | ||
622 | 41 | } | ||
623 | 42 | |||
624 | 43 | // Digest as many blocks as possible. | ||
625 | 44 | func (d *digest32) bmix(p []byte) (tail []byte) { | ||
626 | 45 | h1 := d.h1 | ||
627 | 46 | |||
628 | 47 | nblocks := len(p) / 4 | ||
629 | 48 | for i := 0; i < nblocks; i++ { | ||
630 | 49 | k1 := *(*uint32)(unsafe.Pointer(&p[i*4])) | ||
631 | 50 | |||
632 | 51 | k1 *= c1_32 | ||
633 | 52 | k1 = (k1 << 15) | (k1 >> 17) // rotl32(k1, 15) | ||
634 | 53 | k1 *= c2_32 | ||
635 | 54 | |||
636 | 55 | h1 ^= k1 | ||
637 | 56 | h1 = (h1 << 13) | (h1 >> 19) // rotl32(h1, 13) | ||
638 | 57 | h1 = h1*5 + 0xe6546b64 | ||
639 | 58 | } | ||
640 | 59 | d.h1 = h1 | ||
641 | 60 | return p[nblocks*d.Size():] | ||
642 | 61 | } | ||
643 | 62 | |||
644 | 63 | func (d *digest32) Sum32() (h1 uint32) { | ||
645 | 64 | |||
646 | 65 | h1 = d.h1 | ||
647 | 66 | |||
648 | 67 | var k1 uint32 | ||
649 | 68 | switch len(d.tail) & 3 { | ||
650 | 69 | case 3: | ||
651 | 70 | k1 ^= uint32(d.tail[2]) << 16 | ||
652 | 71 | fallthrough | ||
653 | 72 | case 2: | ||
654 | 73 | k1 ^= uint32(d.tail[1]) << 8 | ||
655 | 74 | fallthrough | ||
656 | 75 | case 1: | ||
657 | 76 | k1 ^= uint32(d.tail[0]) | ||
658 | 77 | k1 *= c1_32 | ||
659 | 78 | k1 = (k1 << 15) | (k1 >> 17) // rotl32(k1, 15) | ||
660 | 79 | k1 *= c2_32 | ||
661 | 80 | h1 ^= k1 | ||
662 | 81 | } | ||
663 | 82 | |||
664 | 83 | h1 ^= uint32(d.clen) | ||
665 | 84 | |||
666 | 85 | h1 ^= h1 >> 16 | ||
667 | 86 | h1 *= 0x85ebca6b | ||
668 | 87 | h1 ^= h1 >> 13 | ||
669 | 88 | h1 *= 0xc2b2ae35 | ||
670 | 89 | h1 ^= h1 >> 16 | ||
671 | 90 | |||
672 | 91 | return h1 | ||
673 | 92 | } | ||
674 | 93 | |||
675 | 94 | /* | ||
676 | 95 | func rotl32(x uint32, r byte) uint32 { | ||
677 | 96 | return (x << r) | (x >> (32 - r)) | ||
678 | 97 | } | ||
679 | 98 | */ | ||
680 | 99 | |||
681 | 100 | // Sum32 returns the MurmurHash3 sum of data. It is equivalent to the | ||
682 | 101 | // following sequence (without the extra burden and the extra allocation): | ||
683 | 102 | // hasher := New32() | ||
684 | 103 | // hasher.Write(data) | ||
685 | 104 | // return hasher.Sum32() | ||
686 | 105 | func Sum32(data []byte) uint32 { | ||
687 | 106 | |||
688 | 107 | var h1 uint32 = 1 | ||
689 | 108 | |||
690 | 109 | nblocks := len(data) / 4 | ||
691 | 110 | var p uintptr | ||
692 | 111 | if len(data) > 0 { | ||
693 | 112 | p = uintptr(unsafe.Pointer(&data[0])) | ||
694 | 113 | } | ||
695 | 114 | p1 := p + uintptr(4*nblocks) | ||
696 | 115 | for ; p < p1; p += 4 { | ||
697 | 116 | k1 := *(*uint32)(unsafe.Pointer(p)) | ||
698 | 117 | |||
699 | 118 | k1 *= c1_32 | ||
700 | 119 | k1 = (k1 << 15) | (k1 >> 17) // rotl32(k1, 15) | ||
701 | 120 | k1 *= c2_32 | ||
702 | 121 | |||
703 | 122 | h1 ^= k1 | ||
704 | 123 | h1 = (h1 << 13) | (h1 >> 19) // rotl32(h1, 13) | ||
705 | 124 | h1 = h1*5 + 0xe6546b64 | ||
706 | 125 | } | ||
707 | 126 | |||
708 | 127 | tail := data[nblocks*4:] | ||
709 | 128 | |||
710 | 129 | var k1 uint32 | ||
711 | 130 | switch len(tail) & 3 { | ||
712 | 131 | case 3: | ||
713 | 132 | k1 ^= uint32(tail[2]) << 16 | ||
714 | 133 | fallthrough | ||
715 | 134 | case 2: | ||
716 | 135 | k1 ^= uint32(tail[1]) << 8 | ||
717 | 136 | fallthrough | ||
718 | 137 | case 1: | ||
719 | 138 | k1 ^= uint32(tail[0]) | ||
720 | 139 | k1 *= c1_32 | ||
721 | 140 | k1 = (k1 << 15) | (k1 >> 17) // rotl32(k1, 15) | ||
722 | 141 | k1 *= c2_32 | ||
723 | 142 | h1 ^= k1 | ||
724 | 143 | } | ||
725 | 144 | |||
726 | 145 | h1 ^= uint32(len(data)) | ||
727 | 146 | |||
728 | 147 | h1 ^= h1 >> 16 | ||
729 | 148 | h1 *= 0x85ebca6b | ||
730 | 149 | h1 ^= h1 >> 13 | ||
731 | 150 | h1 *= 0xc2b2ae35 | ||
732 | 151 | h1 ^= h1 >> 16 | ||
733 | 152 | |||
734 | 153 | return h1 | ||
735 | 154 | } | ||
736 | 0 | 155 | ||
737 | === added file 'external/murmur3/murmur64.go' | |||
738 | --- external/murmur3/murmur64.go 1970-01-01 00:00:00 +0000 | |||
739 | +++ external/murmur3/murmur64.go 2014-03-24 15:37:31 +0000 | |||
740 | @@ -0,0 +1,45 @@ | |||
741 | 1 | package murmur3 | ||
742 | 2 | |||
743 | 3 | import ( | ||
744 | 4 | "hash" | ||
745 | 5 | ) | ||
746 | 6 | |||
747 | 7 | // Make sure interfaces are correctly implemented. | ||
748 | 8 | var ( | ||
749 | 9 | _ hash.Hash = new(digest64) | ||
750 | 10 | _ hash.Hash64 = new(digest64) | ||
751 | 11 | _ bmixer = new(digest64) | ||
752 | 12 | ) | ||
753 | 13 | |||
754 | 14 | // digest64 is half a digest128. | ||
755 | 15 | type digest64 digest128 | ||
756 | 16 | |||
757 | 17 | func New64() hash.Hash64 { | ||
758 | 18 | d := (*digest64)(New128().(*digest128)) | ||
759 | 19 | return d | ||
760 | 20 | } | ||
761 | 21 | |||
762 | 22 | func (d *digest64) Sum(b []byte) []byte { | ||
763 | 23 | h1 := d.h1 | ||
764 | 24 | return append(b, | ||
765 | 25 | byte(h1>>56), byte(h1>>48), byte(h1>>40), byte(h1>>32), | ||
766 | 26 | byte(h1>>24), byte(h1>>16), byte(h1>>8), byte(h1)) | ||
767 | 27 | } | ||
768 | 28 | |||
769 | 29 | func (d *digest64) Sum64() uint64 { | ||
770 | 30 | h1, _ := (*digest128)(d).Sum128() | ||
771 | 31 | return h1 | ||
772 | 32 | } | ||
773 | 33 | |||
774 | 34 | // Sum64 returns the MurmurHash3 sum of data. It is equivalent to the | ||
775 | 35 | // following sequence (without the extra burden and the extra allocation): | ||
776 | 36 | // hasher := New64() | ||
777 | 37 | // hasher.Write(data) | ||
778 | 38 | // return hasher.Sum64() | ||
779 | 39 | func Sum64(data []byte) uint64 { | ||
780 | 40 | d := &digest128{h1: 1, h2: 1} | ||
781 | 41 | d.tail = d.bmix(data) | ||
782 | 42 | d.clen = len(data) | ||
783 | 43 | h1, _ := d.Sum128() | ||
784 | 44 | return h1 | ||
785 | 45 | } | ||
786 | 0 | 46 | ||
787 | === added file 'external/murmur3/murmur_test.go' | |||
788 | --- external/murmur3/murmur_test.go 1970-01-01 00:00:00 +0000 | |||
789 | +++ external/murmur3/murmur_test.go 2014-03-24 15:37:31 +0000 | |||
790 | @@ -0,0 +1,225 @@ | |||
791 | 1 | package murmur3 | ||
792 | 2 | |||
793 | 3 | import ( | ||
794 | 4 | "hash" | ||
795 | 5 | "testing" | ||
796 | 6 | ) | ||
797 | 7 | |||
798 | 8 | var data = []struct { | ||
799 | 9 | h32 uint32 | ||
800 | 10 | h64_1 uint64 | ||
801 | 11 | h64_2 uint64 | ||
802 | 12 | s string | ||
803 | 13 | }{ | ||
804 | 14 | {0x514e28b7, 0x4610abe56eff5cb5, 0x51622daa78f83583, ""}, | ||
805 | 15 | {0xbb4abcad, 0xa78ddff5adae8d10, 0x128900ef20900135, "hello"}, | ||
806 | 16 | {0x6f5cb2e9, 0x8b95f808840725c6, 0x1597ed5422bd493b, "hello, world"}, | ||
807 | 17 | {0xf50e1f30, 0x2a929de9c8f97b2f, 0x56a41d99af43a2db, "19 Jan 2038 at 3:14:07 AM"}, | ||
808 | 18 | {0x846f6a36, 0xfb3325171f9744da, 0xaaf8b92a5f722952, "The quick brown fox jumps over the lazy dog."}, | ||
809 | 19 | } | ||
810 | 20 | |||
811 | 21 | func TestRef(t *testing.T) { | ||
812 | 22 | for _, elem := range data { | ||
813 | 23 | |||
814 | 24 | var h32 hash.Hash32 = New32() | ||
815 | 25 | h32.Write([]byte(elem.s)) | ||
816 | 26 | if v := h32.Sum32(); v != elem.h32 { | ||
817 | 27 | t.Errorf("'%s': 0x%x (want 0x%x)", elem.s, v, elem.h32) | ||
818 | 28 | } | ||
819 | 29 | |||
820 | 30 | if v := Sum32([]byte(elem.s)); v != elem.h32 { | ||
821 | 31 | t.Errorf("'%s': 0x%x (want 0x%x)", elem.s, v, elem.h32) | ||
822 | 32 | } | ||
823 | 33 | |||
824 | 34 | var h64 hash.Hash64 = New64() | ||
825 | 35 | h64.Write([]byte(elem.s)) | ||
826 | 36 | if v := h64.Sum64(); v != elem.h64_1 { | ||
827 | 37 | t.Errorf("'%s': 0x%x (want 0x%x)", elem.s, v, elem.h64_1) | ||
828 | 38 | } | ||
829 | 39 | |||
830 | 40 | var h128 Hash128 = New128() | ||
831 | 41 | h128.Write([]byte(elem.s)) | ||
832 | 42 | if v1, v2 := h128.Sum128(); v1 != elem.h64_1 || v2 != elem.h64_2 { | ||
833 | 43 | t.Errorf("'%s': 0x%x-0x%x (want 0x%x-0x%x)", elem.s, v1, v2, elem.h64_1, elem.h64_2) | ||
834 | 44 | } | ||
835 | 45 | |||
836 | 46 | if v1, v2 := Sum128([]byte(elem.s)); v1 != elem.h64_1 || v2 != elem.h64_2 { | ||
837 | 47 | t.Errorf("'%s': 0x%x-0x%x (want 0x%x-0x%x)", elem.s, v1, v2, elem.h64_1, elem.h64_2) | ||
838 | 48 | } | ||
839 | 49 | } | ||
840 | 50 | } | ||
841 | 51 | |||
842 | 52 | func TestIncremental(t *testing.T) { | ||
843 | 53 | for _, elem := range data { | ||
844 | 54 | h32 := New32() | ||
845 | 55 | h128 := New128() | ||
846 | 56 | for i, j, k := 0, 0, len(elem.s); i < k; i = j { | ||
847 | 57 | j = 2*i + 3 | ||
848 | 58 | if j > k { | ||
849 | 59 | j = k | ||
850 | 60 | } | ||
851 | 61 | s := elem.s[i:j] | ||
852 | 62 | print(s + "|") | ||
853 | 63 | h32.Write([]byte(s)) | ||
854 | 64 | h128.Write([]byte(s)) | ||
855 | 65 | } | ||
856 | 66 | println() | ||
857 | 67 | if v := h32.Sum32(); v != elem.h32 { | ||
858 | 68 | t.Errorf("'%s': 0x%x (want 0x%x)", elem.s, v, elem.h32) | ||
859 | 69 | } | ||
860 | 70 | if v1, v2 := h128.Sum128(); v1 != elem.h64_1 || v2 != elem.h64_2 { | ||
861 | 71 | t.Errorf("'%s': 0x%x-0x%x (want 0x%x-0x%x)", elem.s, v1, v2, elem.h64_1, elem.h64_2) | ||
862 | 72 | } | ||
863 | 73 | } | ||
864 | 74 | } | ||
865 | 75 | |||
866 | 76 | //--- | ||
867 | 77 | |||
868 | 78 | func bench32(b *testing.B, length int) { | ||
869 | 79 | buf := make([]byte, length) | ||
870 | 80 | b.SetBytes(int64(length)) | ||
871 | 81 | b.ResetTimer() | ||
872 | 82 | for i := 0; i < b.N; i++ { | ||
873 | 83 | Sum32(buf) | ||
874 | 84 | } | ||
875 | 85 | } | ||
876 | 86 | |||
877 | 87 | func Benchmark32_1(b *testing.B) { | ||
878 | 88 | bench32(b, 1) | ||
879 | 89 | } | ||
880 | 90 | func Benchmark32_2(b *testing.B) { | ||
881 | 91 | bench32(b, 2) | ||
882 | 92 | } | ||
883 | 93 | func Benchmark32_4(b *testing.B) { | ||
884 | 94 | bench32(b, 4) | ||
885 | 95 | } | ||
886 | 96 | func Benchmark32_8(b *testing.B) { | ||
887 | 97 | bench32(b, 8) | ||
888 | 98 | } | ||
889 | 99 | func Benchmark32_16(b *testing.B) { | ||
890 | 100 | bench32(b, 16) | ||
891 | 101 | } | ||
892 | 102 | func Benchmark32_32(b *testing.B) { | ||
893 | 103 | bench32(b, 32) | ||
894 | 104 | } | ||
895 | 105 | func Benchmark32_64(b *testing.B) { | ||
896 | 106 | bench32(b, 64) | ||
897 | 107 | } | ||
898 | 108 | func Benchmark32_128(b *testing.B) { | ||
899 | 109 | bench32(b, 128) | ||
900 | 110 | } | ||
901 | 111 | func Benchmark32_256(b *testing.B) { | ||
902 | 112 | bench32(b, 256) | ||
903 | 113 | } | ||
904 | 114 | func Benchmark32_512(b *testing.B) { | ||
905 | 115 | bench32(b, 512) | ||
906 | 116 | } | ||
907 | 117 | func Benchmark32_1024(b *testing.B) { | ||
908 | 118 | bench32(b, 1024) | ||
909 | 119 | } | ||
910 | 120 | func Benchmark32_2048(b *testing.B) { | ||
911 | 121 | bench32(b, 2048) | ||
912 | 122 | } | ||
913 | 123 | func Benchmark32_4096(b *testing.B) { | ||
914 | 124 | bench32(b, 4096) | ||
915 | 125 | } | ||
916 | 126 | func Benchmark32_8192(b *testing.B) { | ||
917 | 127 | bench32(b, 8192) | ||
918 | 128 | } | ||
919 | 129 | |||
920 | 130 | //--- | ||
921 | 131 | |||
922 | 132 | func benchPartial32(b *testing.B, length int) { | ||
923 | 133 | buf := make([]byte, length) | ||
924 | 134 | b.SetBytes(int64(length)) | ||
925 | 135 | |||
926 | 136 | start := (32 / 8) / 2 | ||
927 | 137 | chunks := 7 | ||
928 | 138 | k := length / chunks | ||
929 | 139 | tail := (length - start) % k | ||
930 | 140 | |||
931 | 141 | b.ResetTimer() | ||
932 | 142 | for i := 0; i < b.N; i++ { | ||
933 | 143 | hasher := New32() | ||
934 | 144 | hasher.Write(buf[0:start]) | ||
935 | 145 | |||
936 | 146 | for j := start; j+k <= length; j += k { | ||
937 | 147 | hasher.Write(buf[j : j+k]) | ||
938 | 148 | } | ||
939 | 149 | |||
940 | 150 | hasher.Write(buf[length-tail:]) | ||
941 | 151 | hasher.Sum32() | ||
942 | 152 | } | ||
943 | 153 | } | ||
944 | 154 | |||
945 | 155 | func BenchmarkPartial32_8(b *testing.B) { | ||
946 | 156 | benchPartial32(b, 8) | ||
947 | 157 | } | ||
948 | 158 | func BenchmarkPartial32_16(b *testing.B) { | ||
949 | 159 | benchPartial32(b, 16) | ||
950 | 160 | } | ||
951 | 161 | func BenchmarkPartial32_32(b *testing.B) { | ||
952 | 162 | benchPartial32(b, 32) | ||
953 | 163 | } | ||
954 | 164 | func BenchmarkPartial32_64(b *testing.B) { | ||
955 | 165 | benchPartial32(b, 64) | ||
956 | 166 | } | ||
957 | 167 | func BenchmarkPartial32_128(b *testing.B) { | ||
958 | 168 | benchPartial32(b, 128) | ||
959 | 169 | } | ||
960 | 170 | |||
961 | 171 | //--- | ||
962 | 172 | |||
963 | 173 | func bench128(b *testing.B, length int) { | ||
964 | 174 | buf := make([]byte, length) | ||
965 | 175 | b.SetBytes(int64(length)) | ||
966 | 176 | b.ResetTimer() | ||
967 | 177 | for i := 0; i < b.N; i++ { | ||
968 | 178 | Sum128(buf) | ||
969 | 179 | } | ||
970 | 180 | } | ||
971 | 181 | |||
972 | 182 | func Benchmark128_1(b *testing.B) { | ||
973 | 183 | bench128(b, 1) | ||
974 | 184 | } | ||
975 | 185 | func Benchmark128_2(b *testing.B) { | ||
976 | 186 | bench128(b, 2) | ||
977 | 187 | } | ||
978 | 188 | func Benchmark128_4(b *testing.B) { | ||
979 | 189 | bench128(b, 4) | ||
980 | 190 | } | ||
981 | 191 | func Benchmark128_8(b *testing.B) { | ||
982 | 192 | bench128(b, 8) | ||
983 | 193 | } | ||
984 | 194 | func Benchmark128_16(b *testing.B) { | ||
985 | 195 | bench128(b, 16) | ||
986 | 196 | } | ||
987 | 197 | func Benchmark128_32(b *testing.B) { | ||
988 | 198 | bench128(b, 32) | ||
989 | 199 | } | ||
990 | 200 | func Benchmark128_64(b *testing.B) { | ||
991 | 201 | bench128(b, 64) | ||
992 | 202 | } | ||
993 | 203 | func Benchmark128_128(b *testing.B) { | ||
994 | 204 | bench128(b, 128) | ||
995 | 205 | } | ||
996 | 206 | func Benchmark128_256(b *testing.B) { | ||
997 | 207 | bench128(b, 256) | ||
998 | 208 | } | ||
999 | 209 | func Benchmark128_512(b *testing.B) { | ||
1000 | 210 | bench128(b, 512) | ||
1001 | 211 | } | ||
1002 | 212 | func Benchmark128_1024(b *testing.B) { | ||
1003 | 213 | bench128(b, 1024) | ||
1004 | 214 | } | ||
1005 | 215 | func Benchmark128_2048(b *testing.B) { | ||
1006 | 216 | bench128(b, 2048) | ||
1007 | 217 | } | ||
1008 | 218 | func Benchmark128_4096(b *testing.B) { | ||
1009 | 219 | bench128(b, 4096) | ||
1010 | 220 | } | ||
1011 | 221 | func Benchmark128_8192(b *testing.B) { | ||
1012 | 222 | bench128(b, 8192) | ||
1013 | 223 | } | ||
1014 | 224 | |||
1015 | 225 | //--- |