diff --git a/CHANGES.md b/CHANGES.md index 28db9b5..63593c4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,22 @@ # **ANGoLS** Changes +## 0.10.0-beta1 - 7th February 2026 + +* simple refactoring of `ASCIIToLower()` and `ASCIIToUpper()`; +* changed signature of `CollectSlice()`, including making be a generic function (`CollectSlice[T, U]()`); +* refactored `CollectSliceIntoStringSlice()` in terms of `CollectSlice[T, U]()`; +* refactor `CollectSliceOfInt()` in terms of `CollectSliceOfInteger[T]()`; +* refactored `EqualSliceOfInt()` in terms of `EqualSliceOfInteger[T]()`; +* refactored `EqualSliceOfUint()` in terms of `EqualSliceOfInteger[T]()`; +* changed signature of `EqualSlice()`, including making be a generic function (`EqualSlice[T]()`); +* renamed `SelectSliceOfUinteger()` => `SelectSliceOfInteger()`; +* simplified implementation of `SelectSliceOfInteger[T]()`; +* added unit-tests for `SelectSliceOfInt()` and `SelectSliceOfString()`; +* refactored `SelectSliceOfInt()` in terms of `SelectSliceOfInteger[T]()`; +* refactored `SelectSliceOfUint()` in terms of `SelectSliceOfInteger[T]()`; +* simplified implementation of `SelectSliceOfString()`; + + ## 0.9.1 - 7th February 2026 * fixed `EqualSliceOfInteger[]()` return type; diff --git a/README.md b/README.md index e23fadb..50bdfbb 100644 --- a/README.md +++ b/README.md @@ -96,27 +96,26 @@ Modelled after **Ruby**'s `Enumerable#collect()`, these functions provide for tr ```Go // in "github.com/synesissoftware/ANGoLS/slices" -// This function maps an input slice of arbitrary type to an output slice of -// type []any. -func CollectSlice(input_slice any, fn func(input_item any) (any, error)) ([]any, error) +// This function maps an input slice of T[] to an output slice of []T. +func CollectSlice[T any](input_slice []T, collector func(index int, input_item *T) (T, error)) ([]T, error) // This function maps an input slice of []int to an output slice of []int. -func CollectSliceOfInt(input_slice []int, fn func(input_item int) int) (result_slice []int) +func CollectSliceOfInt(input_slice []int, collector func(input_item int) int) (result_slice []int) // This function maps an input slice of []N to an output slice of []N, where // N is any integer type. -func CollectSliceOfInteger[N int8 | int16 | int32 | int64 | int | uint8 | uint16 | uint32 | uint64 | uint | uintptr](input_slice []N, fn func(input_item N) N) (result_slice []N) +func CollectSliceOfInteger[N int8 | int16 | int32 | int64 | int | uint8 | uint16 | uint32 | uint64 | uint | uintptr](input_slice []N, collector func(input_item N) N) (result_slice []N) // This function maps an input slice of []float64 to an output slice of // []float64. -func CollectSliceOfFloat64(input_slice []float64, fn func(input_item float64) float64) (result_slice []float64) +func CollectSliceOfFloat64(input_slice []float64, collector func(input_item float64) float64) (result_slice []float64) // This function maps an input slice of []string to an output slice of // []string. -func CollectSliceOfString(input_slice []string, fn func(input_item string) string) (result_slice []string) +func CollectSliceOfString(input_slice []string, collector func(input_item string) string) (result_slice []string) // This function maps an input slice of []T to an output slice of []string. -func CollectSliceIntoStringSlice[T any](input_slice []T, fn func(input_item *T) (string, error)) ([]string, error) +func CollectSliceIntoStringSlice[T any](input_slice []T, collector func(input_item *T) (string, error)) ([]string, error) ``` #### `EqualSlice` Functions @@ -132,7 +131,7 @@ func EqualSliceOfInt(lhs, rhs []int) bool // Indicates whether two []uint slices have the same size, contents, and // order. -func EqualSliceOfUInt(lhs, rhs []uint) bool +func EqualSliceOfUint(lhs, rhs []uint) bool func EqualSliceOfInteger[N int8 | int16 | int32 | int64 | int | uint8 | uint16 | uint32 | uint64 | uint | uintptr](lhs, rhs []int) bool @@ -160,7 +159,7 @@ func GenerateSliceOfInt(size int, generator func(index int) (result int, err err // Creates a slice of a given size and populates its values with the given // generator (which may be nil). -func GenerateSliceOfUInt(size int, generator func(index int) (result uint, err error)) (result []uint, err error) +func GenerateSliceOfUint(size int, generator func(index int) (result uint, err error)) (result []uint, err error) // Creates a slice of a given size and populates its values with the given // generator (which may be nil). @@ -177,9 +176,9 @@ Modelled after **Ruby**'s `Enumerable#select()`, these functions provide for sel func SelectSliceOfInt(input_slice []int, selector func(index int, input_item int) (bool, error)) ([]int, error) -func SelectSliceOfUInt(input_slice []uint, selector func(index int, input_item uint) (bool, error)) ([]uint, error) +func SelectSliceOfUint(input_slice []uint, selector func(index int, input_item uint) (bool, error)) ([]uint, error) -func SelectSliceOfUInteger[N int8 | int16 | int32 | int64 | int | uint8 | uint16 | uint32 | uint64 | uint | uintptr](input_slice []N, selector func(index int, input_item N) (bool, error)) ([]N, error) +func SelectSliceOfInteger[N int8 | int16 | int32 | int64 | int | uint8 | uint16 | uint32 | uint64 | uint | uintptr](input_slice []N, selector func(index int, input_item N) (bool, error)) ([]N, error) func SelectSliceOfString(input_slice []string, selector func(index int, input_item string) (bool, error)) ([]string, error) ``` diff --git a/TODO.md b/TODO.md index 4485a1d..bb766da 100644 --- a/TODO.md +++ b/TODO.md @@ -11,23 +11,25 @@ recls for Go ## 0.9.x Items -* simplify `CollectSlice()`; -* add unit-testing for `slices` functions; -* enhance code coverage in unit-tests; +* ~~simplify `CollectSlice()`~~ - ✅; +* ~~add unit-testing for `slices` functions~~ - ✅; +* ~~enhance code coverage in unit-tests~~ - ✅; ## 0.10+ Items -* change semantics of `CollectSlice()`, `EqualSlice()` to not take `any`, but (at least) `[]any`; -* correct all `slices` functions to proper naming, including `Uint` rather than `UInt`; -* `GenerateSliceOfInteger[T]()`; +* ~~change semantics of `CollectSlice()`, `EqualSlice()` to not take `any`, but (at least) `[]any`~~ - ✅; +* ~~correct all `slices` functions to proper naming, including `Uint` rather than `Uint`~~ - ✅; +* ~~`GenerateSliceOfInteger[T]()`~~ - ✅; * `SelectSlice[T]()`; -* expand coverage of specific types for `EqualSlice[T]()`; +* ~~expand coverage of specific types for `EqualSlice[T]()`~~ - ✅; +* ~~enhance code coverage in unit-tests~~ - ✅; ## 0.11+ Items * simplify names, e.g. `CollectSlice()` => `Collect()`, and so forth; +* apply `~` on generics; * \ diff --git a/select_test.go b/select_test.go index 94fcfe6..1c5dcdc 100644 --- a/select_test.go +++ b/select_test.go @@ -37,23 +37,23 @@ func Test_SelectSliceOfInt_1(t *testing.T) { } } -func Test_SelectSliceOfUInt_1(t *testing.T) { +func Test_SelectSliceOfUint_1(t *testing.T) { - input, err := slices.GenerateSliceOfUInt(10, func(index int) (uint, error) { return uint(index), nil }) + input, err := slices.GenerateSliceOfUint(10, func(index int) (uint, error) { return uint(index), nil }) if err != nil { - t.Errorf("GenerateSliceOfUInt() failed: %v\n", err) + t.Errorf("GenerateSliceOfUint() failed: %v\n", err) } else { - actual, err := slices.SelectSliceOfUInt(input, func(index int, value uint) (bool, error) { return 0 == (value % 2), nil }) + actual, err := slices.SelectSliceOfUint(input, func(index int, value uint) (bool, error) { return 0 == (value % 2), nil }) if err != nil { - t.Errorf("SelectSliceOfUInt() failed: %v\n", err) + t.Errorf("SelectSliceOfUint() failed: %v\n", err) } else { expected := []uint{0, 2, 4, 6, 8} - if !slices.EqualSliceOfUInt(expected, actual) { + if !slices.EqualSliceOfUint(expected, actual) { t.Errorf("actual value '%v' does not equal expected value '%v'", actual, expected) } diff --git a/slices/collect_slice.go b/slices/collect_slice.go index 1d824ad..240c294 100644 --- a/slices/collect_slice.go +++ b/slices/collect_slice.go @@ -9,73 +9,43 @@ package slices -import ( - "fmt" - "reflect" -) - // ///////////////////////////////////////////////////////////////////////// // Collect* -// This function maps an input slice of arbitrary type to an output slice of -// type []any. -func CollectSlice(input_slice any, fn func(input_item any) (any, error)) ([]any, error) { - - sl_t := reflect.TypeOf(input_slice) - - if reflect.Slice != sl_t.Kind() { - - msg := fmt.Sprintf("CollectSlice() called with input_slice of type %T; slice required", input_slice) - - panic(msg) - } - - sl_v := reflect.ValueOf(input_slice) - len := sl_v.Len() - - result := make([]any, len) +// This function maps an input slice of T[] to an output slice of []U using +// the given collector. +func CollectSlice[T any, U any](input_slice []T, collector func(index int, input_item *T) (U, error)) ([]U, error) { - for i := 0; len != i; i++ { + result := make([]U, len(input_slice)) - p := sl_v.Index(i) - v := p.Interface() + for i := 0; i != len(input_slice); i++ { - r, e := fn(v) - if e != nil { + if r, err := collector(i, &input_slice[i]); err != nil { + return nil, err + } else { - return nil, e + result[i] = r } - - result[i] = r } return result, nil } // This function maps an input slice of []int to an output slice of []int. -func CollectSliceOfInt(input_slice []int, fn func(input_item int) int) (result_slice []int) { - - result_slice = make([]int, len(input_slice)) - - for i, v := range input_slice { +func CollectSliceOfInt(input_slice []int, collector func(input_item int) int) ([]int) { - result := fn(v) - - result_slice[i] = result - } - - return + return CollectSliceOfInteger(input_slice, collector) } // This function maps an input slice of []N to an output slice of []N, where // N is any integer type. -func CollectSliceOfInteger[N int8 | int16 | int32 | int64 | int | uint8 | uint16 | uint32 | uint64 | uint | uintptr](input_slice []N, fn func(input_item N) N) (result_slice []N) { +func CollectSliceOfInteger[N int8 | int16 | int32 | int64 | int | uint8 | uint16 | uint32 | uint64 | uint | uintptr](input_slice []N, collector func(input_item N) N) (result_slice []N) { result_slice = make([]N, len(input_slice)) for i, v := range input_slice { - result := fn(v) + result := collector(v) result_slice[i] = result } @@ -85,13 +55,13 @@ func CollectSliceOfInteger[N int8 | int16 | int32 | int64 | int | uint8 | uint16 // This function maps an input slice of []float64 to an output slice of // []float64. -func CollectSliceOfFloat64(input_slice []float64, fn func(input_item float64) float64) (result_slice []float64) { +func CollectSliceOfFloat64(input_slice []float64, collector func(input_item float64) float64) (result_slice []float64) { result_slice = make([]float64, len(input_slice)) for i, v := range input_slice { - result := fn(v) + result := collector(v) result_slice[i] = result } @@ -101,34 +71,24 @@ func CollectSliceOfFloat64(input_slice []float64, fn func(input_item float64) fl // This function maps an input slice of []string to an output slice of // []string. -func CollectSliceOfString(input_slice []string, fn func(input_item string) string) (result_slice []string) { +func CollectSliceOfString(input_slice []string, collector func(input_item string) string) (result_slice []string) { result_slice = make([]string, len(input_slice)) for i, s := range input_slice { - result_slice[i] = fn(s) + result_slice[i] = collector(s) } return } // This function maps an input slice of []T to an output slice of []string. -func CollectSliceIntoStringSlice[T any](input_slice []T, fn func(input_item *T) (string, error)) ([]string, error) { - - result_slice := make([]string, len(input_slice)) - - for i, t := range input_slice { - - s, err := fn(&t) - if err != nil { - return []string{}, err - } - - result_slice[i] = s - } +func CollectSliceIntoStringSlice[T any](input_slice []T, collector func(input_item *T) (string, error)) ([]string, error) { - return result_slice, nil + return CollectSlice(input_slice, func(_ int, input_item *T) (string, error) { + return collector(input_item) + }) } /* ///////////////////////////// end of file //////////////////////////// */ diff --git a/slices/collect_test.go b/slices/collect_test.go index 1f1f613..d7a9667 100644 --- a/slices/collect_test.go +++ b/slices/collect_test.go @@ -3,6 +3,8 @@ package slices_test import ( "github.com/synesissoftware/ANGoLS/slices" + "github.com/stretchr/testify/assert" + "fmt" "strconv" "strings" @@ -10,48 +12,50 @@ import ( ) const ( - int_equal_iterations = 100000 - int_equal_size = 100 + int_equal_size = 1_000 ) // Tests -func Test_Collect_Array_1_ints_to_ints(t *testing.T) { +func Test_CollectSlice_int_INTO_string(t *testing.T) { + + collector := func(index int, input_item *int) (string, error) { + + return strconv.Itoa(*input_item), nil + } + + input := []int{1, -2, 3} + expected := []string{"1", "-2", "3"} + + actual, err := slices.CollectSlice(input, collector) + if err != nil { + + } else { + assert.Equal(t, expected, actual) + } +} - fn := func(input any) (any, error) { +func Test_Collect_Array_1_ints_to_ints(t *testing.T) { - if i, ok := input.(int); ok { + collector := func(index int, input_item *int) (int, error) { - if i < 0 { + if *input_item < 0 { - return -i, nil - } + return -*input_item, nil } - return input, nil + return *input_item, nil } ints := []int{1, 2, 3} - r, err := slices.CollectSlice(ints, fn) + r, err := slices.CollectSlice(ints, collector) if err != nil { t.Errorf("Collect() failed: %v", err) } else { - for ix, v := range r { - - if i, ok := v.(int); !ok { - - t.Errorf("Element (%T)%v of non-int type at index %d\n", v, v, ix) - } else { - - if ints[ix] != i { - - t.Errorf("Element (%T)%v at index %d is different from expected value %d\n", v, v, ix, ints[ix]) - } - } - } + assert.Equal(t, ints, r) } } @@ -120,7 +124,7 @@ func Test_CollectSliceOfInteger_WITH_uint(t *testing.T) { expected := []uint{2, 0, 4, 6} actual := slices.CollectSliceOfInteger(input_slice, fn) - if !slices.EqualSliceOfUInt(expected, actual) { + if !slices.EqualSliceOfUint(expected, actual) { t.Errorf("actual value '%v' does not equal expected value '%v'", actual, expected) } @@ -183,7 +187,9 @@ func Benchmark_equal_ints_by_EqualSliceOfInt(b *testing.B) { ints_1, _ := slices.GenerateSliceOfInt(int_equal_size, fn) ints_2, _ := slices.GenerateSliceOfInt(int_equal_size, fn) - for i := 0; i != int_equal_iterations; i++ { + b.ResetTimer() + + for b.Loop() { _ = slices.EqualSliceOfInt(ints_1, ints_2) } @@ -195,7 +201,9 @@ func Benchmark_equal_ints_by_EqualSlice(b *testing.B) { ints_1, _ := slices.GenerateSliceOfInt(int_equal_size, fn) ints_2, _ := slices.GenerateSliceOfInt(int_equal_size, fn) - for i := 0; i != int_equal_iterations; i++ { + b.ResetTimer() + + for b.Loop() { _ = slices.EqualSlice(ints_1, ints_2) } @@ -204,10 +212,12 @@ func Benchmark_equal_ints_by_EqualSlice(b *testing.B) { func Benchmark_equal_uints_by_EqualSlice(b *testing.B) { fn := func(index int) (uint, error) { return uint(index), nil } - ints_1, _ := slices.GenerateSliceOfUInt(int_equal_size, fn) - ints_2, _ := slices.GenerateSliceOfUInt(int_equal_size, fn) + ints_1, _ := slices.GenerateSliceOfUint(int_equal_size, fn) + ints_2, _ := slices.GenerateSliceOfUint(int_equal_size, fn) + + b.ResetTimer() - for i := 0; i != int_equal_iterations; i++ { + for b.Loop() { _ = slices.EqualSlice(ints_1, ints_2) } @@ -223,7 +233,7 @@ func Test_CollectSliceIntoStringSlice(t *testing.T) { "Maverick", } - result, err := slices.CollectSliceIntoStringSlice[Nickname](nicknames, func(input_item *Nickname) (string, error) { + result, err := slices.CollectSliceIntoStringSlice(nicknames, func(input_item *Nickname) (string, error) { return string(*input_item), nil }) @@ -248,7 +258,7 @@ func Test_CollectSliceIntoStringSlice_with_CaseTesting(t *testing.T) { "Maverick", } - result, err := slices.CollectSliceIntoStringSlice[Nickname](nicknames, func(input_item *Nickname) (string, error) { + result, err := slices.CollectSliceIntoStringSlice(nicknames, func(input_item *Nickname) (string, error) { return strings.ToUpper(string(*input_item)), nil }) @@ -271,7 +281,7 @@ func Test_CollectSliceIntoStringSlice_with_Ints(t *testing.T) { 3, } - result, err := slices.CollectSliceIntoStringSlice[int](values, func(input_item *int) (string, error) { + result, err := slices.CollectSliceIntoStringSlice(values, func(input_item *int) (string, error) { return strconv.Itoa(*input_item), nil }) @@ -296,7 +306,7 @@ func Test_CollectSliceIntoStringSlice_with_Fail(t *testing.T) { "Maverick", } - _, err := slices.CollectSliceIntoStringSlice[Nickname](nicknames, func(input_item *Nickname) (string, error) { + _, err := slices.CollectSliceIntoStringSlice(nicknames, func(input_item *Nickname) (string, error) { if strings.Contains(string(*input_item), "k") { return "", fmt.Errorf("invalid nickname: %s", *input_item) } diff --git a/slices/equal_slice.go b/slices/equal_slice.go index 30b3284..61be7b8 100644 --- a/slices/equal_slice.go +++ b/slices/equal_slice.go @@ -20,50 +20,18 @@ import ( // order. func EqualSliceOfInt(lhs, rhs []int) bool { - len_l := len(lhs) - len_r := len(rhs) - - if len_l != len_r { - - return false - } else { - - for i := 0; len_l != i; i++ { - - if lhs[i] != rhs[i] { - - return false - } - } - - return true - } + return EqualSliceOfInteger(lhs, rhs) } // Indicates whether two []uint slices have the same size, contents, and // order. -func EqualSliceOfUInt(lhs, rhs []uint) bool { +func EqualSliceOfUint(lhs, rhs []uint) bool { - len_l := len(lhs) - len_r := len(rhs) - - if len_l != len_r { - - return false - } else { - - for i := 0; len_l != i; i++ { - - if lhs[i] != rhs[i] { - - return false - } - } - - return true - } + return EqualSliceOfInteger(lhs, rhs) } +// Indicates whether two []N slices have the same size, contents, and +// order. func EqualSliceOfInteger[N int8 | int16 | int32 | int64 | int | uint8 | uint16 | uint32 | uint64 | uint | uintptr](lhs, rhs []N) bool { len_l := len(lhs) @@ -134,58 +102,85 @@ func EqualSliceOfString(lhs, rhs []string) bool { } } -func EqualSlice(lhs, rhs any) bool { +// Indicates whether two []T slices have the same size, contents, and order. +func EqualSlice[T any](lhs, rhs []T) bool { // Check for typed variants - switch lhs_typed := lhs.(type) { + switch lhs_typed := any(lhs).(type) { + + case []int8: + + rhs_typed, _ := any(rhs).([]int8) + + return EqualSliceOfInteger(lhs_typed, rhs_typed) + case []int16: + + rhs_typed, _ := any(rhs).([]int16) + + return EqualSliceOfInteger(lhs_typed, rhs_typed) + case []int32: + + rhs_typed, _ := any(rhs).([]int32) + + return EqualSliceOfInteger(lhs_typed, rhs_typed) + case []int64: + rhs_typed, _ := any(rhs).([]int64) + + return EqualSliceOfInteger(lhs_typed, rhs_typed) case []int: - if rhs_typed, ok := rhs.([]int); ok { + rhs_typed, _ := any(rhs).([]int) - return EqualSliceOfInt(lhs_typed, rhs_typed) - } else { + return EqualSliceOfInteger(lhs_typed, rhs_typed) + case []uint8: - return false - } - case []float64: + rhs_typed, _ := any(rhs).([]uint8) - if rhs_typed, ok := rhs.([]float64); ok { + return EqualSliceOfInteger(lhs_typed, rhs_typed) + case []uint16: - return EqualSliceOfFloat64(lhs_typed, rhs_typed) - } else { + rhs_typed, _ := any(rhs).([]uint16) - return false - } - case []string: + return EqualSliceOfInteger(lhs_typed, rhs_typed) + case []uint32: - if rhs_typed, ok := rhs.([]string); ok { + rhs_typed, _ := any(rhs).([]uint32) - return EqualSliceOfString(lhs_typed, rhs_typed) - } else { + return EqualSliceOfInteger(lhs_typed, rhs_typed) + case []uint64: - return false - } - } + rhs_typed, _ := any(rhs).([]uint64) - // Generic comparison + return EqualSliceOfInteger(lhs_typed, rhs_typed) + case []uint: - lhs_t := reflect.TypeOf(lhs) - rhs_t := reflect.TypeOf(rhs) + rhs_typed, _ := any(rhs).([]uint) - // check both are slices + return EqualSliceOfInteger(lhs_typed, rhs_typed) + case []uintptr: - if reflect.Slice != lhs_t.Kind() { + rhs_typed, _ := any(rhs).([]uintptr) - return false - } + return EqualSliceOfInteger(lhs_typed, rhs_typed) + case []float64: - if reflect.Slice != rhs_t.Kind() { + rhs_typed, _ := any(rhs).([]float64) - return false + return EqualSliceOfFloat64(lhs_typed, rhs_typed) + case []string: + + rhs_typed, _ := any(rhs).([]string) + + return EqualSliceOfString(lhs_typed, rhs_typed) } + // Generic comparison + + lhs_t := reflect.TypeOf(lhs) + rhs_t := reflect.TypeOf(rhs) + // check element type lhs_k := lhs_t.Elem() diff --git a/slices/equal_test.go b/slices/equal_test.go index 1ed1913..aff757d 100644 --- a/slices/equal_test.go +++ b/slices/equal_test.go @@ -8,6 +8,20 @@ import ( "testing" ) +func Test_EqualSlice(t *testing.T) { + + { + assert.True(t, slices.EqualSlice([]int{}, []int{})) + assert.True(t, slices.EqualSlice([]int{1}, []int{1})) + assert.False(t, slices.EqualSlice([]int{1}, []int{2})) + + assert.True(t, slices.EqualSlice([]int{1, 2, 3, 4}, []int{1, 2, 3, 4})) + assert.False(t, slices.EqualSlice([]int{1, 2, 3, 4}, []int{1, 2, 4, 3})) + + assert.True(t, slices.EqualSlice([]int{1, 2, 3, 4, 5}[:4], []int{1, 2, 3, 4, 6}[:4])) + } +} + func Test_EqualSliceOfInt(t *testing.T) { { @@ -36,14 +50,14 @@ func Test_EqualSliceOfInt(t *testing.T) { func Test_EqualSliceOfUint(t *testing.T) { { - assert.True(t, slices.EqualSliceOfUInt([]uint{}, []uint{})) - assert.True(t, slices.EqualSliceOfUInt([]uint{1}, []uint{1})) - assert.False(t, slices.EqualSliceOfUInt([]uint{1}, []uint{2})) + assert.True(t, slices.EqualSliceOfUint([]uint{}, []uint{})) + assert.True(t, slices.EqualSliceOfUint([]uint{1}, []uint{1})) + assert.False(t, slices.EqualSliceOfUint([]uint{1}, []uint{2})) - assert.True(t, slices.EqualSliceOfUInt([]uint{1, 2, 3, 4}, []uint{1, 2, 3, 4})) - assert.False(t, slices.EqualSliceOfUInt([]uint{1, 2, 3, 4}, []uint{1, 2, 4, 3})) + assert.True(t, slices.EqualSliceOfUint([]uint{1, 2, 3, 4}, []uint{1, 2, 3, 4})) + assert.False(t, slices.EqualSliceOfUint([]uint{1, 2, 3, 4}, []uint{1, 2, 4, 3})) - assert.True(t, slices.EqualSliceOfUInt([]uint{1, 2, 3, 4, 5}[:4], []uint{1, 2, 3, 4, 6}[:4])) + assert.True(t, slices.EqualSliceOfUint([]uint{1, 2, 3, 4, 5}[:4], []uint{1, 2, 3, 4, 6}[:4])) } { diff --git a/slices/generate_slice.go b/slices/generate_slice.go index 4862676..37b6827 100644 --- a/slices/generate_slice.go +++ b/slices/generate_slice.go @@ -1,10 +1,10 @@ -// Copyright 2019-2025 Matthew Wilson and Synesis Information Systems. All +// Copyright 2019-2026 Matthew Wilson and Synesis Information Systems. All // rights reserved. Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. /* * Created: 1st March 2019 - * Updated: 27th November 2025 + * Updated: 7th February 2026 */ package slices @@ -51,7 +51,7 @@ func GenerateSliceOfInt(size int, generator func(index int) (result int, err err // Creates a slice of a given size and populates its values with the given // generator (which may be nil). -func GenerateSliceOfUInt(size int, generator func(index int) (result uint, err error)) (result []uint, err error) { +func GenerateSliceOfUint(size int, generator func(index int) (result uint, err error)) (result []uint, err error) { result = make([]uint, size) diff --git a/slices/select_slice.go b/slices/select_slice.go index 86033fe..578ce2d 100644 --- a/slices/select_slice.go +++ b/slices/select_slice.go @@ -1,10 +1,10 @@ -// Copyright 2019-2025 Matthew Wilson and Synesis Information Systems. All +// Copyright 2019-2026 Matthew Wilson and Synesis Information Systems. All // rights reserved. Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. /* * Created: 1st March 2019 - * Updated: 24th February 2025 + * Updated: 7th February 2026 */ package slices @@ -12,100 +12,64 @@ package slices // ///////////////////////////////////////////////////////////////////////// // Select* +// Selects elements of an input slice of []int to an output slice of []int, +// according to the given selector function. func SelectSliceOfInt(input_slice []int, selector func(index int, input_item int) (bool, error)) ([]int, error) { - input_len := len(input_slice) - result := make([]int, input_len) - result_len := 0 - - for i, v := range input_slice { - - selected, err := selector(i, v) - if err != nil { - - return nil, err - } - - if selected { - - result[result_len] = v - result_len++ - } - } - - return result[0:result_len], nil + return SelectSliceOfInteger(input_slice, selector) } -func SelectSliceOfUInt(input_slice []uint, selector func(index int, input_item uint) (bool, error)) ([]uint, error) { - - input_len := len(input_slice) - result := make([]uint, input_len) - result_len := 0 +// Selects elements of an input slice of []uint to an output slice of +// []uint, according to the given selector function. +func SelectSliceOfUint(input_slice []uint, selector func(index int, input_item uint) (bool, error)) ([]uint, error) { - for i, v := range input_slice { - - selected, err := selector(i, v) - if err != nil { - - return nil, err - } - - if selected { - - result[result_len] = v - result_len++ - } - } - - return result[0:result_len], nil + return SelectSliceOfInteger(input_slice, selector) } -func SelectSliceOfUInteger[N int8 | int16 | int32 | int64 | int | uint8 | uint16 | uint32 | uint64 | uint | uintptr](input_slice []N, selector func(index int, input_item N) (bool, error)) ([]N, error) { +// Selects elements of an input slice of []N to an output slice of []N, +// according to the given selector function. +func SelectSliceOfInteger[N int8 | int16 | int32 | int64 | int | uint8 | uint16 | uint32 | uint64 | uint | uintptr](input_slice []N, selector func(index int, input_item N) (bool, error)) ([]N, error) { - input_len := len(input_slice) - result := make([]N, input_len) - result_len := 0 + r := make([]N, 0, len(input_slice)) for i, v := range input_slice { - selected, err := selector(i, v) - if err != nil { + if selected, err := selector(i, v); err != nil { return nil, err - } + } else { - if selected { + if selected { - result[result_len] = v - result_len++ + r = append(r, v) + } } } - return result[0:result_len], nil + return r, nil } +// Selects elements of an input slice of []string to an output slice of +// []string, according to the given selector function. func SelectSliceOfString(input_slice []string, selector func(index int, input_item string) (bool, error)) ([]string, error) { - input_len := len(input_slice) - result := make([]string, input_len) - result_len := 0 + r := make([]string, 0, len(input_slice)) - for i, v := range input_slice { + for i, s := range input_slice { - selected, err := selector(i, v) - if err != nil { + if selected, err := selector(i, s); err != nil { return nil, err - } + } else { - if selected { + if selected { - result[result_len] = v - result_len++ + r = append(r, s) + } } } - return result[0:result_len], nil + return r, nil } /* ///////////////////////////// end of file //////////////////////////// */ diff --git a/slices/select_test.go b/slices/select_test.go index da561c6..2335437 100644 --- a/slices/select_test.go +++ b/slices/select_test.go @@ -8,6 +8,40 @@ import ( "testing" ) +func Benchmark_SelectSliceOfInt(b *testing.B) { + + inputs := [][]int{ + {}, + {1}, + {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + } + + for b.Loop() { + for _, input := range inputs { + slices.SelectSliceOfInt(input, func(_, _ int) (bool, error) { + return true, nil + }) + } + } +} + +func Benchmark_SelectSliceOfString(b *testing.B) { + + inputs := [][]string{ + {}, + {"1"}, + {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10"}, + } + + for b.Loop() { + for _, input := range inputs { + slices.SelectSliceOfString(input, func(_ int, _ string) (bool, error) { + return true, nil + }) + } + } +} + func Test_SelectSliceOfInt(t *testing.T) { { @@ -74,13 +108,13 @@ func Test_SelectSliceOfInt(t *testing.T) { } } -func Test_SelectSliceOfUInt(t *testing.T) { +func Test_SelectSliceOfUint(t *testing.T) { { input := []uint{} { - r, _ := slices.SelectSliceOfUInt( + r, _ := slices.SelectSliceOfUint( input, func(_ int, _ uint) (bool, error) { return true, nil }, ) @@ -88,7 +122,7 @@ func Test_SelectSliceOfUInt(t *testing.T) { assert.Equal(t, []uint{}, r) } { - r, _ := slices.SelectSliceOfUInt( + r, _ := slices.SelectSliceOfUint( input, func(_ int, _ uint) (bool, error) { return false, nil }, ) @@ -101,7 +135,7 @@ func Test_SelectSliceOfUInt(t *testing.T) { input := []uint{1} { - r, _ := slices.SelectSliceOfUInt( + r, _ := slices.SelectSliceOfUint( input, func(_ int, _ uint) (bool, error) { return true, nil }, ) @@ -109,7 +143,7 @@ func Test_SelectSliceOfUInt(t *testing.T) { assert.Equal(t, []uint{1}, r) } { - r, _ := slices.SelectSliceOfUInt( + r, _ := slices.SelectSliceOfUint( input, func(_ int, _ uint) (bool, error) { return false, nil }, ) @@ -122,7 +156,7 @@ func Test_SelectSliceOfUInt(t *testing.T) { input := []uint{1, 2, 3, 4, 5, 6} { - r, _ := slices.SelectSliceOfUInt( + r, _ := slices.SelectSliceOfUint( input, func(_ int, input_item uint) (bool, error) { return 0 != (input_item % 2), nil }, ) @@ -130,7 +164,7 @@ func Test_SelectSliceOfUInt(t *testing.T) { assert.Equal(t, []uint{1, 3, 5}, r) } { - r, _ := slices.SelectSliceOfUInt( + r, _ := slices.SelectSliceOfUint( input, func(_ int, input_item uint) (bool, error) { return 0 == (input_item % 2), nil }, ) @@ -148,7 +182,7 @@ func Test_SelectSliceOfInteger(t *testing.T) { input := []int{} { - r, _ := slices.SelectSliceOfUInteger( + r, _ := slices.SelectSliceOfInteger( input, func(_, _ int) (bool, error) { return true, nil }, ) @@ -156,7 +190,7 @@ func Test_SelectSliceOfInteger(t *testing.T) { assert.Equal(t, []int{}, r) } { - r, _ := slices.SelectSliceOfUInteger( + r, _ := slices.SelectSliceOfInteger( input, func(_, _ int) (bool, error) { return false, nil }, ) @@ -169,7 +203,7 @@ func Test_SelectSliceOfInteger(t *testing.T) { input := []int{1} { - r, _ := slices.SelectSliceOfUInteger( + r, _ := slices.SelectSliceOfInteger( input, func(_, _ int) (bool, error) { return true, nil }, ) @@ -177,7 +211,7 @@ func Test_SelectSliceOfInteger(t *testing.T) { assert.Equal(t, []int{1}, r) } { - r, _ := slices.SelectSliceOfUInteger( + r, _ := slices.SelectSliceOfInteger( input, func(_, _ int) (bool, error) { return false, nil }, ) @@ -190,7 +224,7 @@ func Test_SelectSliceOfInteger(t *testing.T) { input := []int{1, 2, 3, 4, 5, 6} { - r, _ := slices.SelectSliceOfUInteger( + r, _ := slices.SelectSliceOfInteger( input, func(_, input_item int) (bool, error) { return 0 != (input_item % 2), nil }, ) @@ -198,7 +232,7 @@ func Test_SelectSliceOfInteger(t *testing.T) { assert.Equal(t, []int{1, 3, 5}, r) } { - r, _ := slices.SelectSliceOfUInteger( + r, _ := slices.SelectSliceOfInteger( input, func(_, input_item int) (bool, error) { return 0 == (input_item % 2), nil }, ) @@ -208,69 +242,135 @@ func Test_SelectSliceOfInteger(t *testing.T) { } } - // int + // uint64 { { - input := []int{} + input := []uint64{} { - r, _ := slices.SelectSliceOfUInteger( + r, _ := slices.SelectSliceOfInteger( input, - func(_, _ int) (bool, error) { return true, nil }, + func(_ int, _ uint64) (bool, error) { return true, nil }, ) - assert.Equal(t, []int{}, r) + assert.Equal(t, []uint64{}, r) } { - r, _ := slices.SelectSliceOfUInteger( + r, _ := slices.SelectSliceOfInteger( input, - func(_, _ int) (bool, error) { return false, nil }, + func(_ int, _ uint64) (bool, error) { return false, nil }, ) - assert.Equal(t, []int{}, r) + assert.Equal(t, []uint64{}, r) } } { - input := []int{1} + input := []uint64{1} { - r, _ := slices.SelectSliceOfUInteger( + r, _ := slices.SelectSliceOfInteger( input, - func(_, _ int) (bool, error) { return true, nil }, + func(_ int, _ uint64) (bool, error) { return true, nil }, ) - assert.Equal(t, []int{1}, r) + assert.Equal(t, []uint64{1}, r) } { - r, _ := slices.SelectSliceOfUInteger( + r, _ := slices.SelectSliceOfInteger( input, - func(_, _ int) (bool, error) { return false, nil }, + func(_ int, _ uint64) (bool, error) { return false, nil }, ) - assert.Equal(t, []int{}, r) + assert.Equal(t, []uint64{}, r) } } { - input := []int{1, 2, 3, 4, 5, 6} + input := []uint64{1, 2, 3, 4, 5, 6} { - r, _ := slices.SelectSliceOfUInteger( + r, _ := slices.SelectSliceOfInteger( input, - func(_, input_item int) (bool, error) { return 0 != (input_item % 2), nil }, + func(_ int, input_item uint64) (bool, error) { return 0 != (input_item % 2), nil }, ) - assert.Equal(t, []int{1, 3, 5}, r) + assert.Equal(t, []uint64{1, 3, 5}, r) } { - r, _ := slices.SelectSliceOfUInteger( + r, _ := slices.SelectSliceOfInteger( input, - func(_, input_item int) (bool, error) { return 0 == (input_item % 2), nil }, + func(_ int, input_item uint64) (bool, error) { return 0 == (input_item % 2), nil }, ) - assert.Equal(t, []int{2, 4, 6}, r) + assert.Equal(t, []uint64{2, 4, 6}, r) } } } } + +func Test_SelectSliceOfString(t *testing.T) { + + { + input := []string{} + + { + r, _ := slices.SelectSliceOfString( + input, + func(_ int, _ string) (bool, error) { return true, nil }, + ) + + assert.Equal(t, []string{}, r) + } + { + r, _ := slices.SelectSliceOfString( + input, + func(_ int, _ string) (bool, error) { return false, nil }, + ) + + assert.Equal(t, []string{}, r) + } + } + + { + input := []string{"a"} + + { + r, _ := slices.SelectSliceOfString( + input, + func(_ int, _ string) (bool, error) { return true, nil }, + ) + + assert.Equal(t, []string{"a"}, r) + } + { + r, _ := slices.SelectSliceOfString( + input, + func(_ int, _ string) (bool, error) { return false, nil }, + ) + + assert.Equal(t, []string{}, r) + } + } + + { + input := []string{"", "a", "bcd", "d", "efghij", "kl"} + + { + r, _ := slices.SelectSliceOfString( + input, + func(_ int, input_item string) (bool, error) { return len(input_item) < 2, nil }, + ) + + assert.Equal(t, []string{"", "a", "d"}, r) + } + { + r, _ := slices.SelectSliceOfString( + input, + func(_ int, input_item string) (bool, error) { return len(input_item) >= 2, nil }, + ) + + assert.Equal(t, []string{"bcd", "efghij", "kl"}, r) + } + } +} diff --git a/strings/ascii.go b/strings/ascii.go index d714561..7292fcd 100644 --- a/strings/ascii.go +++ b/strings/ascii.go @@ -4,7 +4,7 @@ /* * Created: 1st January 2026 - * Updated: 2nd January 2026 + * Updated: 7th February 2026 */ package strings @@ -17,12 +17,17 @@ package strings // are known to contain only ASCII and a faster conversion than is provided // by the standard `ToLower()` is desired. func ASCIIToLower(s string) string { + b := []byte(s) - for i := 0; i < len(b); i++ { - if b[i] >= 'A' && b[i] <= 'Z' { + + for i, c := range b { + + if c >= 'A' && c <= 'Z' { + b[i] += 32 } } + return string(b) } @@ -34,12 +39,17 @@ func ASCIIToLower(s string) string { // are known to contain only ASCII and a faster conversion than is provided // by the standard `ToUpper()` is desired. func ASCIIToUpper(s string) string { + b := []byte(s) - for i := 0; i < len(b); i++ { - if b[i] >= 'a' && b[i] <= 'z' { + + for i, c := range b { + + if c >= 'a' && c <= 'z' { + b[i] -= 32 } } + return string(b) } diff --git a/strings/ascii_test.go b/strings/ascii_test.go index bf119cd..cb028d6 100644 --- a/strings/ascii_test.go +++ b/strings/ascii_test.go @@ -43,28 +43,32 @@ func Test_ASCIIToUpper(t *testing.T) { func Benchmark_ASCIIToLower(b *testing.B) { const s = "Hello, World!" - for i := 0; i < b.N; i++ { + + for b.Loop() { _ = strings.ASCIIToLower(s) } } func Benchmark_StringsToLower(b *testing.B) { const s = "Hello, World!" - for i := 0; i < b.N; i++ { + + for b.Loop() { _ = stdstrings.ToLower(s) } } func Benchmark_ASCIIToUpper(b *testing.B) { const s = "Hello, World!" - for i := 0; i < b.N; i++ { + + for b.Loop() { _ = strings.ASCIIToUpper(s) } } func Benchmark_StringsToUpper(b *testing.B) { const s = "Hello, World!" - for i := 0; i < b.N; i++ { + + for b.Loop() { _ = stdstrings.ToUpper(s) } } diff --git a/version.go b/version.go index fa1b750..ab275ac 100644 --- a/version.go +++ b/version.go @@ -4,7 +4,7 @@ /* * Created: 1st March 2019 - * Updated: 6th February 2026 + * Updated: 7th February 2026 */ package angols @@ -13,9 +13,9 @@ import "github.com/synesissoftware/ver2go" const ( VersionMajor uint16 = 0 - VersionMinor uint16 = 9 - VersionPatch uint16 = 1 - VersionAB uint16 = 0xFFFF + VersionMinor uint16 = 10 + VersionPatch uint16 = 0 + VersionAB uint16 = 0x8001 Version uint64 = (uint64(VersionMajor) << 48) + (uint64(VersionMinor) << 32) + (uint64(VersionPatch) << 16) + (uint64(VersionAB) << 0) ) diff --git a/version_test.go b/version_test.go index 8944a74..870d713 100644 --- a/version_test.go +++ b/version_test.go @@ -10,9 +10,9 @@ import ( const ( Expected_VersionMajor uint16 = 0 - Expected_VersionMinor uint16 = 9 - Expected_VersionPatch uint16 = 1 - Expected_VersionAB uint16 = 0xFFFF + Expected_VersionMinor uint16 = 10 + Expected_VersionPatch uint16 = 0 + Expected_VersionAB uint16 = 0x8001 ) func Test_Version_Elements(t *testing.T) { @@ -23,9 +23,9 @@ func Test_Version_Elements(t *testing.T) { } func Test_Version(t *testing.T) { - require.Equal(t, uint64(0x0000_0009_0001_FFFF), angols.Version) + require.Equal(t, uint64(0x0000_000A_0000_8001), angols.Version) } func Test_Version_String(t *testing.T) { - require.Equal(t, "0.9.1", angols.VersionString()) + require.Equal(t, "0.10.0-beta1", angols.VersionString()) }