Skip to content

Commit

Permalink
Improve package documentation (#19)
Browse files Browse the repository at this point in the history
  • Loading branch information
mokiat authored Jun 21, 2023
1 parent 88a156d commit 3eaa195
Show file tree
Hide file tree
Showing 9 changed files with 402 additions and 13 deletions.
5 changes: 5 additions & 0 deletions doc.go
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
7 changes: 7 additions & 0 deletions ds/doc.go
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
95 changes: 95 additions & 0 deletions ds/example_test.go
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
}
196 changes: 196 additions & 0 deletions example_test.go
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]}]
}
10 changes: 10 additions & 0 deletions filter/doc.go
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
40 changes: 40 additions & 0 deletions filter/example_test.go
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"}
}
13 changes: 12 additions & 1 deletion opt/doc.go
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
Loading

0 comments on commit 3eaa195

Please sign in to comment.