OLD | NEW |
| (Empty) |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 package memory | |
6 | |
7 import ( | |
8 "bytes" | |
9 "encoding/binary" | |
10 "fmt" | |
11 "math" | |
12 "time" | |
13 | |
14 "appengine" | |
15 | |
16 "github.com/luci/luci-go/common/cmpbin" | |
17 ) | |
18 | |
19 func writeString(buf *bytes.Buffer, s string) { | |
20 cmpbin.WriteUint(buf, uint64(len(s))) | |
21 buf.WriteString(s) | |
22 } | |
23 | |
24 func readString(buf *bytes.Buffer) (string, error) { | |
25 b, err := readBytes(buf) | |
26 if err != nil { | |
27 return "", err | |
28 } | |
29 return string(b), nil | |
30 } | |
31 | |
32 func writeBytes(buf *bytes.Buffer, b []byte) { | |
33 cmpbin.WriteUint(buf, uint64(len(b))) | |
34 buf.Write(b) | |
35 } | |
36 | |
37 func readBytes(buf *bytes.Buffer) ([]byte, error) { | |
38 val, _, err := cmpbin.ReadUint(buf) | |
39 if err != nil { | |
40 return nil, err | |
41 } | |
42 if val > 2*1024*1024 { // 2MB | |
43 return nil, fmt.Errorf("readBytes: tried to read %d bytes (> 2MB
)", val) | |
44 } | |
45 retBuf := make([]byte, val) | |
46 n, _ := buf.Read(retBuf) // err is either io.EOF or nil for bytes.Buffer | |
47 if uint64(n) != val { | |
48 return nil, fmt.Errorf("readBytes: expected %d bytes but read %d
", val, n) | |
49 } | |
50 return retBuf, err | |
51 } | |
52 | |
53 func writeFloat64(buf *bytes.Buffer, v float64) { | |
54 // byte-ordered floats http://stereopsis.com/radix.html | |
55 bits := math.Float64bits(v) | |
56 bits = bits ^ (-(bits >> 63) | (1 << 63)) | |
57 data := make([]byte, 8) | |
58 binary.BigEndian.PutUint64(data, bits) | |
59 buf.Write(data) | |
60 } | |
61 | |
62 func readFloat64(buf *bytes.Buffer) (float64, error) { | |
63 // byte-ordered floats http://stereopsis.com/radix.html | |
64 data := make([]byte, 8) | |
65 _, err := buf.Read(data) | |
66 if err != nil { | |
67 return 0, err | |
68 } | |
69 bits := binary.BigEndian.Uint64(data) | |
70 return math.Float64frombits(bits ^ (((bits >> 63) - 1) | (1 << 63))), ni
l | |
71 } | |
72 | |
73 // We truncate this to microseconds and drop the timezone, because that's the | |
74 // way that the appengine SDK does it. Awesome, right? Also: its not documented. | |
75 func writeTime(buf *bytes.Buffer, t time.Time) { | |
76 cmpbin.WriteUint(buf, uint64(t.Unix())*1e6+uint64(t.Nanosecond()/1e3)) | |
77 } | |
78 | |
79 func readTime(buf *bytes.Buffer) (time.Time, error) { | |
80 v, _, err := cmpbin.ReadUint(buf) | |
81 if err != nil { | |
82 return time.Time{}, err | |
83 } | |
84 return time.Unix(int64(v/1e6), int64((v%1e6)*1e3)), nil | |
85 } | |
86 | |
87 func writeGeoPoint(buf *bytes.Buffer, gp appengine.GeoPoint) { | |
88 writeFloat64(buf, gp.Lat) | |
89 writeFloat64(buf, gp.Lng) | |
90 } | |
91 | |
92 func readGeoPoint(buf *bytes.Buffer) (pt appengine.GeoPoint, err error) { | |
93 if pt.Lat, err = readFloat64(buf); err != nil { | |
94 return | |
95 } | |
96 pt.Lng, err = readFloat64(buf) | |
97 return | |
98 } | |
OLD | NEW |