safeslice

package module
v0.0.0-...-04945b0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 20, 2022 License: BSD-3-Clause Imports: 1 Imported by: 0

README

go-safeslice

PkgGoDev

SafeSlice is similar to a slice except it is safe for modification during range-based traversals.

This is achieved by guaranteeing that there are no changes made to allocations of slices returned by previous calls to Get. That is, only new calls to Get will observe the elements added, removed, or swapped, to the array before that call to Get.

IMPORTANT: See the following examples for safe iteration.

Installation

$ go get github.com/jabolopes/go-safeslice

You can use go get -u to update the package. If you are using Go modules, you can also just import the package and it will be automatically downloaded on the first compilation.

Examples

The Go language guarantees that the expression passed to range is evaluated only once. Therefore, the following iteration makes a single call to Get before the iteration begins. As such, the slice being traversed does not observe the added / removed / swapped elements.

a := NewSafeSlice()
for _, x := range a.Get() {
  a.Append(...)  // SAFE
}

a := NewSafeSlice()
for _, x := range a.Get() {
  a.Remove(0)  // SAFE
}

The following while loop calls Get multiple times, therefore the length of the array is varying between the loops. While this is correct, it's extremely inefficient because this is forcing a "snapshot" of the array on each call to the pair (Get, Remove), so don't do this.

a := NewSafeSlice()
for len(a.Get()) > 0 {
  a.Remove(0)  // INEFFICIENT; DON'T DO
}

The following iteration however is NOT safe because each call to Get observes the removed elements.

a := NewSafeSlice()
for i := 0; i < len(a.Get()); i++ {
  a.Remove(i)  // WRONG and UNSAFE
}

SafeSlice is not safe for concurrent use but it is safe for non-concurrent modification during traversal.

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type SafeSlice

type SafeSlice[T any] struct {
	// contains filtered or unexported fields
}

SafeSlice is similar to a slice except it is safe for modification during range-based traversals.

This is done by guaranteeing that there are no changes made to allocations of slices returned by previous calls to 'Get'. That is, only new calls to 'Get' will observe the elements added, removed, or swapped, to the array before that call to 'Get'.

IMPORTANT: See the following examples for safe iteration.

The Go language guarantees that the expression passed to 'range' is evaluated only once. Therefore, the following iteration makes a single call to 'Get' before the iteration begins. As such, the slice being traversed does not observe the added / removed / swapped elements.

a := NewSafeSlice()

for _, x := range a.Get() {
  a.Append(...)  // SAFE
}

a := NewSafeSlice()

for _, x := range a.Get() {
  a.Remove(0)  // SAFE
}

The following while loop calls 'Get' multiple times, therefore the length of the array is varying between the loops. While this is correct, it's extremely inefficient because this is forcing a 'snapshot' of the array on each call to the pair (Get, Remove), so don't do this.

a := NewSafeSlice()

for len(a.Get()) > 0 {
  a.Remove(0)  // INEFFICIENT; DON'T DO
}

The following iteration however is NOT safe because each call to 'Get' observes the removed elements.

a := NewSafeSlice()

for i := 0; i < len(a.Get()); i++ {
  a.Remove(i)  // WRONG and UNSAFE
}

This is not safe for concurrent use. This is safe for non-concurrent modification during traversal.

This performs the worst when the calls to 'Get' and 'Remove' are interleaved.

Example
a := safeslice.New[int]()
a.Append(1)
a.Append(2)
a.Append(3)

fmt.Printf("%v", a.Get())

for range a.Get() {
	a.Remove(0)
}
Output:

[1 2 3]

func New

func New[T any]() *SafeSlice[T]

func (*SafeSlice[T]) Append

func (s *SafeSlice[T]) Append(elem T)

Append adds a new element to the end of this. It is safe to call this during traversal.

func (*SafeSlice[T]) Get

func (s *SafeSlice[T]) Get() []T

Get returns a "snapshot" of the underlying data as a slice. This slice can be iterated and this SafeSlice can be modified during that iteration.

func (*SafeSlice[T]) Remove

func (s *SafeSlice[T]) Remove(index int)

Remove removes the element at the given index from this. It is safe to call this during traversal.

func (*SafeSlice[T]) Swap

func (s *SafeSlice[T]) Swap(i, j int)

Swap swaps the elements at the given indices.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL