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