Added:
* slicesx:
** Last
** LastIndex
This commit is contained in:
brent saner
2026-07-14 03:02:22 -04:00
parent c9f3e7a639
commit b85d328311
5 changed files with 284 additions and 2 deletions
+4
View File
@@ -0,0 +1,4 @@
/*
Package slicesx aims to extend functionality of the stdlib [slices] module.
*/
package slicesx
+43
View File
@@ -0,0 +1,43 @@
package slicesx
/*
Last returns the last item/element in slice s.
e will be the nil/zero value of the slice element type
if the slice length is 0.
*/
func Last[S ~[]E, E any](s S) (e E) {
var idx int = LastIndex(s)
if idx < 0 {
return
}
e = s[idx]
return
}
/*
LastIndex returns the index of the last element in slice s.
If s is empty, idx will be -1.
If s is nil, idx will be -2.
*/
func LastIndex[S ~[]E, E any](s S) (idx int) {
var l int = len(s)
idx = -2
if s != nil {
idx++
}
if l == 0 {
return
}
idx = l - 1
return
}
+235
View File
@@ -0,0 +1,235 @@
package slicesx
import (
"testing"
)
func TestLast(t *testing.T) {
var v any
var e any
var intSl []int
var strSl []string
var boolSl []bool
var anySl []any
/*
int
*/
// nil
v = Last(intSl)
e = 0
if v != e {
t.Errorf("%T %#v, expected %T %#v", v, v, e, e)
}
// empty
intSl = make([]int, 0)
v = Last(intSl)
if v != e { // still expect 0
t.Errorf("%T %#v, expected %T %#v", v, v, e, e)
}
// populated
intSl = []int{0, 1, 2, 3}
v = Last(intSl)
e = 3
if v != e {
t.Errorf("%T %#v, expected %T %#v", v, v, e, e)
}
/*
string
*/
// nil
v = Last(strSl)
e = ""
if v != e {
t.Errorf("%T %#v, expected %T %#v", v, v, e, e)
}
// empty
strSl = make([]string, 0)
v = Last(strSl)
if v != e { // still expect ""
t.Errorf("%T %#v, expected %T %#v", v, v, e, e)
}
// populated
strSl = []string{"a", "b", "c"}
v = Last(strSl)
e = "c"
if v != e {
t.Errorf("%T %#v, expected %T %#v", v, v, e, e)
}
/*
bool
*/
// nil
v = Last(boolSl)
e = false
if v != e {
t.Errorf("%T %#v, expected %T %#v", v, v, e, e)
}
// empty
boolSl = make([]bool, 0)
v = Last(boolSl)
if v != e { // still expect false
t.Errorf("%T %#v, expected %T %#v", v, v, e, e)
}
// populated
boolSl = []bool{true, false, true, false, true}
v = Last(boolSl)
e = true
if v != e {
t.Errorf("%T %#v, expected %T %#v", v, v, e, e)
}
/*
any/interface{}
*/
// nil
v = Last(anySl)
e = nil
if v != e {
t.Errorf("%T %#v, expected %T %#v", v, v, e, e)
}
// empty
anySl = make([]any, 0)
v = Last(anySl)
if v != e { // still expect nil
t.Errorf("%T %#v, expected %T %#v", v, v, e, e)
}
// populated
anySl = []any{3, true, "foo", "bar"}
v = Last(anySl)
e = "bar"
if v != e {
t.Errorf("%T %#v, expected %T %#v", v, v, e, e)
}
}
/*
this test only runs in Go 1.26+;
which lets you new() on values instead of just types.
commented out until req bumps to 1.26+ in go.mod.
*/
/*
func TestLastPtr(t *testing.T) {
var v any
var i *int
var s *string
var b *bool
var ptrIntSl []*int
var ptrStrSl []*string
var ptrBoolSl []*bool
//
// int
//
// nil
v = Last(ptrIntSl)
i = nil
if v != i {
t.Errorf("%T %#v, expected %T %#v", v, v, i, i)
}
// empty
ptrIntSl = make([]*int, 0)
v = Last(ptrIntSl)
if v != i { // still expect nil
t.Errorf("%T %#v, expected %T %#v", v, v, i, i)
}
// populated
ptrIntSl = []*int{new(0), new(1), new(2), new(3)}
v = Last(ptrIntSl)
i = ptrIntSl[len(ptrIntSl)-1]
if v != i {
t.Errorf("%T %#v, expected %T %#v", v, v, i, i)
}
//
// string
//
// nil
v = Last(ptrStrSl)
if v != s {
t.Errorf("%T %#v, expected %T %#v", v, v, s, s)
}
// empty
ptrStrSl = make([]*string, 0)
v = Last(ptrStrSl)
if v != s { // still expect nil
t.Errorf("%T %#v, expected %T %#v", v, v, s, s)
}
// populated
ptrStrSl = []*string{new("a"), new("b"), new("c")}
v = Last(ptrStrSl)
s = ptrStrSl[len(ptrStrSl)-1]
if v != s {
t.Errorf("%T %#v, expected %T %#v", v, v, s, s)
}
//
// bool
//
// nil
v = Last(ptrBoolSl)
if v != b {
t.Errorf("%T %#v, expected %T %#v", v, v, b, b)
}
// empty
ptrBoolSl = make([]*bool, 0)
v = Last(ptrBoolSl)
if v != b { // still expect nil
t.Errorf("%T %#v, expected %T %#v", v, v, b, b)
}
// populated
ptrBoolSl = []*bool{new(true), new(false), new(true), new(false), new(true)}
v = Last(ptrBoolSl)
b = ptrBoolSl[len(ptrBoolSl)-1]
if v != b {
t.Errorf("%T %#v, expected %T %#v", v, v, b, b)
}
}
*/
func TestLastIndex(t *testing.T) {
var e int
var v int
var s []string
e = -2
v = LastIndex(s)
if e != v {
t.Errorf("Got %d, expected %d", v, e)
}
e = -1
s = make([]string, 0)
v = LastIndex(s)
if e != v {
t.Errorf("Got %d, expected %d", v, e)
}
e = 0
s = []string{"a"}
v = LastIndex(s)
if e != v {
t.Errorf("Got %d, expected %d", v, e)
}
e = 1
s = []string{"a", "b"}
v = LastIndex(s)
if e != v {
t.Errorf("Got %d, expected %d", v, e)
}
e = 2
s = []string{"a", "b", "c"}
v = LastIndex(s)
if e != v {
t.Errorf("Got %d, expected %d", v, e)
}
}
+1 -1
View File
@@ -636,7 +636,7 @@ pre.rouge .gs {
<div class="details">
<span id="author" class="author">Brent Saner</span><br>
<span id="email" class="email"><a href="mailto:bts@square-r00t.net">bts@square-r00t.net</a></span><br>
<span id="revdate">Last rendered 2026-07-13 19:17:39 -0400</span>
<span id="revdate">Last rendered 2026-07-14 03:02:23 -0400</span>
</div>
<div id="toc" class="toc2">
<div id="toctitle">Table of Contents</div>
+1 -1
View File
@@ -6,7 +6,7 @@
<span id="author" class="author">Brent Saner</span>
<span id="email" class="email"><bts@square-r00t.net></span>
<span id="revdate">Last rendered 2026-07-13 19:17:43 -0400</span>
<span id="revdate">Last rendered 2026-07-14 03:02:27 -0400</span>
</div>