Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(619)

Side by Side Diff: service/rawdatastore/invertible.go

Issue 1259593005: Add 'user friendly' datastore API. (Closed) Base URL: https://github.com/luci/gae.git@master
Patch Set: 100% coverage of new code Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 rawdatastore
6
7 import (
8 "bytes"
9 )
10
11 // Buffer is the interface which corresponds to the subset of *bytes.Buffer
12 // that this package requires.
13 type Buffer interface {
14 String() string
15 Grow(int)
16
17 Read([]byte) (int, error)
18 ReadByte() (byte, error)
19
20 Write([]byte) (int, error)
21 WriteByte(c byte) error
22 WriteString(s string) (int, error)
23 }
24
25 var _ Buffer = (*bytes.Buffer)(nil)
26
27 // InvertibleBuffer is just like Buffer, except that it also has a stateful
28 // Invert() method, which will cause all reads and writes to/from it to be
29 // inverted (e.g. every byte XOR 0xFF).
30 //
31 // Implementing queries requires manipulating the index entries (e.g.
32 // synthesizing them, parsing them, etc.). In particular, when you have
33 // a reverse-sorted field (e.g. high to low instead of low to high), it's
34 // achieved by having all the bits inverted.
35 //
36 // All the serialization formats include delimiter information, which the
37 // parsers only know to parse non-inverted. If we don't have this buffer, we'd
38 // basically have to invert every byte in the []byte array when we're trying to
39 // decode a reverse-ordered field (including the bytes of all fields after the
40 // one we intend to parse) so that the parser can consume as many bytes as it
41 // needs (and it only knows the number of bytes it needs as it decodes them).
42 // This InvertibleBuffer lets that happen on the fly without having to flip the
43 // whole []byte.
44 //
45 // If you know you need it, you'll know it's the right thing. If you're not sure
46 // then you definitely don't need it!
47 type InvertibleBuffer interface {
48 Buffer
49 Invert()
50 }
51
52 type invertibleBuffer struct {
53 Buffer
54 invert bool
55 }
56
57 // Invertible returns an InvertibleBuffer based on the Buffer.
58 func Invertible(b Buffer) InvertibleBuffer {
59 return &invertibleBuffer{b, false}
60 }
61
62 func (ib *invertibleBuffer) Read(bs []byte) (int, error) {
63 n, err := ib.Buffer.Read(bs)
64 if ib.invert {
65 for i, b := range bs {
66 bs[i] = b ^ 0xFF
67 }
68 }
69 return n, err
70 }
71
72 func (ib *invertibleBuffer) WriteString(s string) (int, error) {
73 if ib.invert {
74 ib.Grow(len(s))
75 for i := 0; i < len(s); i++ {
76 if err := ib.Buffer.WriteByte(s[i] ^ 0xFF); err != nil {
77 return i, err
78 }
79 }
80 return len(s), nil
81 }
82 return ib.Buffer.WriteString(s)
83 }
84
85 func (ib *invertibleBuffer) Write(bs []byte) (int, error) {
86 if ib.invert {
87 ib.Grow(len(bs))
88 for i, b := range bs {
89 if err := ib.Buffer.WriteByte(b ^ 0xFF); err != nil {
90 return i, err
91 }
92 }
93 return len(bs), nil
94 }
95 return ib.Buffer.Write(bs)
96 }
97
98 func (ib *invertibleBuffer) WriteByte(b byte) error {
99 if ib.invert {
100 b = b ^ 0xFF
101 }
102 return ib.Buffer.WriteByte(b)
103 }
104
105 func (ib *invertibleBuffer) ReadByte() (byte, error) {
106 ret, err := ib.Buffer.ReadByte()
107 if ib.invert {
108 ret = ret ^ 0xFF
109 }
110 return ret, err
111 }
112
113 func (ib *invertibleBuffer) Invert() {
114 ib.invert = !ib.invert
115 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698