-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
402 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,7 @@ | ||
// Package gog provides utilities for working with Go generics. | ||
// | ||
// This top-level package contains common functions that transform, search and | ||
// filter built-in Go types (e.g. slices, maps, etc) of generic type. | ||
// | ||
// For more sophisticated scenarios check subdirectories. | ||
package gog |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,9 @@ | ||
// Package ds provides various data structure implementations with generics. | ||
// | ||
// Prior to Go 1.18, such data structures could not be implemented in a | ||
// satisfactory way, as one had to use interfaces, which ofter resulted in | ||
// unreadable code, memory allocations and conditions for unexpected panics. | ||
// | ||
// Now that Go has generics, this package provides some common data structures | ||
// that make use of this new language feature. | ||
package ds |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package ds_test | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
|
||
"github.com/mokiat/gog/ds" | ||
) | ||
|
||
func ExampleHeap() { | ||
heap := ds.NewHeap(0, func(a, b int) bool { | ||
return a < b | ||
}) | ||
heap.Push(100) | ||
heap.Push(20) | ||
heap.Push(50) | ||
heap.Push(13) | ||
heap.Push(300) | ||
|
||
fmt.Println(heap.Pop()) | ||
fmt.Println(heap.Pop()) | ||
fmt.Println(heap.Pop()) | ||
fmt.Println(heap.Pop()) | ||
fmt.Println(heap.Pop()) | ||
|
||
// Output: | ||
// 13 | ||
// 20 | ||
// 50 | ||
// 100 | ||
// 300 | ||
} | ||
|
||
func ExampleList() { | ||
list := ds.NewList[string](0) | ||
list.Add("first") | ||
list.Add("second") | ||
list.Add("third") | ||
list.Add("fourth") | ||
list.Remove("second") | ||
list.Remove("third") | ||
fmt.Printf("%#v\n", list.Items()) | ||
|
||
// Output: | ||
// []string{"first", "fourth"} | ||
} | ||
|
||
func ExamplePool() { | ||
pool := ds.NewPool[bytes.Buffer]() | ||
|
||
buffer := pool.Fetch() | ||
buffer.Reset() | ||
buffer.WriteString("this buffer is mine") | ||
pool.Restore(buffer) | ||
|
||
newBuffer := pool.Fetch() | ||
// newBuffer.Reset() // commented out to show that the instance is reused | ||
fmt.Println(newBuffer.String()) | ||
|
||
// Output: | ||
// this buffer is mine | ||
} | ||
|
||
func ExampleSet() { | ||
set := ds.NewSet[int](0) | ||
set.Add(2) | ||
set.Add(3) | ||
set.Add(5) | ||
set.Add(7) | ||
fmt.Println(set.Contains(2)) | ||
fmt.Println(set.Contains(10)) | ||
fmt.Println(set.Contains(5)) | ||
fmt.Println(set.Contains(8)) | ||
|
||
// Output: | ||
// true | ||
// false | ||
// true | ||
// false | ||
} | ||
|
||
func ExampleStack() { | ||
stack := ds.NewStack[string](3) | ||
stack.Push("first") | ||
stack.Push("second") | ||
stack.Push("third") | ||
fmt.Println(stack.Pop()) | ||
fmt.Println(stack.Pop()) | ||
fmt.Println(stack.Pop()) | ||
|
||
// Output: | ||
// third | ||
// second | ||
// first | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,196 @@ | ||
package gog_test | ||
|
||
import ( | ||
"fmt" | ||
"strconv" | ||
"strings" | ||
|
||
"github.com/mokiat/gog" | ||
"golang.org/x/exp/slices" | ||
) | ||
|
||
func ExampleDedupe() { | ||
source := []int{1, 1, 2, 3, 3, 4} | ||
target := gog.Dedupe(source) | ||
fmt.Printf("%#v\n", target) | ||
|
||
// Output: | ||
// []int{1, 2, 3, 4} | ||
} | ||
|
||
func ExampleDerefElements() { | ||
first, second, third := "first", "second", "third" | ||
source := []*string{&first, &second, &third} | ||
target := gog.DerefElements(source) | ||
fmt.Printf("%#v\n", target) | ||
|
||
// Output: | ||
// []string{"first", "second", "third"} | ||
} | ||
|
||
func ExampleFindFunc() { | ||
source := []string{"user 01", "user 02", "user 03"} | ||
target, ok := gog.FindFunc(source, func(item string) bool { | ||
return strings.Contains(item, "02") | ||
}) | ||
fmt.Println(ok) | ||
fmt.Println(target) | ||
|
||
// Output: | ||
// true | ||
// user 02 | ||
} | ||
|
||
func ExampleFindFuncPtr() { | ||
source := []string{"user 01", "user 02", "user 03"} | ||
target := gog.FindFuncPtr(source, func(item string) bool { | ||
return strings.Contains(item, "02") | ||
}) | ||
fmt.Println(target != nil) | ||
fmt.Println(*target) | ||
*target = "user 04" | ||
fmt.Printf("%#v\n", source) | ||
|
||
// Output: | ||
// true | ||
// user 02 | ||
// []string{"user 01", "user 04", "user 03"} | ||
} | ||
|
||
func ExampleFlatten() { | ||
source := [][]int{ | ||
{1, 2, 3}, | ||
{4, 5, 6, 7}, | ||
} | ||
target := gog.Flatten(source) | ||
fmt.Printf("%#v\n", target) | ||
|
||
// Output: | ||
// []int{1, 2, 3, 4, 5, 6, 7} | ||
} | ||
|
||
func ExampleMap() { | ||
source := []int{1, 2, 3} | ||
target := gog.Map(source, func(item int) string { | ||
return strconv.Itoa(item * 2) | ||
}) | ||
fmt.Printf("%#v\n", target) | ||
|
||
// Output: | ||
// []string{"2", "4", "6"} | ||
} | ||
|
||
func ExampleMapping() { | ||
source := []int{1, 2, 3, 4, 5} | ||
target := gog.Mapping(source, func(item int) (bool, string) { | ||
isEven := item%2 == 0 | ||
return isEven, strconv.Itoa(item) | ||
}) | ||
fmt.Printf("even: %#v\n", target[true]) | ||
fmt.Printf("odd: %#v\n", target[false]) | ||
|
||
// Output: | ||
// even: []string{"2", "4"} | ||
// odd: []string{"1", "3", "5"} | ||
} | ||
|
||
func ExampleMutate() { | ||
source := []int{1, 2, 3, 4, 5} | ||
gog.Mutate(source, func(item *int) { | ||
*item = *item + 10 | ||
}) | ||
fmt.Printf("%#v\n", source) | ||
|
||
// Output: | ||
// []int{11, 12, 13, 14, 15} | ||
} | ||
|
||
func ExamplePartition() { | ||
source := []int{1, 2, 3, 4, 5} | ||
target := gog.Partition(source, func(item int) bool { | ||
isEven := item%2 == 0 | ||
return isEven | ||
}) | ||
fmt.Printf("even: %#v\n", target[true]) | ||
fmt.Printf("odd: %#v\n", target[false]) | ||
|
||
// Output: | ||
// even: []int{2, 4} | ||
// odd: []int{1, 3, 5} | ||
} | ||
|
||
func ExamplePtrOf() { | ||
ptr := gog.PtrOf("hello world") // since &"hello world" is not possible | ||
fmt.Println(ptr != nil) | ||
fmt.Println(*ptr) | ||
|
||
// Output: | ||
// true | ||
// hello world | ||
} | ||
|
||
func ExampleReduce() { | ||
source := []int{2, 30, 100} | ||
target := gog.Reduce(source, 0, func(accum, item int) int { | ||
return accum + item*2 | ||
}) | ||
fmt.Println(target) | ||
|
||
// Output: | ||
// 264 | ||
} | ||
|
||
func ExampleRefElements() { | ||
source := []int{5, 7} | ||
target := gog.RefElements(source) | ||
*target[0] = 9 | ||
*target[1] = 11 | ||
fmt.Printf("%#v\n", source) | ||
|
||
// Output: | ||
// []int{9, 11} | ||
} | ||
|
||
func ExampleSelect() { | ||
source := []int{5, 8, 9, 10} | ||
target := gog.Select(source, func(item int) bool { | ||
isEven := item%2 == 0 | ||
return isEven | ||
}) | ||
fmt.Printf("%#v\n", target) | ||
|
||
// Output: | ||
// []int{8, 10} | ||
} | ||
|
||
func ExampleValueOf() { | ||
firstValue := "first" | ||
|
||
var firstPtr *string = &firstValue | ||
var secondPtr *string = nil | ||
|
||
first := gog.ValueOf(firstPtr, "default") | ||
fmt.Println(first) | ||
|
||
second := gog.ValueOf(secondPtr, "default") | ||
fmt.Println(second) | ||
|
||
// Output: | ||
// first | ||
// default | ||
} | ||
|
||
func ExampleEntries() { | ||
source := map[string][]int{ | ||
"even": {2, 4, 6}, | ||
"odd": {1, 3, 5}, | ||
} | ||
target := gog.Entries(source) | ||
slices.SortFunc(target, func(first, second gog.KV[string, []int]) bool { | ||
return first.Key < second.Key | ||
}) | ||
fmt.Printf("%+v\n", target) | ||
|
||
// Output: | ||
// [{Key:even Value:[2 4 6]} {Key:odd Value:[1 3 5]}] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,13 @@ | ||
// Package filter adds helper functions for performing filtering | ||
// over a data set. | ||
// | ||
// There are times when one needs to filter a slice of values but the exact | ||
// filtering logic cannot be hardcoded in advance and is conditional on | ||
// some external flags or parameters. In such cases, it is useful to be able to | ||
// dynamically construct a filtering expression that can pick values from some | ||
// data set. | ||
// | ||
// This can be achieved through the usage of the Slice function | ||
// and the set of predefined filtering expressions like Or, And, Not and more, | ||
// where custom ones can be plugged in as well. | ||
package filter |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package filter_test | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
|
||
"github.com/mokiat/gog/filter" | ||
) | ||
|
||
func Example() { | ||
items := []string{ | ||
"hello universe", | ||
"big world", | ||
"hello strange world", | ||
"will be dropped", | ||
"oh well", | ||
"let me through", | ||
} | ||
|
||
hasHelloPrefix := func(candidate string) bool { | ||
return strings.HasPrefix(candidate, "hello") | ||
} | ||
hasWorldSuffix := func(candidate string) bool { | ||
return strings.HasSuffix(candidate, "world") | ||
} | ||
|
||
filteredItems := filter.Slice(items, | ||
filter.Or( | ||
filter.And( | ||
hasHelloPrefix, | ||
hasWorldSuffix, | ||
), | ||
filter.Equal("let me through"), | ||
), | ||
) | ||
fmt.Printf("%#v\n", filteredItems) | ||
|
||
// Output: | ||
// []string{"hello strange world", "let me through"} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,13 @@ | ||
// Package opt provides utilities for optional types. | ||
// Package opt provides utilities for representing optional types. | ||
// | ||
// While it is possible to represent an optional type in Go through the usage | ||
// of a pointer, there are a number of drawbacks with such an approach: | ||
// | ||
// - The value might be allocated on the heap due to the pointer reference. | ||
// - The value or structs of such values will not be comparable. | ||
// - It becomes unreadable when trying to represent an optional pointer type. | ||
// | ||
// The generic type T in this package allows one to overcome the limitations of | ||
// pointer references. Structs that are composed of such opt fields can often be | ||
// safely used as map keys (as long as the underlying values are comparable). | ||
package opt |
Oops, something went wrong.