cm

package module
v0.9.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 13, 2024 License: MIT Imports: 2 Imported by: 0

README

Complex Generic Maps for Go

Go Referencegopherbadger-tag-do-not-edit

go get github.com/thejerf/cm

import "github.com/thejerf/cm"

cm provides some generic complex maps for Go;

  • The equivalent of map[A]map[B]C and map[A]map[B]map[C]D, in two flavors:

    • MapMap and MapMapMap implement that, with the constraint that the value type is comparable. This allows the equvialent of the maps' package .Equal method.
    • MapMapAny and MapMapMapAny are the same, but allowing the Value type to be any. This removes the .Equal method but allows storing any value.
  • DualMap implements a map that can be keyed by either of two keys, packaging up a map[A]map[B]C and map[B]map[A]C into a single coherent package.

  • MapSet implements a map that contains sets, like map[K]Set[V].

  • To support MapSet, there's a full Set implementation.

    As I write this, there's a proposal for a standard-library Set type on github. It has stalled out on lacking iterator support. This Set sidesteps that by simply accepting that it is based on a map type, thus permitting a standard range iteration. While a custom Set type may theoretically permit higher performance for large sets, and it does make sense for the standard library to consider such a case, this set type will be acceptable for quite significantly sized sets.

    This set is also biased in the direction of mutability and performance. So, for instance, .Subtract will modify the Set it is called on. I chose this because if you have a mutation-based library, but want to create a new set, it is easy to set.Clone().Subtract(set2), but if you have a library that only works by creating new values you can't get the higher performance of direct mutation. And in my experience, direct mutation is a frequently common case, as is cloning a set once and performing many mutation operations on it (like subtracting several sets).

  • To support this library there is also a Tuple2 and Tuple3 type. While these may not be 'full featured' tuples, I have found a use for them in table-based tests to avoid declaring

    type SomeTestType struct {
         In  Type1
         Out Type2
    }
    

    If you're using this library anyhow, there's no harm in using them.

There's nothing particularly "special" about this implementation, no magic sauce or anything. Just code I've had to write in several projects and would like to get factored out and into a well-tested library, rather than write over and over.

Go Versions

0.9.0 and beyond require Go 1.23 for the iterator support.

0.8.0 can be used for Go verions after 1.18, for generic support. (If you need a 0.8.1 to fix the missing ValueSlice on MapMap(Map)?, let me know.)

Performance

All of these methods are extremely strong candidates for inlining. Some brief checks with -gcflags="-m" on some test programs suggest that they are indeed all inlined. Consequently, this library should generally be zero-performance-impact versus having directly written the code. (There are a few places where nil is checked for where you might not have, but a highly-predictable branch should be lost in the noise compared to what even one map lookup requires.)

Future Plans

If the standard library implements a .Set, I am not sure if I will switch to it. It depends on the details. I am tempted just to 1.0 this package as-is, and then roll out a v2 with the built-in set if there's a compelling reason.

Status

I am using this a lot in my own code. With the release of rangefunc, I consider this a 1.0 candidate.

PRs

I am actively accepting PRs. If this almost does what you want, please by all means file a PR to add it rather than starting a new project.

However, I'm aiming for a library that does not replace things we already have built-ins or implementations in the to-be-standard maps package. Especially when implementations would be wildly slower than native support.

Users of this library are expected to understand this library as helpful methods that work on the relevant data types, not as a complete replacement data type for maps.

Code Signing

All commits and releases will be signed with a GPG key, as verified by GitHub. It is the "jerf" keybase account key.

(Bear in mind that due to the nature of how git commit signing works, there may be runs of unverified commits. What matters is that the top one is signed.)

Changelog

cm uses semantic versioning.

