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 | |
iannucci
2016/05/28 02:50:53
bitfield?
dnj
2016/05/28 17:47:21
IMO BoolList is more Go-friendly, since it actuall
| |
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 |