From a6d7a9fae87b745dfa234b71d008c638acef537a Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Sun, 15 Feb 2026 07:33:28 +1100 Subject: [PATCH 1/5] boilerplate --- slices/generate_test.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/slices/generate_test.go b/slices/generate_test.go index e021fa7..c5d3287 100644 --- a/slices/generate_test.go +++ b/slices/generate_test.go @@ -29,10 +29,12 @@ func Test_GenerateSliceOfInt_1_nil_generator(t *testing.T) { } } -func Test_GenerateSliceOfInt_2_setting_all_to_const(t *testing.T) { +func Test_GenerateSliceOfInt_2_SETTING_ALL_TO_CONST(t *testing.T) { req_len := 1001 - ints, err := slices.GenerateSliceOfInt(req_len, func(index int) (int, error) { return 1, nil }) + ints, err := slices.GenerateSliceOfInt(req_len, func(index int) (int, error) { + return 1, nil + }) if err != nil { } else { @@ -52,10 +54,12 @@ func Test_GenerateSliceOfInt_2_setting_all_to_const(t *testing.T) { } } -func Test_GenerateSliceOfInt_3_doubling_index(t *testing.T) { +func Test_GenerateSliceOfInt_3_DOUBLING_index(t *testing.T) { req_len := 1001 - ints, err := slices.GenerateSliceOfInt(req_len, func(index int) (int, error) { return 2 * index, nil }) + ints, err := slices.GenerateSliceOfInt(req_len, func(index int) (int, error) { + return 2 * index, nil + }) if err != nil { } else { From 51871086afb4ee8356ac93cba783ab2ee58de13a Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Sun, 15 Feb 2026 08:00:00 +1100 Subject: [PATCH 2/5] refactored `SkipOneElement` and `SkipRemainingElements` --- CHANGES.md | 5 +++++ slices/generate_slice.go | 27 +++++++++++++++++++++------ 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 63593c4..54bf273 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,10 @@ # **ANGoLS** Changes +## 0.10.0-beta2 - 15th February 2026 + +* refactored `SkipOneElement` and `SkipRemainingElements`; + + ## 0.10.0-beta1 - 7th February 2026 * simple refactoring of `ASCIIToLower()` and `ASCIIToUpper()`; diff --git a/slices/generate_slice.go b/slices/generate_slice.go index 37b6827..0f5a373 100644 --- a/slices/generate_slice.go +++ b/slices/generate_slice.go @@ -4,17 +4,32 @@ /* * Created: 1st March 2019 - * Updated: 7th February 2026 + * Updated: 15th February 2026 */ package slices -import ( - "errors" -) +type skipOneElement struct { + s string +} + +func (e *skipOneElement) Error() string { + return e.s +} + +type skipRemainingElements struct { + s string +} + +func (e *skipRemainingElements) Error() string { + return e.s +} + +// Causes generation of a single element to be skipped. +var SkipOneElement = &skipOneElement{s: "Skip one element"} -var SkipOneElement = errors.New("Skip one element") -var SkipRemainingElements = errors.New("Skip remaining elements") +// Causes generation of all remaining elements to be skipped. +var SkipRemainingElements = &skipRemainingElements{s: "Skip remaining elements"} // Creates a slice of a given size and populates its values with the given // generator (which may be nil). From 5b424a56a5102fc47b9298f123abc1c9ff279415 Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Sun, 15 Feb 2026 09:11:26 +1100 Subject: [PATCH 3/5] * added `GenerateSliceOfInteger[T]()`; * changed semantics of `GenerateSliceOfInt()`, `GenerateSliceOfUint()`, `GenerateSliceOfString()`, * refactored `GenerateSliceOfInt()` in terms of `GenerateSliceOfInteger[T, U]()`; * refactored `GenerateSliceOfUint()` in terms of `GenerateSliceOfInteger[T, U]()`; --- CHANGES.md | 4 ++ slices/generate_slice.go | 132 ++++++++++++++++++--------------------- slices/generate_test.go | 102 ++++++++++++++++++++++++++---- 3 files changed, 155 insertions(+), 83 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 54bf273..e2bec62 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,10 @@ ## 0.10.0-beta2 - 15th February 2026 +* added `GenerateSliceOfInteger[T]()`; +* changed semantics of `GenerateSliceOfInt()`, `GenerateSliceOfUint()`, `GenerateSliceOfString()`, +* refactored `GenerateSliceOfInt()` in terms of `GenerateSliceOfInteger[T, U]()`; +* refactored `GenerateSliceOfUint()` in terms of `GenerateSliceOfInteger[T, U]()`; * refactored `SkipOneElement` and `SkipRemainingElements`; diff --git a/slices/generate_slice.go b/slices/generate_slice.go index 0f5a373..2c5d4b6 100644 --- a/slices/generate_slice.go +++ b/slices/generate_slice.go @@ -31,103 +31,95 @@ var SkipOneElement = &skipOneElement{s: "Skip one element"} // Causes generation of all remaining elements to be skipped. var SkipRemainingElements = &skipRemainingElements{s: "Skip remaining elements"} -// Creates a slice of a given size and populates its values with the given -// generator (which may be nil). -func GenerateSliceOfInt(size int, generator func(index int) (result int, err error)) (result []int, err error) { +func generateSliceOfBuiltIn[T bool | int8 | int16 | int32 | int64 | int | uint8 | uint16 | uint32 | uint64 | uint | uintptr | float32 | float64 | complex64 | complex128 | string](size int, generator func(index int) (result T, err error)) (result []T, err error) { - result = make([]int, size) + result = make([]T, 0, size) - if generator != nil { + var i int - for i := 0; size != i; i++ { + for { + if size == 0 { + break; + } else { + if size > 0 { + size-- + } + } - value, err := generator(i) + value, err := generator(i) - if err == nil { + if err == nil { - result[i] = value - } else { + result = append(result, value) + } else { - if SkipOneElement == err { + if SkipOneElement == err { - } else if SkipRemainingElements == err { + } else if SkipRemainingElements == err { - break - } else { + break + } else { - return nil, err - } + return nil, err } } + + i++ } return } -// 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) { - - result = make([]uint, size) - - if generator != nil { - - for i := 0; size != i; i++ { - - value, err := generator(i) - - if err == nil { - - result[i] = value - } else { - - if SkipOneElement == err { +// Creates a slice of []N up to a maximum size and populates its values with +// those created by the given generator. +// +// Parameters: +// - `size` - maximum size if non-negative; otherwise size unlimited; +// - `generator` - function that receives the given loop index, returning +// a result to be added into the result-slice, or one of the specific +// errors SkipOneElement (to skip a single element) or +// SkipRemainingElements (to skip all remaining elements), or another +// error to cause the operation to fail; +func GenerateSliceOfInteger[N int8 | int16 | int32 | int64 | int | uint8 | uint16 | uint32 | uint64 | uint | uintptr](size int, generator func(index int) (result N, err error)) (result []N, err error) { + + return generateSliceOfBuiltIn(size, generator) +} - } else if SkipRemainingElements == err { +// Creates a slice of []int up to a maximum size and populates its values +// with those created by the given generator. +// +// Parameters: +// - `size` - maximum size if non-negative; otherwise size unlimited; +// - `generator` - function that receives the given loop index, returning +// a result to be added into the result-slice, or one of the specific +// errors SkipOneElement (to skip a single element) or +// SkipRemainingElements (to skip all remaining elements), or another +// error to cause the operation to fail; +func GenerateSliceOfInt(size int, generator func(index int) (result int, err error)) (result []int, err error) { - break - } else { + return GenerateSliceOfInteger(size, generator) +} - return nil, err - } - } - } - } +// Creates a slice of []uint up to a maximum size and populates its values +// with those created by the given generator. +// +// Parameters: +// - `size` - maximum size if non-negative; otherwise size unlimited; +// - `generator` - function that receives the given loop index, returning +// a result to be added into the result-slice, or one of the specific +// errors SkipOneElement (to skip a single element) or +// SkipRemainingElements (to skip all remaining elements), or another +// error to cause the operation to fail; +func GenerateSliceOfUint(size int, generator func(index int) (result uint, err error)) (result []uint, err error) { - return + return GenerateSliceOfInteger(size, generator) } // Creates a slice of a given size and populates its values with the given // generator (which may be nil). func GenerateSliceOfString(size int, generator func(index int) (result string, err error)) (result []string, err error) { - result = make([]string, size) - - if generator != nil { - - for i := 0; size != i; i++ { - - value, err := generator(i) - - if err == nil { - - result[i] = value - } else { - - if SkipOneElement == err { - - } else if SkipRemainingElements == err { - - break - } else { - - return nil, err - } - } - } - } - - return + return generateSliceOfBuiltIn(size, generator) } /* ///////////////////////////// end of file //////////////////////////// */ diff --git a/slices/generate_test.go b/slices/generate_test.go index c5d3287..01d382c 100644 --- a/slices/generate_test.go +++ b/slices/generate_test.go @@ -1,15 +1,20 @@ package slices_test import ( + "fmt" + "strconv" + "github.com/synesissoftware/ANGoLS/slices" "testing" ) -func Test_GenerateSliceOfInt_1_nil_generator(t *testing.T) { +func Test_GenerateSliceOfInt_2_SETTING_ALL_TO_CONSTANT_VALUE(t *testing.T) { - req_len := 1001 - ints, err := slices.GenerateSliceOfInt(req_len, nil) + req_len := 101 + ints, err := slices.GenerateSliceOfInt(req_len, func(index int) (int, error) { + return -123, nil + }) if err != nil { } else { @@ -21,19 +26,19 @@ func Test_GenerateSliceOfInt_1_nil_generator(t *testing.T) { for i, v := range ints { - if 0 != v { + if -123 != v { - t.Errorf("element at index %d is expected to be %v, but is %v\n", i, 0, v) + t.Errorf("element at index %d is expected to be %v, but is %v\n", i, 1, v) } } } } -func Test_GenerateSliceOfInt_2_SETTING_ALL_TO_CONST(t *testing.T) { +func Test_GenerateSliceOfInt_3_DOUBLING_index(t *testing.T) { req_len := 1001 ints, err := slices.GenerateSliceOfInt(req_len, func(index int) (int, error) { - return 1, nil + return 2 * index, nil }) if err != nil { @@ -46,25 +51,30 @@ func Test_GenerateSliceOfInt_2_SETTING_ALL_TO_CONST(t *testing.T) { for i, v := range ints { - if 1 != v { + if 2*i != v { - t.Errorf("element at index %d is expected to be %v, but is %v\n", i, 1, v) + t.Errorf("element at index %d is expected to be %v, but is %v\n", i, 2*i, v) } } } } -func Test_GenerateSliceOfInt_3_DOUBLING_index(t *testing.T) { +func Test_GenerateSliceOfInt_3_SkipOneElement_FOR_ODD_INDEXES(t *testing.T) { - req_len := 1001 + req_len := 100 ints, err := slices.GenerateSliceOfInt(req_len, func(index int) (int, error) { - return 2 * index, nil + + if 1 == (index % 2) { + return -1, slices.SkipOneElement + } + + return index, nil }) if err != nil { } else { - if len(ints) != req_len { + if len(ints) != 50 { t.Errorf("generated slice was required to be of length %d, but %d obtained", req_len, len(ints)) } @@ -78,3 +88,69 @@ func Test_GenerateSliceOfInt_3_DOUBLING_index(t *testing.T) { } } } + +func Test_GenerateSliceOfInt_4_SkipAllElements_AFTER_50(t *testing.T) { + + req_len := 100 + ints, err := slices.GenerateSliceOfInt(req_len, func(index int) (int, error) { + + if index == 50 { + return -1, slices.SkipRemainingElements + } + + return index, nil + }) + if err != nil { + + } else { + + if len(ints) != 50 { + + t.Errorf("generated slice was required to be of length %d, but %d obtained", req_len, len(ints)) + } + + for i, v := range ints { + + if i != v { + + t.Errorf("element at index %d is expected to be %v, but is %v\n", i, 2*i, v) + } + } + } +} + +func Test_GenerateSliceOfString_1_itoa_FROM_INDEX_EXCEPT_22(t *testing.T) { + + req_len := 40 + ints, err := slices.GenerateSliceOfString(req_len, func(index int) (s string, err error) { + if index == 22 { + return "", slices.SkipOneElement + } + + s = "[" + strconv.Itoa(index) + "]" + + return + }) + if err != nil { + + } else { + + if len(ints) != req_len-1 { + + t.Errorf("generated slice was required to be of length %d, but %d obtained", req_len, len(ints)) + } + + for i, v := range ints { + + n := i + if i >= 22 { + n++ + } + + if fmt.Sprintf("[%d]", n) != v { + + t.Errorf("element at index %d is expected to be %v, but is %v\n", i, 2*i, v) + } + } + } +} From 26eb9b03ce7ac8b34e73fabff726bdf4c534beca Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Sun, 15 Feb 2026 09:17:14 +1100 Subject: [PATCH 4/5] added `GenerateSlice[T]()` --- CHANGES.md | 1 + slices/generate_slice.go | 49 ++++++++++++++++++++++++++++++++++++++++ slices/generate_test.go | 36 +++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index e2bec62..e2d271b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,7 @@ ## 0.10.0-beta2 - 15th February 2026 +* added `GenerateSlice[T]()`; * added `GenerateSliceOfInteger[T]()`; * changed semantics of `GenerateSliceOfInt()`, `GenerateSliceOfUint()`, `GenerateSliceOfString()`, * refactored `GenerateSliceOfInt()` in terms of `GenerateSliceOfInteger[T, U]()`; diff --git a/slices/generate_slice.go b/slices/generate_slice.go index 2c5d4b6..44e5f6f 100644 --- a/slices/generate_slice.go +++ b/slices/generate_slice.go @@ -70,6 +70,55 @@ func generateSliceOfBuiltIn[T bool | int8 | int16 | int32 | int64 | int | uint8 return } +// Creates a slice of []T up to a maximum size and populates its values with +// those created by the given generator. +// +// Parameters: +// - `size` - maximum size if non-negative; otherwise size unlimited; +// - `generator` - function that receives the given loop index, returning +// a result to be added into the result-slice, or one of the specific +// errors SkipOneElement (to skip a single element) or +// SkipRemainingElements (to skip all remaining elements), or another +// error to cause the operation to fail; +func GenerateSlice[T any](size int, generator func(index int) (result T, err error)) (result []T, err error) { + + result = make([]T, 0, size) + + var i int + + for { + if size == 0 { + break; + } else { + if size > 0 { + size-- + } + } + + value, err := generator(i) + + if err == nil { + + result = append(result, value) + } else { + + if SkipOneElement == err { + + } else if SkipRemainingElements == err { + + break + } else { + + return nil, err + } + } + + i++ + } + + return +} + // Creates a slice of []N up to a maximum size and populates its values with // those created by the given generator. // diff --git a/slices/generate_test.go b/slices/generate_test.go index 01d382c..bf9973d 100644 --- a/slices/generate_test.go +++ b/slices/generate_test.go @@ -154,3 +154,39 @@ func Test_GenerateSliceOfString_1_itoa_FROM_INDEX_EXCEPT_22(t *testing.T) { } } } + +func Test_GenerateSlice_1_itoa_FROM_INDEX_EXCEPT_27(t *testing.T) { + + req_len := 40 + ints, err := slices.GenerateSlice(req_len, func(index int) (s string, err error) { + if index == 27 { + return "", slices.SkipOneElement + } + + s = "[" + strconv.Itoa(index) + "]" + + return + }) + if err != nil { + + } else { + + if len(ints) != req_len-1 { + + t.Errorf("generated slice was required to be of length %d, but %d obtained", req_len, len(ints)) + } + + for i, v := range ints { + + n := i + if i >= 27 { + n++ + } + + if fmt.Sprintf("[%d]", n) != v { + + t.Errorf("element at index %d is expected to be %v, but is %v\n", i, 2*i, v) + } + } + } +} From 4da27fb0b34c2478772c761a545f5092c06d9a33 Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Sun, 15 Feb 2026 09:22:43 +1100 Subject: [PATCH 5/5] 0.10.0-beta2 --- NEWS.md | 16 +++++++++------- version.go | 2 +- version_test.go | 6 +++--- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/NEWS.md b/NEWS.md index 0c4fbf1..358a2e7 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,14 +1,16 @@ # ANGoLS - NEWS -| Date | News Item | -| ------------------- | ------------------------------------------------------------------------------- | -| 3rd January 2026 | Release of [**ANGoLS** 0.9.0](https://github.com/synesissoftware/ANGoLS/releases/tag/0.9.0) | +| Date | News Item | +| ------------------- | ---------------------------------------------------------------------------------------------------------- | +| 15th February 2026 | Release of [**ANGoLS** 0.10.0-beta2](https://github.com/synesissoftware/ANGoLS/releases/tag/0.10.0-beta2) | +| 7th February 2026 | Release of [**ANGoLS** 0.10.0-beta1](https://github.com/synesissoftware/ANGoLS/releases/tag/0.10.0-beta1) | +| 3rd January 2026 | Release of [**ANGoLS** 0.9.0](https://github.com/synesissoftware/ANGoLS/releases/tag/0.9.0) | | 15th September 2025 | Release of [**ANGoLS** 0.8.0-alpha1](https://github.com/synesissoftware/ANGoLS/releases/tag/0.8.0-alpha1) | -| 27th August 2025 | Release of [**ANGoLS** 0.7.0](https://github.com/synesissoftware/ANGoLS/releases/tag/0.7.0) | -| 20th August 2025 | Release of [**ANGoLS** 0.6.0](https://github.com/synesissoftware/ANGoLS/releases/tag/0.6.0) | -| 30th March 2019 | Release of [**ANGoLS** 0.5.0](https://github.com/synesissoftware/ANGoLS/releases/tag/0.5.0) | -| 11th March 2019 | Release of [**ANGoLS** 0.4.0](https://github.com/synesissoftware/ANGoLS/releases/tag/0.4.0) | +| 27th August 2025 | Release of [**ANGoLS** 0.7.0](https://github.com/synesissoftware/ANGoLS/releases/tag/0.7.0) | +| 20th August 2025 | Release of [**ANGoLS** 0.6.0](https://github.com/synesissoftware/ANGoLS/releases/tag/0.6.0) | +| 30th March 2019 | Release of [**ANGoLS** 0.5.0](https://github.com/synesissoftware/ANGoLS/releases/tag/0.5.0) | +| 11th March 2019 | Release of [**ANGoLS** 0.4.0](https://github.com/synesissoftware/ANGoLS/releases/tag/0.4.0) | | 1st March 2019 | initial commit | diff --git a/version.go b/version.go index ab275ac..8c780c1 100644 --- a/version.go +++ b/version.go @@ -15,7 +15,7 @@ const ( VersionMajor uint16 = 0 VersionMinor uint16 = 10 VersionPatch uint16 = 0 - VersionAB uint16 = 0x8001 + VersionAB uint16 = 0x8002 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 870d713..40721e7 100644 --- a/version_test.go +++ b/version_test.go @@ -12,7 +12,7 @@ const ( Expected_VersionMajor uint16 = 0 Expected_VersionMinor uint16 = 10 Expected_VersionPatch uint16 = 0 - Expected_VersionAB uint16 = 0x8001 + Expected_VersionAB uint16 = 0x8002 ) 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_000A_0000_8001), angols.Version) + require.Equal(t, uint64(0x0000_000A_0000_8002), angols.Version) } func Test_Version_String(t *testing.T) { - require.Equal(t, "0.10.0-beta1", angols.VersionString()) + require.Equal(t, "0.10.0-beta2", angols.VersionString()) }