At the moment, this is in pre-release, which means no guarantees whatsoever about backwards compatibility. Change is still happening frequently as I hone in on the best solutions.

  • 0.9.0:
    • BACKWARDS INCOMPATIBLE CHANGE: Values is renamed to ValueSlice, to allow Values to be used for iterators.
    • rangefunc support is added to the data structures, allowing efficient iteration without having to construct full slices. This adds:
      • MapMap[Any] gets All() for key/value, and Keys and Values for their respective contents.

      • Set gets SetFromIter to construct a set from an iter.Seq.

      • MapSet gets a Values iterator for all values.

        Note that a Keys iterator is already de facto available by ranging on the MapSet itself.

    • Added ValueSlice to MapMap, which was missing it.
  • 0.8.0:
    • This is the last version that works back to 1.18. Future versions require 1.23 for rangefunc support. (I am not inclined to maintain multiple versions of this library in perpetuity.)
    • Add a Len method to the various maps that require a loop to compute them.
  • 0.7.0:
    • Add AddByTuple to MapSet, as I encountered code where that was useful.
    • Add Intersect to Set.
  • 0.6.0:
    • Add a Values method to MapMap, MapMapAny, MapMapMap, and MapMapMapAny.
  • 0.5.0:
    • Trimmed off the .Get functions from the MapMap and MapMapMap as they are unnecessary.
    • NewDualMap is removed because it doesn't matter; the first Set will initialize the values and there is no reason to need them to be initialized before that.
    • DualMap's two maps are now called Primary and Reverse, which will probably be easier to remember than Left and Right.
  • 0.4.0:
    • Removed MapSlice because upon an even more careful review of the behavior of nil slices, it adds nothing. The .Append method I wrote can also just be written as m[key] = append(m[key], vals...) without loss. The remaining .Set method that removes the key entirely for empty slices doesn't justify a full datatype.
  • 0.3.0:
    • Worked out a way to recover the .Equal method without a lot of nasty casting on values.
  • 0.2.0:
    • Renamed almost everything to something shorter, but also more comprehensible, I hope.
    • Additional data types:
      • Set
      • MapSet
      • MapSlice
  • 0.1: Initial release to GitHub. This release has not been publicized as it is still missing a couple of key methods:
    • Methods for getting values.
    • Methods for getting full key/value tuples.
    • KeyTree2 may need some renaming; it works in the context of a MultiLevelMap2 but when recursively used by the MultiLevelMap3 the struct names are a bit off.

Documentation

Overview

Package cm contains generic "complicated maps": multi-level maps, dual-key maps, and maps containing sets.

This package provides no locking in the datastructures. All locking is the responsibility of code using these maps.

This code panics analogously to normal map behaviors. When there is no existing map behavior to guide, it tries to match the same logic Go normally uses. This is justified because these are just wrappers around maps, rather than independent data structures. Most or all of the places where this library panics is places where the code was going to panic anyhow; the panic calls in the code simply offer more direct guidance on the problem rather than panicking deep in library code.

Similarly, none of these data structures are thread-safe on their own, just like conventional Go maps.

Multilevel Maps

Multi-level maps are maps that have other maps as their values. This provides convenience functions for interacting with multi-level maps. It is intended to work harmoniously with golang.org/x/maps, and tries not to replicate any functionality already found there. For instance, to get the first level of keys of these maps, simply pass them as normal maps to maps.Keys. The internal maps are exported so normal map operations work, so redundant operations already provided by range and such are not implemented.

It is safe to write to these maps directly, no constraints maintained by this code will be violated. The delete methods provided by the multi-level maps will also clean up any higher-level maps left emptied by a delete. Directly executing deletes on the lower-level maps yourself will not automatically clean these maps up, which may also cause spurious keys to appear in the KeySlice method. Otherwise it is safe too.

In theory, you can drop this into any existing multilevel map you already have, and they should continue to work, give or take any type conversions as you pass them around. You just also have the additional methods added by this type.

Unlike single level maps where a sequence of the key values is the only sensible representation of the keys, multi-level maps have more than one useful representation. You can either look at the set of keys as a set of tuples for all levels, or you can look at them as a tree. Each representation has its costs and benefits, so this package provides both.

As multilevel maps are just Go maps under the hood, they scale the same as Go maps do in general.

Dual Keyed Maps

A dual-keyed map is a map that allows you to lookup values by either of the two keys. Under the hood, it is simply both possible maps, and functions for setting and deleting by both keys.

For your convenience, the two maps are left exported so you can efficiently read from them. Writing directly to them will violate the guarantees provided by this implementation and should generally not be done.

Values are stored as given in both maps. This means that a dual-keyed map consumes twice the resources of a normal map. This is targeted for cases where a dual-key map is very convenient, but not large by modern standards. As you scale up needs like this you eventually need a database.

Because this simply stores the maps in both directions, you may want to double-check before using pointer types for either type. It is legal in Go to use pointers to key maps, but it may not have the desired or expected result, as it will result in one of the two directions keying off of object identity rather than value. This has its uses too, though.

For dual-key maps, it is obvious how to store them, with a reasonable penalty. As you get into needs for three or more keys, the cost of this technique multiplies resource consumption by the number of permutations of the keys, which by three keys is already six times a single map. So this package stops at dual-level maps.

Map Sets

A MapSet is a map, whose value is a set. Several convenience functions can be implemented for manipulating such values.

