| Index: service/rawdatastore/invertible.go
|
| diff --git a/service/rawdatastore/invertible.go b/service/rawdatastore/invertible.go
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..c8b40b148596aeb8c4ed6d5667cc56a525401a79
|
| --- /dev/null
|
| +++ b/service/rawdatastore/invertible.go
|
| @@ -0,0 +1,115 @@
|
| +// Copyright 2015 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +package rawdatastore
|
| +
|
| +import (
|
| + "bytes"
|
| +)
|
| +
|
| +// Buffer is the interface which corresponds to the subset of *bytes.Buffer
|
| +// that this package requires.
|
| +type Buffer interface {
|
| + String() string
|
| + Grow(int)
|
| +
|
| + Read([]byte) (int, error)
|
| + ReadByte() (byte, error)
|
| +
|
| + Write([]byte) (int, error)
|
| + WriteByte(c byte) error
|
| + WriteString(s string) (int, error)
|
| +}
|
| +
|
| +var _ Buffer = (*bytes.Buffer)(nil)
|
| +
|
| +// InvertibleBuffer is just like Buffer, except that it also has a stateful
|
| +// Invert() method, which will cause all reads and writes to/from it to be
|
| +// inverted (e.g. every byte XOR 0xFF).
|
| +//
|
| +// Implementing queries requires manipulating the index entries (e.g.
|
| +// synthesizing them, parsing them, etc.). In particular, when you have
|
| +// a reverse-sorted field (e.g. high to low instead of low to high), it's
|
| +// achieved by having all the bits inverted.
|
| +//
|
| +// All the serialization formats include delimiter information, which the
|
| +// parsers only know to parse non-inverted. If we don't have this buffer, we'd
|
| +// basically have to invert every byte in the []byte array when we're trying to
|
| +// decode a reverse-ordered field (including the bytes of all fields after the
|
| +// one we intend to parse) so that the parser can consume as many bytes as it
|
| +// needs (and it only knows the number of bytes it needs as it decodes them).
|
| +// This InvertibleBuffer lets that happen on the fly without having to flip the
|
| +// whole []byte.
|
| +//
|
| +// If you know you need it, you'll know it's the right thing. If you're not sure
|
| +// then you definitely don't need it!
|
| +type InvertibleBuffer interface {
|
| + Buffer
|
| + Invert()
|
| +}
|
| +
|
| +type invertibleBuffer struct {
|
| + Buffer
|
| + invert bool
|
| +}
|
| +
|
| +// Invertible returns an InvertibleBuffer based on the Buffer.
|
| +func Invertible(b Buffer) InvertibleBuffer {
|
| + return &invertibleBuffer{b, false}
|
| +}
|
| +
|
| +func (ib *invertibleBuffer) Read(bs []byte) (int, error) {
|
| + n, err := ib.Buffer.Read(bs)
|
| + if ib.invert {
|
| + for i, b := range bs {
|
| + bs[i] = b ^ 0xFF
|
| + }
|
| + }
|
| + return n, err
|
| +}
|
| +
|
| +func (ib *invertibleBuffer) WriteString(s string) (int, error) {
|
| + if ib.invert {
|
| + ib.Grow(len(s))
|
| + for i := 0; i < len(s); i++ {
|
| + if err := ib.Buffer.WriteByte(s[i] ^ 0xFF); err != nil {
|
| + return i, err
|
| + }
|
| + }
|
| + return len(s), nil
|
| + }
|
| + return ib.Buffer.WriteString(s)
|
| +}
|
| +
|
| +func (ib *invertibleBuffer) Write(bs []byte) (int, error) {
|
| + if ib.invert {
|
| + ib.Grow(len(bs))
|
| + for i, b := range bs {
|
| + if err := ib.Buffer.WriteByte(b ^ 0xFF); err != nil {
|
| + return i, err
|
| + }
|
| + }
|
| + return len(bs), nil
|
| + }
|
| + return ib.Buffer.Write(bs)
|
| +}
|
| +
|
| +func (ib *invertibleBuffer) WriteByte(b byte) error {
|
| + if ib.invert {
|
| + b = b ^ 0xFF
|
| + }
|
| + return ib.Buffer.WriteByte(b)
|
| +}
|
| +
|
| +func (ib *invertibleBuffer) ReadByte() (byte, error) {
|
| + ret, err := ib.Buffer.ReadByte()
|
| + if ib.invert {
|
| + ret = ret ^ 0xFF
|
| + }
|
| + return ret, err
|
| +}
|
| +
|
| +func (ib *invertibleBuffer) Invert() {
|
| + ib.invert = !ib.invert
|
| +}
|
|
|