diff --git a/CHANGES.md b/CHANGES.md index 63593c4..e2d271b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,15 @@ # **ANGoLS** Changes +## 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]()`; +* refactored `GenerateSliceOfUint()` in terms of `GenerateSliceOfInteger[T, U]()`; +* refactored `SkipOneElement` and `SkipRemainingElements`; + + ## 0.10.0-beta1 - 7th February 2026 * simple refactoring of `ASCIIToLower()` and `ASCIIToUpper()`; 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/slices/generate_slice.go b/slices/generate_slice.go index 37b6827..44e5f6f 100644 --- a/slices/generate_slice.go +++ b/slices/generate_slice.go @@ -4,115 +4,171 @@ /* * Created: 1st March 2019 - * Updated: 7th February 2026 + * Updated: 15th February 2026 */ package slices -import ( - "errors" -) +type skipOneElement struct { + s string +} -var SkipOneElement = errors.New("Skip one element") -var SkipRemainingElements = errors.New("Skip remaining elements") +func (e *skipOneElement) Error() string { + return e.s +} -// 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) { +type skipRemainingElements struct { + s string +} - result = make([]int, size) +func (e *skipRemainingElements) Error() string { + return e.s +} - if generator != nil { +// Causes generation of a single element to be skipped. +var SkipOneElement = &skipOneElement{s: "Skip one element"} - for i := 0; size != i; i++ { +// Causes generation of all remaining elements to be skipped. +var SkipRemainingElements = &skipRemainingElements{s: "Skip remaining elements"} - value, err := generator(i) +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) { - if err == nil { + result = make([]T, 0, size) - result[i] = value - } else { + var i int + + for { + if size == 0 { + break; + } else { + if size > 0 { + size-- + } + } + + value, err := generator(i) - if SkipOneElement == err { + if err == nil { - } else if SkipRemainingElements == err { + result = append(result, value) + } else { - break - } else { + if SkipOneElement == err { - return nil, err - } + } else if SkipRemainingElements == err { + + break + } else { + + 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) { +// 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-- + } + } - result = make([]uint, size) + value, err := generator(i) - if generator != nil { + if err == nil { - for i := 0; size != i; i++ { + result = append(result, value) + } else { - value, err := generator(i) + if SkipOneElement == err { - if err == nil { + } else if SkipRemainingElements == err { - result[i] = value + break } else { - if SkipOneElement == err { - - } else if SkipRemainingElements == err { - - 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 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 { +// 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) +} - result[i] = value - } else { +// 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) { - if SkipOneElement == err { + return GenerateSliceOfInteger(size, generator) +} - } else if SkipRemainingElements == 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) { - break - } else { + return GenerateSliceOfInteger(size, generator) +} - return nil, err - } - } - } - } +// 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) { - return + return generateSliceOfBuiltIn(size, generator) } /* ///////////////////////////// end of file //////////////////////////// */ diff --git a/slices/generate_test.go b/slices/generate_test.go index e021fa7..bf9973d 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,18 +26,20 @@ 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 }) + ints, err := slices.GenerateSliceOfInt(req_len, func(index int) (int, error) { + return 2 * index, nil + }) if err != nil { } else { @@ -44,23 +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 - ints, err := slices.GenerateSliceOfInt(req_len, func(index int) (int, error) { return 2 * index, nil }) + req_len := 100 + ints, err := slices.GenerateSliceOfInt(req_len, func(index int) (int, error) { + + 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)) } @@ -74,3 +88,105 @@ 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) + } + } + } +} + +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) + } + } + } +} 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()) }