As a consequence of offering this functionality, this package also provides a Set implementation.

Key Trees And Key Slices

Each of these structures implements the ability to get data structures representing the set of all keys, or keys and values in the set, as a single static data structure.

It is an anti-pattern to use them as such:

keySlice := someMapMap.KeySlice()
for _, keys := range keySlice {
    // ...
}

This causes the needless instantiation of a data structure in memory. This should be written as

for key1, submap := range someMapMap {
    for key2, val := range submap {
        // do work here
    }
}

Normal use of KeySlice and KeyTree would be sorting it somehow before iterating, or possibly serializing them somewhere.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type DualMap

type DualMap[P, S comparable, V any] struct {
	Primary MapMapAny[P, S, V]
	Reverse MapMapAny[S, P, V]
}

A DualMap is a map that will store values in a way that allows you to access them by either key. For any key tuple (K1, K2), you can get the set of all values by either K1 or K2. This contrasts with a standard multilevel map, which provides no querying capability with just the second level of a key (other than scanning the whole thing).

Note that both components of the DualMap are MapMapAnys, so all methods available on those are available here as well, such as the iteration methods.

The full key (P, S) must be unique, but there can be any number of "primaries" associated with a given "secondary key" and vice versa.

I have found it convenient to remember the map as having one of the particular types as "primary", so this map refers to the "Primary" mapping and the "Reverse" mapping. This helps keep straight which keys are which, even in situations where you have no particular preference. If you have no preference, it doesn't actually matter; DualMap entire point is to be fully symmetric on the types.

The zero-value of this struct is safe to use. When Set is first used, the maps will be initialized.

Direct read access is permissible. You should not directly write to the maps. DualMap makes no guarantees if you directly write to the internal maps.

func (*DualMap[P, S, V]) Delete

func (dm *DualMap[P, S, V]) Delete(l P, r S)

Delete deletes by the keys in primary/secondary order.

func (*DualMap[P, S, V]) DeleteByTuple

func (dm *DualMap[P, S, V]) DeleteByTuple(key Tuple2[P, S])

Delete deletes by the tuple returned by the Primary's KeySlice method.

func (*DualMap[P, S, V]) GetByTuple

func (dm *DualMap[P, S, V]) GetByTuple(key Tuple2[P, S]) (val V, exists bool)

GetByTuple retrieves by the tuple returned by the Primary's KeySlice method.

func (*DualMap[P, S, V]) Set

func (dm *DualMap[P, S, V]) Set(
	l P,
	r S,
	value V,
)

Set sets the given value with the keys in primary/secondary order.

func (*DualMap[P, S, V]) SetByTuple

func (dm *DualMap[P, S, V]) SetByTuple(
	key Tuple2[P, S],
	value V,
)

SetByTuple sets by the tuple returned by the Primary's KeySlice method.

type KeyTree

type KeyTree[K1, V any] struct {
	Key  K1
	Vals []V
}

KeyTree is a data type that can represent the keys of a map via a tree sort of structure.

type MapMap

type MapMap[K1, K2, V comparable] MapMapAny[K1, K2, V]

MapMap is a map of maps that has a comparable Value type, which allows for the .Equal method.

AnyMapMap lacks this restriction, and has all the methods MapMap has except .Equal.

func (MapMap[K1, K2, V]) All added in v0.9.0

func (mm MapMap[K1, K2, V]) All() iter.Seq2[Tuple2[K1, K2], V]

All will return an iterator over the map that yields the keys as a Tuple2, and the value in the value slot.

func (MapMap[K1, K2, V]) Clone

func (mm MapMap[K1, K2, V]) Clone() MapMap[K1, K2, V]

Clone returns a copy of the MapMap struture, with the keys copied over. It's a shallow copy of the full MapMap.

func (MapMap[K1, K2, V]) Delete

func (mm MapMap[K1, K2, V]) Delete(key1 K1, key2 K2)

Delete deletes the value from the map.

func (MapMap[K1, K2, V]) DeleteByTuple

func (mm MapMap[K1, K2, V]) DeleteByTuple(key Tuple2[K1, K2])

DeleteByKey deletes by the tuple version of the key.

func (MapMap[K1, K2, V]) DeleteFunc

func (mm MapMap[K1, K2, V]) DeleteFunc(f func(K1, K2, V) bool)

DeleteFunc deletes from the map the values for which the function returns true. If all values from a submap are deleted, the submap will be deleted from the MapMap.

func (MapMap[K1, K2, V]) Equal added in v0.3.0

