OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 //go:generate stringer -type=Toggle | 5 //go:generate stringer -type=Toggle |
6 | 6 |
7 package datastore | 7 package datastore |
8 | 8 |
9 // GeoPoint represents a location as latitude/longitude in degrees. | 9 // GeoPoint represents a location as latitude/longitude in degrees. |
10 // | 10 // |
(...skipping 29 matching lines...) Expand all Loading... |
40 // Toggle is a tri-state boolean (Auto/True/False), which allows structs | 40 // Toggle is a tri-state boolean (Auto/True/False), which allows structs |
41 // to control boolean flags for metadata in a non-ambiguous way. | 41 // to control boolean flags for metadata in a non-ambiguous way. |
42 type Toggle byte | 42 type Toggle byte |
43 | 43 |
44 // These are the allowed values for Toggle. Any other values are invalid. | 44 // These are the allowed values for Toggle. Any other values are invalid. |
45 const ( | 45 const ( |
46 Auto Toggle = iota | 46 Auto Toggle = iota |
47 On | 47 On |
48 Off | 48 Off |
49 ) | 49 ) |
| 50 |
| 51 // BoolList is a convenience wrapper for []bool that provides summary methods |
| 52 // for working with the list in aggregate. |
| 53 type BoolList []bool |
| 54 |
| 55 // All returns true iff all of the booleans in this list are true. |
| 56 func (bl BoolList) All() bool { |
| 57 for _, b := range bl { |
| 58 if !b { |
| 59 return false |
| 60 } |
| 61 } |
| 62 return true |
| 63 } |
| 64 |
| 65 // Any returns true iff any of the booleans in this list are true. |
| 66 func (bl BoolList) Any() bool { |
| 67 for _, b := range bl { |
| 68 if b { |
| 69 return true |
| 70 } |
| 71 } |
| 72 return false |
| 73 } |
| 74 |
| 75 // ExistsResult is a 2-dimensional boolean array that represents the existence |
| 76 // of entries in the datastore. It is returned by the datastore Exists method. |
| 77 // It is designed to accommodate the potentially-nested variadic arguments that |
| 78 // can be passed to Exists. |
| 79 // |
| 80 // The first dimension contains one entry for each Exists input index. If the |
| 81 // argument is a single entry, the boolean value at this index will be true if |
| 82 // that argument was present in the datastore and false otherwise. If the |
| 83 // argument is a slice, it will contain an aggregate value that is true iff no |
| 84 // values in that slice were missing from the datastore. |
| 85 // |
| 86 // The second dimension presents a boolean slice for each input argument. Single |
| 87 // arguments will have a slice of size 1 whose value corresponds to the first |
| 88 // dimension value for that argument. Slice arguments have a slice of the same |
| 89 // size. A given index in the second dimension slice is true iff the element at |
| 90 // that index was present. |
| 91 type ExistsResult struct { |
| 92 // values is the first dimension aggregate values. |
| 93 values BoolList |
| 94 // slices is the set of second dimension positional values. |
| 95 slices []BoolList |
| 96 } |
| 97 |
| 98 func (r *ExistsResult) init(sizes ...int) { |
| 99 // In order to reduce allocations, we allocate a single continuous boole
an |
| 100 // slice and then partition it up into first- and second-dimension slice
s. |
| 101 // |
| 102 // To determine the size of the continuous slize, count the number of el
ements |
| 103 // that we'll need: |
| 104 // - Single arguments and slice arguments with size 1 will have their |
| 105 // second-dimension slice just point to their element in the first-dim
ension |
| 106 // slice. |
| 107 // - Slice elements of size >1 will have their second-dimension slice ad
ded to |
| 108 // the end of the continuous slice. Their slice will be carved off in
the |
| 109 // subsequent loop. |
| 110 // |
| 111 // Consequently, we need one element for each argument, plus len(slice) |
| 112 // additional elements for each slice argument of size >1. |
| 113 count := len(sizes) // [0..n) |
| 114 for _, s := range sizes { |
| 115 if s > 1 { |
| 116 count += s |
| 117 } |
| 118 } |
| 119 |
| 120 // Allocate our continuous array and partition it into first- and |
| 121 // second-dimension slices. |
| 122 entries := make(BoolList, count) |
| 123 r.values, entries = entries[:len(sizes)], entries[len(sizes):] |
| 124 r.slices = make([]BoolList, len(sizes)) |
| 125 for i, s := range sizes { |
| 126 switch { |
| 127 case s <= 0: |
| 128 break |
| 129 |
| 130 case s == 1: |
| 131 // Single-entry slice out of "entries". |
| 132 r.slices[i] = r.values[i : i+1] |
| 133 |
| 134 default: |
| 135 r.slices[i], entries = entries[:s], entries[s:] |
| 136 } |
| 137 } |
| 138 } |
| 139 |
| 140 func (r *ExistsResult) set(i, j int) { r.slices[i][j] = true } |
| 141 |
| 142 // updateSlices updates the top-level value for multi-dimensional elements based |
| 143 // on their current values. |
| 144 func (r *ExistsResult) updateSlices() { |
| 145 for i, s := range r.slices { |
| 146 // Zero-length slices will have a first-dimension true value, si
nce they |
| 147 // have no entries and first-dimension is true when there are no
false |
| 148 // entries. |
| 149 r.values[i] = (len(s) == 0 || s.All()) |
| 150 } |
| 151 } |
| 152 |
| 153 // All returns true if all of the available boolean slots are true. |
| 154 func (r *ExistsResult) All() bool { return r.values.All() } |
| 155 |
| 156 // Any returns true if any of the boolean slots are true. |
| 157 func (r *ExistsResult) Any() bool { |
| 158 // We have to implement our own Any so zero-length slices don't count to
wards |
| 159 // our result. |
| 160 for i, b := range r.values { |
| 161 if b && len(r.slices[i]) > 0 { |
| 162 return true |
| 163 } |
| 164 } |
| 165 return false |
| 166 } |
| 167 |
| 168 // Get returns the boolean value at the specified index. |
| 169 // |
| 170 // The one-argument form returns the first-dimension boolean. If i is a slice |
| 171 // argument, this will be true iff all of the slice's booleans are true. |
| 172 // |
| 173 // An optional second argument can be passed to access a specific boolean value |
| 174 // in slice i. If the argument at i is a single argument, the only valid index, |
| 175 // 0, will be the same as calling the single-argument Get. |
| 176 // |
| 177 // Passing more than one additional argument will result in a panic. |
| 178 func (r *ExistsResult) Get(i int, j ...int) bool { |
| 179 switch len(j) { |
| 180 case 0: |
| 181 return r.values[i] |
| 182 case 1: |
| 183 return r.slices[i][j[0]] |
| 184 default: |
| 185 panic("this method takes one or two arguments") |
| 186 } |
| 187 } |
| 188 |
| 189 // List returns the BoolList for the given argument index. |
| 190 // |
| 191 // The zero-argument form returns the first-dimension boolean list. |
| 192 // |
| 193 // An optional argument can be passed to access a specific argument's boolean |
| 194 // slice. If the argument at i is a non-slice argument, the list will be a slice |
| 195 // of size 1 containing i's first-dimension value. |
| 196 // |
| 197 // Passing more than one argument will result in a panic. |
| 198 func (r *ExistsResult) List(i ...int) BoolList { |
| 199 switch len(i) { |
| 200 case 0: |
| 201 return r.values |
| 202 case 1: |
| 203 return r.slices[i[0]] |
| 204 default: |
| 205 panic("this method takes zero or one arguments") |
| 206 } |
| 207 } |
| 208 |
| 209 // Len returns the number of boolean results available. |
| 210 // |
| 211 // The zero-argument form returns the first-dimension size, which will equal the |
| 212 // total number of arguments passed to Exists. |
| 213 // |
| 214 // The one-argument form returns the number of booleans in the slice for |
| 215 // argument i. |
| 216 // |
| 217 // Passing more than one argument will result in a panic. |
| 218 func (r *ExistsResult) Len(i ...int) int { |
| 219 switch len(i) { |
| 220 case 0: |
| 221 return len(r.values) |
| 222 case 1: |
| 223 return len(r.slices[i[0]]) |
| 224 default: |
| 225 panic("this method takes zero or one arguments") |
| 226 } |
| 227 } |
OLD | NEW |