github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/dbnode/storage/repair/map_gen.go (about) 1 // Copyright (c) 2021 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 // This file was automatically generated by genny. 22 // Any changes will be lost if this file is regenerated. 23 // see https://github.com/mauricelam/genny 24 25 package repair 26 27 import ( 28 "github.com/m3db/m3/src/x/ident" 29 ) 30 31 // Copyright (c) 2021 Uber Technologies, Inc. 32 // 33 // Permission is hereby granted, free of charge, to any person obtaining a copy 34 // of this software and associated documentation files (the "Software"), to deal 35 // in the Software without restriction, including without limitation the rights 36 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 37 // copies of the Software, and to permit persons to whom the Software is 38 // furnished to do so, subject to the following conditions: 39 // 40 // The above copyright notice and this permission notice shall be included in 41 // all copies or substantial portions of the Software. 42 // 43 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 44 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 45 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 46 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 47 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 48 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 49 // THE SOFTWARE. 50 51 // This file was automatically generated by genny. 52 // Any changes will be lost if this file is regenerated. 53 // see https://github.com/mauricelam/genny 54 55 // Copyright (c) 2018 Uber Technologies, Inc. 56 // 57 // Permission is hereby granted, free of charge, to any person obtaining a copy 58 // of this software and associated documentation files (the "Software"), to deal 59 // in the Software without restriction, including without limitation the rights 60 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 61 // copies of the Software, and to permit persons to whom the Software is 62 // furnished to do so, subject to the following conditions: 63 // 64 // The above copyright notice and this permission notice shall be included in 65 // all copies or substantial portions of the Software. 66 // 67 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 68 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 69 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 70 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 71 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 72 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 73 // THE SOFTWARE. 74 75 // MapHash is the hash for a given map entry, this is public to support 76 // iterating over the map using a native Go for loop. 77 type MapHash uint64 78 79 // HashFn is the hash function to execute when hashing a key. 80 type HashFn func(ident.ID) MapHash 81 82 // EqualsFn is the equals key function to execute when detecting equality of a key. 83 type EqualsFn func(ident.ID, ident.ID) bool 84 85 // CopyFn is the copy key function to execute when copying the key. 86 type CopyFn func(ident.ID) ident.ID 87 88 // FinalizeFn is the finalize key function to execute when finished with a key. 89 type FinalizeFn func(ident.ID) 90 91 // Map uses the genny package to provide a generic hash map that can be specialized 92 // by running the following command from this root of the repository: 93 // ``` 94 // make hashmap-gen pkg=outpkg key_type=Type value_type=Type out_dir=/tmp 95 // ``` 96 // Or if you would like to use bytes or ident.ID as keys you can use the 97 // partially specialized maps to generate your own maps as well: 98 // ``` 99 // make byteshashmap-gen pkg=outpkg value_type=Type out_dir=/tmp 100 // make idhashmap-gen pkg=outpkg value_type=Type out_dir=/tmp 101 // ``` 102 // This will output to stdout the generated source file to use for your map. 103 // It uses linear probing by incrementing the number of the hash created when 104 // hashing the identifier if there is a collision. 105 // Map is a value type and not an interface to allow for less painful 106 // upgrades when adding/removing methods, it is not likely to need mocking so 107 // an interface would not be super useful either. 108 type Map struct { 109 mapOptions 110 111 // lookup uses hash of the identifier for the key and the MapEntry value 112 // wraps the value type and the key (used to ensure lookup is correct 113 // when dealing with collisions), we use uint64 for the hash partially 114 // because lookups of maps with uint64 keys has a fast path for Go. 115 lookup map[MapHash]MapEntry 116 } 117 118 // mapOptions is a set of options used when creating an identifier map, it is kept 119 // private so that implementers of the generated map can specify their own options 120 // that partially fulfill these options. 121 type mapOptions struct { 122 // hash is the hash function to execute when hashing a key. 123 hash HashFn 124 // equals is the equals key function to execute when detecting equality. 125 equals EqualsFn 126 // copy is the copy key function to execute when copying the key. 127 copy CopyFn 128 // finalize is the finalize key function to execute when finished with a 129 // key, this is optional to specify. 130 finalize FinalizeFn 131 // initialSize is the initial size for the map, use zero to use Go's std map 132 // initial size and consequently is optional to specify. 133 initialSize int 134 } 135 136 // MapEntry is an entry in the map, this is public to support iterating 137 // over the map using a native Go for loop. 138 type MapEntry struct { 139 // key is used to check equality on lookups to resolve collisions 140 key mapKey 141 // value type stored 142 value ReplicaSeriesBlocksMetadata 143 } 144 145 type mapKey struct { 146 key ident.ID 147 finalize bool 148 } 149 150 // Key returns the map entry key. 151 func (e MapEntry) Key() ident.ID { 152 return e.key.key 153 } 154 155 // Value returns the map entry value. 156 func (e MapEntry) Value() ReplicaSeriesBlocksMetadata { 157 return e.value 158 } 159 160 // mapAlloc is a non-exported function so that when generating the source code 161 // for the map you can supply a public constructor that sets the correct 162 // hash, equals, copy, finalize options without users of the map needing to 163 // implement them themselves. 164 func mapAlloc(opts mapOptions) *Map { 165 m := &Map{mapOptions: opts} 166 m.Reallocate() 167 return m 168 } 169 170 func (m *Map) newMapKey(k ident.ID, opts mapKeyOptions) mapKey { 171 key := mapKey{key: k, finalize: opts.finalizeKey} 172 if !opts.copyKey { 173 return key 174 } 175 176 key.key = m.copy(k) 177 return key 178 } 179 180 func (m *Map) removeMapKey(hash MapHash, key mapKey) { 181 delete(m.lookup, hash) 182 if key.finalize { 183 m.finalize(key.key) 184 } 185 } 186 187 // Get returns a value in the map for an identifier if found. 188 func (m *Map) Get(k ident.ID) (ReplicaSeriesBlocksMetadata, bool) { 189 hash := m.hash(k) 190 for entry, ok := m.lookup[hash]; ok; entry, ok = m.lookup[hash] { 191 if m.equals(entry.key.key, k) { 192 return entry.value, true 193 } 194 // Linear probe to "next" to this entry (really a rehash) 195 hash++ 196 } 197 var empty ReplicaSeriesBlocksMetadata 198 return empty, false 199 } 200 201 // Set will set the value for an identifier. 202 func (m *Map) Set(k ident.ID, v ReplicaSeriesBlocksMetadata) { 203 m.set(k, v, mapKeyOptions{ 204 copyKey: true, 205 finalizeKey: m.finalize != nil, 206 }) 207 } 208 209 // SetUnsafeOptions is a set of options to use when setting a value with 210 // the SetUnsafe method. 211 type SetUnsafeOptions struct { 212 NoCopyKey bool 213 NoFinalizeKey bool 214 } 215 216 // SetUnsafe will set the value for an identifier with unsafe options for how 217 // the map treats the key. 218 func (m *Map) SetUnsafe(k ident.ID, v ReplicaSeriesBlocksMetadata, opts SetUnsafeOptions) { 219 m.set(k, v, mapKeyOptions{ 220 copyKey: !opts.NoCopyKey, 221 finalizeKey: !opts.NoFinalizeKey, 222 }) 223 } 224 225 type mapKeyOptions struct { 226 copyKey bool 227 finalizeKey bool 228 } 229 230 func (m *Map) set(k ident.ID, v ReplicaSeriesBlocksMetadata, opts mapKeyOptions) { 231 hash := m.hash(k) 232 for entry, ok := m.lookup[hash]; ok; entry, ok = m.lookup[hash] { 233 if m.equals(entry.key.key, k) { 234 m.lookup[hash] = MapEntry{ 235 key: entry.key, 236 value: v, 237 } 238 return 239 } 240 // Linear probe to "next" to this entry (really a rehash) 241 hash++ 242 } 243 244 m.lookup[hash] = MapEntry{ 245 key: m.newMapKey(k, opts), 246 value: v, 247 } 248 } 249 250 // Iter provides the underlying map to allow for using a native Go for loop 251 // to iterate the map, however callers should only ever read and not write 252 // the map. 253 func (m *Map) Iter() map[MapHash]MapEntry { 254 return m.lookup 255 } 256 257 // Len returns the number of map entries in the map. 258 func (m *Map) Len() int { 259 return len(m.lookup) 260 } 261 262 // Contains returns true if value exists for key, false otherwise, it is 263 // shorthand for a call to Get that doesn't return the value. 264 func (m *Map) Contains(k ident.ID) bool { 265 _, ok := m.Get(k) 266 return ok 267 } 268 269 // Delete will remove a value set in the map for the specified key. 270 func (m *Map) Delete(k ident.ID) { 271 hash := m.hash(k) 272 for entry, ok := m.lookup[hash]; ok; entry, ok = m.lookup[hash] { 273 if m.equals(entry.key.key, k) { 274 m.removeMapKey(hash, entry.key) 275 return 276 } 277 // Linear probe to "next" to this entry (really a rehash) 278 hash++ 279 } 280 } 281 282 // Reset will reset the map by simply deleting all keys to avoid 283 // allocating a new map. 284 func (m *Map) Reset() { 285 for hash, entry := range m.lookup { 286 m.removeMapKey(hash, entry.key) 287 } 288 } 289 290 // Reallocate will avoid deleting all keys and reallocate a new 291 // map, this is useful if you believe you have a large map and 292 // will not need to grow back to a similar size. 293 func (m *Map) Reallocate() { 294 if m.initialSize > 0 { 295 m.lookup = make(map[MapHash]MapEntry, m.initialSize) 296 } else { 297 m.lookup = make(map[MapHash]MapEntry) 298 } 299 }