func (mm MapMap[K1, K2, V]) Equal(r MapMap[K1, K2, V]) bool

Equal returns if this MapMap is equal to the passed-in MapMap.

Two zero-sized maps are considered equal to each other, even if one is nil and the other is not. This matches the current behavior of maps.Equal. If that changes before release, this will change to match it.

func (MapMap[K1, K2, V]) EqualFunc

func (mm MapMap[K1, K2, V]) EqualFunc(
	r MapMap[K1, K2, V],
	eq func(v1, v2 V) bool,
) bool

EqualFunc reimplements maps.EqualFunc on the MapMap.

func (MapMap[K1, K2, V]) GetByTuple

func (mm MapMap[K1, K2, V]) GetByTuple(key Tuple2[K1, K2]) (val V, exists bool)

GetByTuple retreives by the given tuple. The second value is true if the key exists, false otherwise.

GetByTuple called on a nil MapMap will not panic, and return that the value was not found.

func (MapMap[K1, K2, V]) KeySlice

func (mm MapMap[K1, K2, V]) KeySlice() []Tuple2[K1, K2]

KeySlice returns the keys of the MapMap as a slice of Tuple2 values.

A nil map will return a nil slice.

func (MapMap[K1, K2, V]) KeyTree

func (mm MapMap[K1, K2, V]) KeyTree() []KeyTree[K1, K2]

KeyTree returns the keys of the MapMap as a 2-level tree of the various keys.

A nil map will return a nil slice.

func (MapMap[K1, K2, V]) Keys added in v0.9.0

func (mm MapMap[K1, K2, V]) Keys() iter.Seq[Tuple2[K1, K2]]

Keys returns an iterator on the keys as a Tuple2.

func (MapMap[K1, K2, V]) Len added in v0.8.0

func (mm MapMap[K1, K2, V]) Len() int

Len returns the total number of values in the MapMap.

func (MapMap[K1, K2, V]) Set

func (mm MapMap[K1, K2, V]) Set(key1 K1, key2 K2, value V)

Set will set the given value with the given keys.

This will panic if called on a nil map.

func (MapMap[K1, K2, V]) SetByTuple

func (mm MapMap[K1, K2, V]) SetByTuple(key Tuple2[K1, K2], value V)

SetByTuple sets by the key tuple.

func (MapMap[K1, K2, V]) ValueSlice added in v0.9.0

func (mm MapMap[K1, K2, V]) ValueSlice() []V

ValueSlice returns a slice containing all values for this MapMap in a nondeterministic order.

This is marginally more efficient than converting the iterator into a slice as this counts up and pre-allocates the correct size in advance.

func (MapMap[K1, K2, V]) Values added in v0.9.0

func (mm MapMap[K1, K2, V]) Values() iter.Seq[V]

Values returns an iterator for all values in this MapMap in a nondeterministic order.

type MapMapAny added in v0.3.0

type MapMapAny[K1, K2 comparable, V any] map[K1]map[K2]V

MapMapAny is a 2-level MapMap, with two key types and a value type.

func (MapMapAny[K1, K2, V]) All added in v0.9.0

func (mma MapMapAny[K1, K2, V]) All() iter.Seq2[Tuple2[K1, K2], V]

All will return an iterator over the map that yields the keys as a Tuple2, and the value in the value slot.

func (MapMapAny[K1, K2, V]) Clone added in v0.3.0

func (mma MapMapAny[K1, K2, V]) Clone() MapMapAny[K1, K2, V]

Clone returns a copy of the MapMap struture, with the keys copied over. It's a shallow copy of the full MapMap.

func (MapMapAny[K1, K2, V]) Delete added in v0.3.0

func (mma MapMapAny[K1, K2, V]) Delete(
	key1 K1,
	key2 K2,
)

Delete deletes the value from the map.

func (MapMapAny[K1, K2, V]) DeleteByTuple added in v0.3.0

func (mma MapMapAny[K1, K2, V]) DeleteByTuple(key Tuple2[K1, K2])

DeleteByKey deletes by the tuple version of the key.

func (MapMapAny[K1, K2, V]) DeleteFunc added in v0.3.0

func (mma MapMapAny[K1, K2, V]) DeleteFunc(f func(K1, K2, V) bool)

DeleteFunc deletes from the map the values for which the function returns true. If all values from a submap are deleted, the submap will be deleted from the MapMap.

func (MapMapAny[K1, K2, V]) EqualFunc added in v0.3.0

func (mma MapMapAny[K1, K2, V]) EqualFunc(
	r MapMapAny[K1, K2, V],
	eq func(v1, v2 V) bool,
) bool

EqualFunc reimplements maps.EqualFunc on the MapMap.

func (MapMapAny[K1, K2, V]) GetByTuple added in v0.3.0

func (mma MapMapAny[K1, K2, V]) GetByTuple(key Tuple2[K1, K2]) (val V, exists bool)

GetByTuple retreives by the given tuple. The second value is true if the key exists, false otherwise.

GetByTuple called on a nil MapMap will not panic, and return that the value was not found.

func (MapMapAny[K1, K2, V]) KeySlice added in v0.3.0

func (mma MapMapAny[K1, K2, V]) KeySlice() []Tuple2[K1, K2]

KeySlice returns the keys of the MapMap as a slice of Tuple2 values.

A nil map will return a nil slice.

func (MapMapAny[K1, K2, V]) KeyTree added in v0.3.0

func (mma MapMapAny[K1, K2, V]) KeyTree() []KeyTree[K1, K2]

KeyTree returns the keys of the MapMap as a 2-level tree of the various keys.

A nil map will return a nil slice.

func (MapMapAny[K1, K2, V]) Keys added in v0.9.0

func (mma MapMapAny[K1, K2, V]) Keys() iter.Seq[Tuple2[K1, K2]]

Keys returns an iterator on the keys as a Tuple2.

func (MapMapAny[K1, K2, V]) Len added in v0.8.0

func (mma MapMapAny[K1, K2, V]) Len() int

Len returns the total number of values in the MapMap.

func (MapMapAny[K1, K2, V]) Set added in v0.3.0

func (mma MapMapAny[K1, K2, V]) Set(
	key1 K1,
	key2 K2,
	value V,
)

Set will set the given value with the given keys.

This will panic if called on a nil map.

func (MapMapAny[K1, K2, V]) SetByTuple added in v0.3.0

func (mma MapMapAny[K1, K2, V]) SetByTuple(
	key Tuple2[K1, K2],
	value V,
)

SetByTuple sets by the key tuple.

func (MapMapAny[K1, K2, V]) ValueSlice added in v0.9.0

func (mma MapMapAny[K1, K2, V]) ValueSlice() []V

ValueSlice returns a slice containing all values for this MapMap in a nondeterministic order.

This is marginally more efficient than converting the iterator into a slice as this counts up and pre-allocates the correct size in advance.

func (MapMapAny[K1, K2, V]) Values added in v0.6.0

func (mma MapMapAny[K1, K2, V]) Values() iter.Seq[V]

Values returns an iterator for all values in this MapMap in a nondeterministic order.

type MapMapMap

type MapMapMap[K1, K2, K3, V comparable] MapMapMapAny[K1, K2, K3, V]

MapMapMap is a map of map of maps that has a comparable Value type, which allows for the .Equal method.

MapMapMapAny lacks this restriction, and has all the methods MapMapMap has except .Equal.

func (MapMapMap[K1, K2, K3, V]) All added in v0.9.0

func (mmm MapMapMap[K1, K2, K3, V]) All() iter.Seq2[Tuple3[K1, K2, K3], V]

All returns the keys of the multimap as a Tuple3 values, and the values of the map in the value slot.

func (MapMapMap[K1, K2, K3, V]) Clone

func (mmm MapMapMap[K1, K2, K3, V]) Clone() MapMapMap[K1, K2, K3, V]

Clone yields a shallow copy of the MapMapMap, with the values simply copied across.

func (MapMapMap[K1, K2, K3, V]) Delete

func (mmm MapMapMap[K1, K2, K3, V]) Delete(key1 K1, key2 K2, key3 K3)

Delete deletes the value from the map.

func (MapMapMap[K1, K2, K3, V]) DeleteByTuple

func (mmm MapMapMap[K1, K2, K3, V]) DeleteByTuple(key Tuple3[K1, K2, K3])

DeleteByKey deletes by the tuple version of the key.

func (MapMapMap[K1, K2, K3, V]) DeleteFunc

func (mmm MapMapMap[K1, K2, K3, V]) DeleteFunc(f func(K1, K2, K3, V) bool)

DeleteFunc deletes from the map the values for which the function returns true. If all values from a submap are deleted, the submap will be deleted from the MapMap.

func (MapMapMap[K1, K2, K3, V]) Equal added in v0.3.0

func (mmm MapMapMap[K1, K2, K3, V]) Equal(r MapMapMap[K1, K2, K3, V]) bool

Equal returns if this MapMapMap is equal to the passed-in MapMapMap.

