Skip to content

Commit

Permalink
Made set implementation thread-safe
Browse files Browse the repository at this point in the history
  • Loading branch information
TR-SLimey committed Dec 31, 2020
1 parent 33f73f5 commit df320b7
Showing 1 changed file with 17 additions and 11 deletions.
28 changes: 17 additions & 11 deletions sets.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
package gopoints

import "sync"

// A simple set implementation for 2D points as Go does not provide one. Uses map keys as the storage
// as they do not repeat and are unordered. The value used is a blank struct as it causes little
// to no overead due to its 0-byte size.
type PointSet struct {
// The actual data-storage part
data map[Point]struct{}
data sync.Map
// Keep track of whether the map has been initialised
dataPostInit bool
}

// Init initialises the set by creating the map which stores the data. This is called implicitly
// by all other methods of the set so does not need to be called explicitly. It does not overwrite
// the set if called multiple times.
func (set *PointSet) Init() {
// Only if the set is not already initialised in order to avoid accidentally removing data
if set.data == nil {
set.data = make(map[Point]struct{})
if !set.dataPostInit {
set.dataPostInit = true
set.data = sync.Map{}
}
}

Expand All @@ -23,7 +28,7 @@ func (set *PointSet) Add(point Point) {
// Automatically init the set if it's not initialised yet (check handled by Init())
set.Init()

set.data[point] = struct{}{}
set.data.Store(point, struct{}{})
}

// AddArray works much like Add but accepts a slice of points (poor naming) and adds each element of it to the set
Expand All @@ -41,7 +46,7 @@ func (set *PointSet) Remove(point Point) {
// Automatically init the set if it's not initialised yet (check handled by Init())
set.Init()

delete(set.data, point)
set.data.Delete(point)
}

// RemoveArray works much like Remove but accepts a slice of points (poor naming) and removes each element of it from the set
Expand All @@ -55,11 +60,11 @@ func (set *PointSet) RemoveArray(pointArray []Point) {
}

// CheckFor checks if a given point is in the set
func (set PointSet) CheckFor(point Point) bool {
func (set *PointSet) CheckFor(point Point) bool {
// Automatically init the set if it's not initialised yet (check handled by Init())
set.Init()

_, ok := set.data[point]
_, ok := set.data.Load(point)
return ok
}

Expand All @@ -74,14 +79,15 @@ func (set *PointSet) CheckForAll(points []Point) bool {
}

// AsArray returns the contents of the set as a slice
func (set PointSet) AsArray() []Point {
func (set *PointSet) AsArray() []Point {
// Automatically init the set if it's not initialised yet (check handled by Init())
set.Init()

// Convert the set to an array for easy access
arr := []Point{}
for point := range set.data {
arr = append(arr, point)
}
set.data.Range(func(key, value interface{}) bool {
arr = append(arr, key.(Point))
return true
})
return arr
}

0 comments on commit df320b7

Please sign in to comment.