Two zero-sized maps are considered equal to each other, even if one is nil and the other is not. This matches the current behavior of maps.Equal. If that changes before release, this will change to match it.

func (MapMapMap[K1, K2, K3, V]) EqualFunc

func (mmm MapMapMap[K1, K2, K3, V]) EqualFunc(
	r MapMapMap[K1, K2, K3, V],
	eq func(v1, v2 V) bool,
) bool

EqualFunc reimplements maps.EqualFunc on the MapMap.

func (MapMapMap[K1, K2, K3, V]) GetByTuple

func (mmm MapMapMap[K1, K2, K3, V]) GetByTuple(key Tuple3[K1, K2, K3]) (val V, exists bool)

GetByTuple retreives by the given tuple. The second value is true if the key exists, false otherwise.

GetByTuple called on a nil MapMap will not panic, and return that the value was not found.

func (MapMapMap[K1, K2, K3, V]) KeySlice

func (mmm MapMapMap[K1, K2, K3, V]) KeySlice() []Tuple3[K1, K2, K3]

KeySlice returns the keys of the mulitmap as a slice of Tuple2 values.

A nil map will return a nil slice.

func (MapMapMap[K1, K2, K3, V]) KeyTree

func (mmm MapMapMap[K1, K2, K3, V]) KeyTree() []KeyTree[K1, KeyTree[K2, K3]]

KeyTree returns the keys of the multimap as a 2-level tree of the various keys.

A nil map will return a nil slice.

func (MapMapMap[K1, K2, K3, V]) Keys added in v0.9.0

func (mmm MapMapMap[K1, K2, K3, V]) Keys() iter.Seq[Tuple3[K1, K2, K3]]

Keys returns th ekeys of the MapMapMap as an iterator of Tuple3s.

func (MapMapMap[K1, K2, K3, V]) Len added in v0.8.0

func (mmm MapMapMap[K1, K2, K3, V]) Len() int

Len returns the number of values in the MapMapMap.

func (MapMapMap[K1, K2, K3, V]) Set

func (mmm MapMapMap[K1, K2, K3, V]) Set(key1 K1, key2 K2, key3 K3, value V)

Set will set the given value with the given keys.

This will panic if called on a nil map.

func (MapMapMap[K1, K2, K3, V]) SetByTuple

func (mmm MapMapMap[K1, K2, K3, V]) SetByTuple(key Tuple3[K1, K2, K3], value V)

SetByTuple sets by the key tuple.

func (MapMapMap[K1, K2, K3, V]) ValueSlice added in v0.9.0

func (mmm MapMapMap[K1, K2, K3, V]) ValueSlice() []V

ValueSlice returns a slice containing all the values for this MapMapMap in a nondeterministic order.

func (MapMapMap[K1, K2, K3, V]) Values added in v0.9.0

func (mmm MapMapMap[K1, K2, K3, V]) Values() iter.Seq[V]

Values return an iterator for the values in nondeterministic order.

type MapMapMapAny added in v0.3.0

type MapMapMapAny[K1, K2, K3 comparable, V any] map[K1]MapMapAny[K2, K3, V]

MapMapMapAny is a three-level map that can contain any value.

func (MapMapMapAny[K1, K2, K3, V]) All added in v0.9.0

func (mmma MapMapMapAny[K1, K2, K3, V]) All() iter.Seq2[Tuple3[K1, K2, K3], V]

All returns the keys of the multimap as a Tuple3 values, and the values of the map in the value slot.

func (MapMapMapAny[K1, K2, K3, V]) Clone added in v0.3.0

func (mmma MapMapMapAny[K1, K2, K3, V]) Clone() MapMapMapAny[K1, K2, K3, V]

Clone yields a shallow copy of the MapMapMapAny, with the values simply copied across.

func (MapMapMapAny[K1, K2, K3, V]) Delete added in v0.3.0

func (mmma MapMapMapAny[K1, K2, K3, V]) Delete(
	key1 K1,
	key2 K2,
	key3 K3,
)

Delete deletes the value from the map.

func (MapMapMapAny[K1, K2, K3, V]) DeleteByTuple added in v0.3.0

func (mmma MapMapMapAny[K1, K2, K3, V]) DeleteByTuple(key Tuple3[K1, K2, K3])

DeleteByKey deletes by the tuple version of the key.

func (MapMapMapAny[K1, K2, K3, V]) DeleteFunc added in v0.3.0

func (mmma MapMapMapAny[K1, K2, K3, V]) DeleteFunc(f func(K1, K2, K3, V) bool)

DeleteFunc deletes from the map the values for which the function returns true. If all values from a submap are deleted, the submap will be deleted from the MapMapMap.

func (MapMapMapAny[K1, K2, K3, V]) EqualFunc added in v0.3.0

func (mmma MapMapMapAny[K1, K2, K3, V]) EqualFunc(
	r MapMapMapAny[K1, K2, K3, V],
	eq func(v1, v2 V) bool,
) bool

EqualFunc returns if this MapMapMap is equal to the passed-in MapMapMap, using the passed-in function to compare the equality of values, re-implementing maps.EqualFunc on a MapMapMap.

func (MapMapMapAny[K1, K2, K3, V]) GetByTuple added in v0.3.0

func (mmma MapMapMapAny[K1, K2, K3, V]) GetByTuple(key Tuple3[K1, K2, K3]) (val V, exists bool)

GetByTuple is a convenience function to retrieve the value out of the map by the key tuple returned by KeySlice. Normal usage should just index into the map like mmm[key1][key2][key3].

func (MapMapMapAny[K1, K2, K3, V]) KeySlice added in v0.3.0

func (mmma MapMapMapAny[K1, K2, K3, V]) KeySlice() []Tuple3[K1, K2, K3]

KeySlice returns the keys of the mulitmap as a slice of Tuple3 values.

func (MapMapMapAny[K1, K2, K3, V]) KeyTree added in v0.3.0

func (mmma MapMapMapAny[K1, K2, K3, V]) KeyTree() []KeyTree[K1, KeyTree[K2, K3]]

KeyTree returns the keys of the multimap as a 3-level tree of the various keys.

func (MapMapMapAny[K1, K2, K3, V]) Keys added in v0.9.0

func (mmma MapMapMapAny[K1, K2, K3, V]) Keys() iter.Seq[Tuple3[K1, K2, K3]]

Keys returns the keys of the MapMapMapAny as an iterator of Tuple3s.

func (MapMapMapAny[K1, K2, K3, V]) Len added in v0.8.0

func (mmma MapMapMapAny[K1, K2, K3, V]) Len() int

Len returns the number of values in the MapMapMap.

func (MapMapMapAny[K1, K2, K3, V]) Set added in v0.3.0

func (mmma MapMapMapAny[K1, K2, K3, V]) Set(
	key1 K1,
	key2 K2,
	key3 K3,
	value V,
)

Set will set the given value with the given keys.

func (MapMapMapAny[K1, K2, K3, V]) SetByTuple added in v0.3.0

func (mmma MapMapMapAny[K1, K2, K3, V]) SetByTuple(
	key Tuple3[K1, K2, K3],
	value V,
)

SetByKey sets by the key tuple.

func (MapMapMapAny[K1, K2, K3, V]) ValueSlice added in v0.9.0

func (mmma MapMapMapAny[K1, K2, K3, V]) ValueSlice() []V

ValueSlice returns a slice containing all the values for this MapMapMap in a nondeterministic order.

func (MapMapMapAny[K1, K2, K3, V]) Values added in v0.6.0

func (mmma MapMapMapAny[K1, K2, K3, V]) Values() iter.Seq[V]

Values returns an iterator for the values in nondeterministic order.

type MapSet

type MapSet[K, V comparable] map[K]Set[V]

A MapSet is a map that contains sets. For example, a map of users to the set of resources they are allowed to access.

Direct access is legal for most operations, except that if you delete the last element out of the set with Delete, the set will be entirely removed from the MapSet, but if you delete manually it won't unless you clean it up yourself. Reading and writing directly is fine.

Perhaps the most subtle is, if you want something like "KeyTree" but that returns sets, the MapSet is itself that thing. Just:

for key, set := range MyMapSet {
    // and here you have the key and the set accessible
}

Since the nil set is mostly functional, many operations can be performed naturally simply by indexing the top-level map, even if that results in a nil set. This package only implements methods that are value-adds on top of direct map access, such as Set, which creates the map entry to a valid set if necessary. For instance, there is no need for a .Contains method; you can simply

ms := MapSet[int, int]{}
ms[0].Contains(1) // will be false

This is legal, and will not vivify the set into the MapSet.

This is why there are so few methods on MapSet; the vast majority of set operations work by direct reference into the MapSet's map, even if there is no set there. Only the operations on Set that panic if they are called on a nil set need to be wrapped by this data type, or Delete, which cleans up the set if it is empty.

func (MapSet[K, V]) Add added in v0.3.0

func (ms MapSet[K, V]) Add(key K, val V)

Add adds the given value to the mapset.

func (MapSet[K, V]) AddByTuple added in v0.7.0

func (ms MapSet[K, V]) AddByTuple(key Tuple2[K, V])

AddByTuple will add to the set via the given tuple.

func (MapSet[K, V]) AllValueSet

func (ms MapSet[K, V]) AllValueSet() Set[V]

AllValueSet returns a single set containing all values in the MapSet.

func (MapSet[K, V]) Delete

func (ms MapSet[K, V]) Delete(key K, val V)

func (MapSet[K, V]) Union added in v0.3.0

func (ms MapSet[K, V]) Union(key K, r Set[V])

Union will union the passed-in set into the Set for the given key, creating it if necessary.

func (MapSet[K, V]) Values added in v0.9.0

func (ms MapSet[K, V]) Values() iter.Seq[V]

Values yields all the values in the MapSet as an iterator.

type Set

type Set[M comparable] map[M]struct{}

A Set wraps a map[Type]struct{} with various convenience functions to turn it into a set.

As with the other data structures in this package, redundant operations with map are not implemented. To get the contents of this set, use maps.Keys. to clear a set, use maps.Clear, to get the number of elements in a set, use length(), to iterate over the set, use range in a for loop, etc. This only implements additional useful set functionality. (In particular, there is no useful rangefunc to offer that is not already provided by being a map under the hood.)

This Set offer high-efficiency mutating operations on the map; for instance, Union will copy the target Set into the Set the method is called on. To get the behavior where a separate Set is returned that is a union, add .Clone() to the appropriate place in your code.

It is safe to directly manipulate a set using map syntax in Go. This data type does not make any guarantees that would be violated.

The nil Set is mostly legal and functions as an empty set, except you can not .Add or .Union it.

func SetFromIter added in v0.9.0

func SetFromIter[M comparable](i iter.Seq[M]) Set[M]

SetFromIter loads a set in from an iterator.

func SetFromSlice

func SetFromSlice[M comparable](l []M) Set[M]

SetFromSlice loads a set in from a slice.

It is not appropriate or indeed even possible for a library to select how to serialize specific sets, but it can be helpful for JSON or YAML serialization to embed a specific Set and then use this and AsSlice as a pair to serialize a set as a slice instead of a map.

func (Set[M]) Add

func (s Set[M]) Add(v M)

Add will add the given value in to the set.

func (Set[M]) AsSlice

func (s Set[M]) AsSlice() []M

AsSlice returns the set as a slice, in hash order.

See comment on SetFromSlice.

func (Set[M]) Clone

func (s Set[M]) Clone() Set[M]

Clone returns a copy of the set.

func (Set[M]) Contains

func (s Set[M]) Contains(v M) bool

Contains returns true if the set contains the given value.

func (Set[M]) Equal

func (s Set[M]) Equal(r Set[M]) bool

Equal returns if two sets are equal.

func (Set[M]) Intersect added in v0.7.0

func (s Set[M]) Intersect(r Set[M]) Set[M]

Returns a new set containing only the elements that exist only in both sets.

func (Set[M]) Remove

func (s Set[M]) Remove(v M)

Remove will remove the given value from the set if it exists.

func (Set[M]) SubsetOf

func (s Set[M]) SubsetOf(r Set[M]) bool

SubsetOf returns true if the set this is called on is a subset of the passed-in set.

func (Set[M]) Subtract

func (s Set[M]) Subtract(r Set[M]) Set[M]

Subtract removes all elements from this set that are in the passed-in set.

The set this is called on is returned, allowing for chaining.

func (Set[M]) SupersetOf

func (s Set[M]) SupersetOf(r Set[M]) bool

SupersetOf returns true if the set this is called on is a superset of the passed-in set.

func (Set[M]) Union

func (s Set[M]) Union(r Set[M]) Set[M]

Union will add all elements with the passed-in set to this set. This set is then returned, allowing chaining.

func (Set[M]) XOR

func (s Set[M]) XOR(r Set[M]) Set[M]

XOR returns the values in either the set this method is called on, or the set passed in, but not both.

type Tuple2

type Tuple2[K1, K2 comparable] struct {
	Key1 K1
	Key2 K2
}

Tuple2 is a two-element tuple struct with a slot for each of the two keys.

type Tuple3

type Tuple3[K1, K2, K3 comparable] struct {
	Key1 K1
	Key2 K2
	Key3 K3
}

Tuple3 is a three-element tuple struct with a slot for each of the two keys.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL