mirror of
https://github.com/tursom/GoCollections.git
synced 2025-01-13 20:30:17 +08:00
impl ConcurrentLinkedStack and ConcurrentLinkedQueue
This commit is contained in:
parent
150fa1f04e
commit
561ff20adb
@ -5,10 +5,16 @@ import (
|
||||
"github.com/tursom/GoCollections/lang"
|
||||
)
|
||||
|
||||
type ArrayList[T lang.Object] struct {
|
||||
lang.BaseObject
|
||||
array []T
|
||||
}
|
||||
type (
|
||||
ArrayList[T lang.Object] struct {
|
||||
lang.BaseObject
|
||||
array []T
|
||||
}
|
||||
arrayListIterator[T lang.Object] struct {
|
||||
arrayList *ArrayList[T]
|
||||
index int
|
||||
}
|
||||
)
|
||||
|
||||
func NewArrayList[T lang.Object]() *ArrayList[T] {
|
||||
return NewArrayListByCapacity[T](16)
|
||||
@ -137,11 +143,6 @@ func (a *ArrayList[T]) RemoveLast() (T, exceptions.Exception) {
|
||||
return v, a.RemoveAt(a.Size() - 1)
|
||||
}
|
||||
|
||||
type arrayListIterator[T lang.Object] struct {
|
||||
arrayList *ArrayList[T]
|
||||
index int
|
||||
}
|
||||
|
||||
func (a *arrayListIterator[T]) HasNext() bool {
|
||||
return a.index < a.arrayList.Size()
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import (
|
||||
|
||||
type (
|
||||
Collection[T any] interface {
|
||||
Iterator() Iterator[T]
|
||||
Iterable[T]
|
||||
Size() int
|
||||
IsEmpty() bool
|
||||
Contains(element T) bool
|
||||
@ -17,13 +17,9 @@ type (
|
||||
}
|
||||
|
||||
MutableCollection[T any] interface {
|
||||
Iterator() Iterator[T]
|
||||
Size() int
|
||||
IsEmpty() bool
|
||||
Contains(element T) bool
|
||||
ContainsAll(c Collection[T]) bool
|
||||
Collection[T]
|
||||
MutableIterable[T]
|
||||
|
||||
MutableIterator() MutableIterator[T]
|
||||
Add(element T) bool
|
||||
Remove(element T) exceptions.Exception
|
||||
AddAll(c Collection[T]) bool
|
||||
@ -33,33 +29,15 @@ type (
|
||||
}
|
||||
|
||||
List[T any] interface {
|
||||
Iterator() Iterator[T]
|
||||
Size() int
|
||||
IsEmpty() bool
|
||||
Contains(element T) bool
|
||||
ContainsAll(c Collection[T]) bool
|
||||
Collection[T]
|
||||
|
||||
Get(index int) (T, exceptions.Exception)
|
||||
SubList(from, to int) List[T]
|
||||
}
|
||||
|
||||
MutableList[T any] interface {
|
||||
Iterator() Iterator[T]
|
||||
Size() int
|
||||
IsEmpty() bool
|
||||
Contains(element T) bool
|
||||
ContainsAll(c Collection[T]) bool
|
||||
|
||||
MutableIterator() MutableIterator[T]
|
||||
Add(element T) bool
|
||||
Remove(element T) exceptions.Exception
|
||||
AddAll(c Collection[T]) bool
|
||||
RemoveAll(c Collection[T]) bool
|
||||
RetainAll(c Collection[T]) bool
|
||||
Clear()
|
||||
|
||||
Get(index int) (T, exceptions.Exception)
|
||||
SubList(from, to int) List[T]
|
||||
List[T]
|
||||
MutableCollection[T]
|
||||
|
||||
Set(index int, element T) exceptions.Exception
|
||||
AddAtIndex(index int, element T) bool
|
||||
|
@ -3,157 +3,166 @@ package collections
|
||||
import (
|
||||
"github.com/tursom/GoCollections/exceptions"
|
||||
"github.com/tursom/GoCollections/lang"
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
"github.com/tursom/GoCollections/lang/atomic"
|
||||
)
|
||||
|
||||
type ConcurrentLinkedQueue[T lang.Object] struct {
|
||||
lang.BaseObject
|
||||
head *concurrentLinkedQueueNode[T]
|
||||
}
|
||||
type (
|
||||
ConcurrentLinkedQueueNode[T lang.Object] interface {
|
||||
Get() (T, exceptions.Exception)
|
||||
Remove() exceptions.Exception
|
||||
RemoveAndGet() (T, exceptions.Exception)
|
||||
}
|
||||
|
||||
func (c *ConcurrentLinkedQueue[T]) String() string {
|
||||
return String[T](c)
|
||||
}
|
||||
ConcurrentLinkedQueue[T lang.Object] struct {
|
||||
lang.BaseObject
|
||||
ConcurrentLinkedStack[T]
|
||||
end *concurrentLinkedStackNode[T]
|
||||
}
|
||||
|
||||
type concurrentLinkedQueueNode[T any] struct {
|
||||
value T
|
||||
prev *concurrentLinkedQueueNode[T]
|
||||
next *concurrentLinkedQueueNode[T]
|
||||
}
|
||||
concurrentLinkedQueueIterator[T lang.Object] struct {
|
||||
node *concurrentLinkedStackNode[T]
|
||||
queue *ConcurrentLinkedQueue[T]
|
||||
}
|
||||
)
|
||||
|
||||
type concurrentLinkedQueueIterator[T any] struct {
|
||||
head *concurrentLinkedQueueNode[T]
|
||||
node *concurrentLinkedQueueNode[T]
|
||||
func (q *ConcurrentLinkedQueue[T]) String() string {
|
||||
return String[T](q)
|
||||
}
|
||||
|
||||
func NewConcurrentLinkedQueue[T lang.Object]() *ConcurrentLinkedQueue[T] {
|
||||
head := &concurrentLinkedQueueNode[T]{}
|
||||
head.prev = head
|
||||
head.next = head
|
||||
return &ConcurrentLinkedQueue[T]{lang.NewBaseObject(), head}
|
||||
return &ConcurrentLinkedQueue[T]{}
|
||||
}
|
||||
|
||||
func (c *ConcurrentLinkedQueue[T]) Iterator() Iterator[T] {
|
||||
return c.MutableIterator()
|
||||
func (q *ConcurrentLinkedQueue[T]) Iterator() Iterator[T] {
|
||||
return q.MutableIterator()
|
||||
}
|
||||
|
||||
func (c *ConcurrentLinkedQueue[T]) Push(element T) exceptions.Exception {
|
||||
newNode := &concurrentLinkedQueueNode[T]{element, c.head.prev, c.head}
|
||||
p := (*unsafe.Pointer)(unsafe.Pointer(&c.head.prev))
|
||||
for !atomic.CompareAndSwapPointer(p, unsafe.Pointer(&*newNode.prev), unsafe.Pointer(newNode)) {
|
||||
newNode.prev = c.head.prev
|
||||
func (q *ConcurrentLinkedQueue[T]) Offer(element T) exceptions.Exception {
|
||||
_, err := q.offerAndGetNode(element)
|
||||
return err
|
||||
}
|
||||
|
||||
func (q *ConcurrentLinkedQueue[T]) OfferAndGetNode(element T) (ConcurrentLinkedQueueNode[T], exceptions.Exception) {
|
||||
newNode, err := q.offerAndGetNode(element)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
atomic.CompareAndSwapPointer(
|
||||
(*unsafe.Pointer)(unsafe.Pointer(&newNode.prev.next)),
|
||||
unsafe.Pointer(&*c.head),
|
||||
unsafe.Pointer(newNode),
|
||||
)
|
||||
return nil
|
||||
return &concurrentLinkedQueueIterator[T]{queue: q, node: newNode}, nil
|
||||
}
|
||||
|
||||
func (c *ConcurrentLinkedQueue[T]) Offer() (T, exceptions.Exception) {
|
||||
next := c.head.next
|
||||
if next == c.head {
|
||||
return lang.Nil[T](), exceptions.NewIndexOutOfBound("", nil)
|
||||
func (q *ConcurrentLinkedQueue[T]) offerAndGetNode(element T) (*concurrentLinkedStackNode[T], exceptions.Exception) {
|
||||
newNode := &concurrentLinkedStackNode[T]{value: element}
|
||||
q.size.Add(1)
|
||||
|
||||
var next **concurrentLinkedStackNode[T]
|
||||
ref := q.end
|
||||
switch {
|
||||
case ref == nil:
|
||||
next = &q.head
|
||||
default:
|
||||
next = &ref.next
|
||||
}
|
||||
|
||||
p := (*unsafe.Pointer)(unsafe.Pointer(&next.next.prev))
|
||||
|
||||
if !next.removeNode(p) {
|
||||
next = c.head.next
|
||||
p = (*unsafe.Pointer)(unsafe.Pointer(&next.prev))
|
||||
if next == nil {
|
||||
return lang.Nil[T](), exceptions.NewIndexOutOfBound("", nil)
|
||||
for !atomic.CompareAndSwapPointer(next, nil, newNode) {
|
||||
if ref == nil || ref.next == nil {
|
||||
next = &q.head
|
||||
ref = q.head
|
||||
} else {
|
||||
for ref.next != nil {
|
||||
ref = ref.next
|
||||
}
|
||||
next = &ref.next
|
||||
}
|
||||
}
|
||||
|
||||
return next.value, nil
|
||||
q.end = newNode
|
||||
return newNode, nil
|
||||
}
|
||||
|
||||
func (node *concurrentLinkedQueueNode[T]) removeNode(p *unsafe.Pointer) bool {
|
||||
if p == nil {
|
||||
p = (*unsafe.Pointer)(unsafe.Pointer(&node.next.prev))
|
||||
}
|
||||
if !atomic.CompareAndSwapPointer(p, unsafe.Pointer(node), unsafe.Pointer(&*node.prev)) {
|
||||
return false
|
||||
}
|
||||
atomic.CompareAndSwapPointer(
|
||||
(*unsafe.Pointer)(unsafe.Pointer(&node.prev.next)),
|
||||
unsafe.Pointer(node),
|
||||
unsafe.Pointer(&*node.next),
|
||||
)
|
||||
return true
|
||||
func (q *ConcurrentLinkedQueue[T]) Poll() (T, exceptions.Exception) {
|
||||
return q.Pop()
|
||||
}
|
||||
|
||||
func (c *ConcurrentLinkedQueue[T]) MutableIterator() MutableIterator[T] {
|
||||
return &concurrentLinkedQueueIterator[T]{c.head, c.head}
|
||||
func (q *ConcurrentLinkedQueue[T]) MutableIterator() MutableIterator[T] {
|
||||
return &concurrentLinkedQueueIterator[T]{node: q.head}
|
||||
}
|
||||
|
||||
func (c *concurrentLinkedQueueIterator[T]) HasNext() bool {
|
||||
return c.node.next != c.head
|
||||
func (q *ConcurrentLinkedQueue[T]) Size() int {
|
||||
return int(q.size.Load())
|
||||
}
|
||||
|
||||
func (c *concurrentLinkedQueueIterator[T]) Next() (T, exceptions.Exception) {
|
||||
c.node = c.node.next
|
||||
if c.node == c.head {
|
||||
return lang.Nil[T](), exceptions.NewIndexOutOfBound("", nil)
|
||||
}
|
||||
return c.node.value, nil
|
||||
func (q *ConcurrentLinkedQueue[T]) IsEmpty() bool {
|
||||
return q.head == nil
|
||||
}
|
||||
|
||||
func (c *concurrentLinkedQueueIterator[T]) Remove() exceptions.Exception {
|
||||
if c.node == c.head {
|
||||
return exceptions.NewIndexOutOfBound("", nil)
|
||||
}
|
||||
c.node.removeNode(nil)
|
||||
c.node = c.node.prev
|
||||
return nil
|
||||
func (q *ConcurrentLinkedQueue[T]) Contains(element T) bool {
|
||||
return Contains[T](q, element)
|
||||
}
|
||||
|
||||
func (c *ConcurrentLinkedQueue[T]) Size() int {
|
||||
size, err := Size[T](c)
|
||||
exceptions.Print(err)
|
||||
return size
|
||||
func (q *ConcurrentLinkedQueue[T]) ContainsAll(collection Collection[T]) bool {
|
||||
return ContainsAll[T](q, collection)
|
||||
}
|
||||
|
||||
func (c *ConcurrentLinkedQueue[T]) IsEmpty() bool {
|
||||
return c.head.next == c.head
|
||||
}
|
||||
|
||||
func (c *ConcurrentLinkedQueue[T]) Contains(element T) bool {
|
||||
return Contains[T](c, element)
|
||||
}
|
||||
|
||||
func (c *ConcurrentLinkedQueue[T]) ContainsAll(collection Collection[T]) bool {
|
||||
return ContainsAll[T](c, collection)
|
||||
}
|
||||
|
||||
func (c *ConcurrentLinkedQueue[T]) Add(element T) bool {
|
||||
exception := c.Push(element)
|
||||
func (q *ConcurrentLinkedQueue[T]) Add(element T) bool {
|
||||
exception := q.Push(element)
|
||||
exceptions.Print(exception)
|
||||
return exception == nil
|
||||
}
|
||||
|
||||
func (c *ConcurrentLinkedQueue[T]) Remove(element T) exceptions.Exception {
|
||||
return Remove[T](c, element)
|
||||
func (q *ConcurrentLinkedQueue[T]) Remove(element T) exceptions.Exception {
|
||||
return Remove[T](q, element)
|
||||
}
|
||||
|
||||
func (c *ConcurrentLinkedQueue[T]) AddAll(collection Collection[T]) bool {
|
||||
return AddAll[T](c, collection)
|
||||
func (q *ConcurrentLinkedQueue[T]) AddAll(collection Collection[T]) bool {
|
||||
return AddAll[T](q, collection)
|
||||
}
|
||||
|
||||
func (c *ConcurrentLinkedQueue[T]) RemoveAll(collection Collection[T]) bool {
|
||||
return RemoveAll[T](c, collection)
|
||||
func (q *ConcurrentLinkedQueue[T]) RemoveAll(collection Collection[T]) bool {
|
||||
return RemoveAll[T](q, collection)
|
||||
}
|
||||
|
||||
func (c *ConcurrentLinkedQueue[T]) RetainAll(collection Collection[T]) bool {
|
||||
return RetainAll[T](c, collection)
|
||||
func (q *ConcurrentLinkedQueue[T]) RetainAll(collection Collection[T]) bool {
|
||||
return RetainAll[T](q, collection)
|
||||
}
|
||||
|
||||
func (c *ConcurrentLinkedQueue[T]) Clear() {
|
||||
head := &concurrentLinkedQueueNode[T]{}
|
||||
head.prev = head
|
||||
head.next = head
|
||||
c.head = head
|
||||
func (q *ConcurrentLinkedQueue[T]) Clear() {
|
||||
q.head = nil
|
||||
q.end = nil
|
||||
q.size.Store(0)
|
||||
}
|
||||
|
||||
func (i *concurrentLinkedQueueIterator[T]) HasNext() bool {
|
||||
for i.node != nil && i.node.deleted {
|
||||
i.node = i.node.next
|
||||
}
|
||||
return i.node != nil
|
||||
}
|
||||
|
||||
func (i *concurrentLinkedQueueIterator[T]) Next() (T, exceptions.Exception) {
|
||||
value, err := i.Get()
|
||||
i.node = i.node.next
|
||||
for i.node != nil && i.node.deleted {
|
||||
i.node = i.node.next
|
||||
}
|
||||
return value, err
|
||||
}
|
||||
|
||||
func (i *concurrentLinkedQueueIterator[T]) Get() (T, exceptions.Exception) {
|
||||
return (*i.node).value, nil
|
||||
}
|
||||
|
||||
func (i *concurrentLinkedQueueIterator[T]) Remove() exceptions.Exception {
|
||||
_, err := i.RemoveAndGet()
|
||||
return err
|
||||
}
|
||||
|
||||
func (i *concurrentLinkedQueueIterator[T]) RemoveAndGet() (T, exceptions.Exception) {
|
||||
if i.node == nil {
|
||||
return lang.Nil[T](), nil
|
||||
}
|
||||
load := i.node
|
||||
load.deleted = true
|
||||
i.queue.size.Add(-1)
|
||||
i.queue.deleted.Add(1)
|
||||
i.queue.CleanDeleted()
|
||||
i.node = load.next
|
||||
return load.value, nil
|
||||
}
|
||||
|
97
collections/ConcurrentLinkedQueue_test.go
Normal file
97
collections/ConcurrentLinkedQueue_test.go
Normal file
@ -0,0 +1,97 @@
|
||||
package collections
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/tursom/GoCollections/exceptions"
|
||||
"github.com/tursom/GoCollections/lang"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type data struct {
|
||||
lang.BaseObject
|
||||
id int
|
||||
index int
|
||||
}
|
||||
|
||||
func (d *data) String() string {
|
||||
return fmt.Sprintf("(%d,%d)", d.id, d.index)
|
||||
}
|
||||
|
||||
func TestConcurrentLinkedQueue_NodeSize(t *testing.T) {
|
||||
fmt.Println(unsafe.Alignof(concurrentLinkedStackNode[*data]{}))
|
||||
fmt.Println(unsafe.Sizeof(concurrentLinkedStackNode[*data]{}))
|
||||
}
|
||||
|
||||
func TestConcurrentLinkedQueue_Push(t *testing.T) {
|
||||
queue := NewConcurrentLinkedQueue[*data]()
|
||||
cond := sync.WaitGroup{}
|
||||
cond.Add(1)
|
||||
for i := 0; i < 10; i++ {
|
||||
id := i
|
||||
go func() {
|
||||
cond.Wait()
|
||||
for i := 0; i < 100; i++ {
|
||||
_ = queue.Offer(&data{id: id, index: i})
|
||||
}
|
||||
}()
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
cond.Done()
|
||||
time.Sleep(time.Second)
|
||||
fmt.Println(queue)
|
||||
}
|
||||
|
||||
func TestConcurrentLinkedQueue_ThreadSafe(t *testing.T) {
|
||||
times := 400000
|
||||
queue := NewConcurrentLinkedQueue[*data]()
|
||||
for i := 0; i < 100; i++ {
|
||||
id := i
|
||||
go func() {
|
||||
//nodes := make([]ConcurrentLinkedQueueNode[*data], 0)
|
||||
for j := 0; j < times; j++ {
|
||||
_ = queue.Offer(&data{id: id, index: j})
|
||||
//node, _ := queue.OfferAndGetNode(&data{id: id, index: j})
|
||||
//nodes = append(nodes, node)
|
||||
//fmt.Println(queue)
|
||||
}
|
||||
//time.Sleep(time.Second * 1)
|
||||
fmt.Println(queue.Size())
|
||||
//for _, node := range nodes {
|
||||
// exceptions.Exec0r0(node.Remove)
|
||||
//}
|
||||
for j := 0; j < times; j++ {
|
||||
offer, _ := queue.Poll()
|
||||
if offer == nil {
|
||||
panic("offer is nil")
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
time.Sleep(time.Second * 10)
|
||||
if queue.Size() != 0 {
|
||||
t.Fatalf(fmt.Sprintf("queue remain %d element, is not thread safe", queue.Size()))
|
||||
}
|
||||
//for !queue.IsEmpty() {
|
||||
// fmt.Println(queue.Offer())
|
||||
//}
|
||||
}
|
||||
|
||||
func Test_concurrentLinkedQueueIterator_Remove(t *testing.T) {
|
||||
queue := NewConcurrentLinkedQueue[lang.Int]()
|
||||
nodes := make([]ConcurrentLinkedQueueNode[lang.Int], 0)
|
||||
for i := 0; i < 1000; i++ {
|
||||
node, _ := queue.OfferAndGetNode(lang.Int(i))
|
||||
nodes = append(nodes, node)
|
||||
//fmt.Println(queue)
|
||||
}
|
||||
for _, node := range nodes {
|
||||
fmt.Println(exceptions.Exec0r1(node.RemoveAndGet))
|
||||
}
|
||||
if queue.Size() != 0 {
|
||||
t.Fatalf(fmt.Sprintf("queue remain %d element, is not thread safe", queue.Size()))
|
||||
}
|
||||
}
|
@ -3,89 +3,146 @@ package collections
|
||||
import (
|
||||
"github.com/tursom/GoCollections/exceptions"
|
||||
"github.com/tursom/GoCollections/lang"
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
"github.com/tursom/GoCollections/lang/atomic"
|
||||
)
|
||||
|
||||
type ConcurrentLinkedStack[T any] struct {
|
||||
lang.BaseObject
|
||||
head *concurrentLinkedStackNode[T]
|
||||
p *unsafe.Pointer
|
||||
}
|
||||
|
||||
func (c ConcurrentLinkedStack[T]) String() string {
|
||||
return String[T](c)
|
||||
}
|
||||
|
||||
type concurrentLinkedStackNode[T any] struct {
|
||||
value T
|
||||
next *concurrentLinkedStackNode[T]
|
||||
}
|
||||
|
||||
type concurrentLinkedStackIterator[T any] struct {
|
||||
node *concurrentLinkedStackNode[T]
|
||||
prev *concurrentLinkedStackNode[T]
|
||||
}
|
||||
|
||||
func NewConcurrentLinkedStack[T any]() *ConcurrentLinkedStack[T] {
|
||||
head := &concurrentLinkedStackNode[T]{}
|
||||
return &ConcurrentLinkedStack[T]{lang.NewBaseObject(), head, (*unsafe.Pointer)(unsafe.Pointer(&head.next))}
|
||||
}
|
||||
|
||||
func (c ConcurrentLinkedStack[T]) Iterator() Iterator[T] {
|
||||
return c.MutableIterator()
|
||||
}
|
||||
|
||||
func (c *ConcurrentLinkedStack[T]) Push(element T) exceptions.Exception {
|
||||
newNode := &concurrentLinkedStackNode[T]{element, c.head.next}
|
||||
np := unsafe.Pointer(newNode)
|
||||
for !atomic.CompareAndSwapPointer(c.p, unsafe.Pointer(&*newNode.next), np) {
|
||||
type (
|
||||
ConcurrentLinkedStack[T lang.Object] struct {
|
||||
lang.BaseObject
|
||||
size atomic.Int32
|
||||
deleted atomic.Int32
|
||||
head *concurrentLinkedStackNode[T]
|
||||
}
|
||||
|
||||
concurrentLinkedStackNode[T any] struct {
|
||||
deleted bool
|
||||
next *concurrentLinkedStackNode[T]
|
||||
value T
|
||||
}
|
||||
|
||||
concurrentLinkedStackIterator[T lang.Object] struct {
|
||||
node *concurrentLinkedStackNode[T]
|
||||
stack *ConcurrentLinkedStack[T]
|
||||
}
|
||||
)
|
||||
|
||||
func (s *ConcurrentLinkedStack[T]) String() string {
|
||||
return String[T](s)
|
||||
}
|
||||
|
||||
func NewConcurrentLinkedStack[T lang.Object]() *ConcurrentLinkedStack[T] {
|
||||
return &ConcurrentLinkedStack[T]{}
|
||||
}
|
||||
|
||||
func (s *ConcurrentLinkedStack[T]) Iterator() Iterator[T] {
|
||||
return s.MutableIterator()
|
||||
}
|
||||
|
||||
func (s *ConcurrentLinkedStack[T]) Push(element T) exceptions.Exception {
|
||||
newNode := &concurrentLinkedStackNode[T]{value: element, next: s.head}
|
||||
for !atomic.CompareAndSwapPointer(&s.head, newNode.next, newNode) {
|
||||
newNode.next = s.head
|
||||
}
|
||||
s.size.Add(1)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ConcurrentLinkedStack[T]) Pop() (T, exceptions.Exception) {
|
||||
next := c.head.next
|
||||
if next == nil {
|
||||
func (s *ConcurrentLinkedStack[T]) Pop() (T, exceptions.Exception) {
|
||||
node := s.head
|
||||
for node != nil && (!atomic.CompareAndSwapPointer(&s.head, node, node.next) || node.deleted) {
|
||||
node = s.head
|
||||
}
|
||||
if node == nil {
|
||||
return lang.Nil[T](), exceptions.NewIndexOutOfBound("", nil)
|
||||
}
|
||||
|
||||
p := (*unsafe.Pointer)(unsafe.Pointer(&c.head.next))
|
||||
s.size.Add(-1)
|
||||
return node.value, nil
|
||||
}
|
||||
|
||||
if !atomic.CompareAndSwapPointer(p, unsafe.Pointer(&*next), unsafe.Pointer(&*next.next)) {
|
||||
next = c.head.next
|
||||
if next == nil {
|
||||
return lang.Nil[T](), exceptions.NewIndexOutOfBound("", nil)
|
||||
func (s *ConcurrentLinkedStack[T]) CleanDeleted() {
|
||||
if s.deleted.Load() <= s.size.Load() {
|
||||
return
|
||||
}
|
||||
s.deleted.Store(0)
|
||||
node := &s.head
|
||||
for node != nil && *node != nil {
|
||||
if (*node).deleted {
|
||||
atomic.CompareAndSwapPointer(node, *node, (*node).next)
|
||||
} else {
|
||||
node = &(*node).next
|
||||
}
|
||||
}
|
||||
|
||||
return next.value, nil
|
||||
}
|
||||
|
||||
func (c *ConcurrentLinkedStack[T]) MutableIterator() MutableIterator[T] {
|
||||
return &concurrentLinkedStackIterator[T]{c.head, nil}
|
||||
func (s *ConcurrentLinkedStack[T]) Size() int {
|
||||
return int(s.size.Load())
|
||||
}
|
||||
|
||||
func (c *concurrentLinkedStackIterator[T]) HasNext() bool {
|
||||
return c.node.next != nil
|
||||
func (s *ConcurrentLinkedStack[T]) IsEmpty() bool {
|
||||
return s.head == nil
|
||||
}
|
||||
|
||||
func (c *concurrentLinkedStackIterator[T]) Next() (T, exceptions.Exception) {
|
||||
c.prev = c.node
|
||||
c.node = c.node.next
|
||||
if c.node == nil {
|
||||
func (s *ConcurrentLinkedStack[T]) Contains(element T) bool {
|
||||
return Contains[T](s, element)
|
||||
}
|
||||
|
||||
func (s *ConcurrentLinkedStack[T]) ContainsAll(c Collection[T]) bool {
|
||||
return ContainsAll[T](s, c)
|
||||
}
|
||||
|
||||
func (s *ConcurrentLinkedStack[T]) Add(element T) bool {
|
||||
exception := s.Push(element)
|
||||
exceptions.Print(exception)
|
||||
return exception == nil
|
||||
}
|
||||
|
||||
func (s *ConcurrentLinkedStack[T]) Remove(element T) exceptions.Exception {
|
||||
return Remove[T](s, element)
|
||||
}
|
||||
|
||||
func (s *ConcurrentLinkedStack[T]) AddAll(c Collection[T]) bool {
|
||||
return AddAll[T](s, c)
|
||||
}
|
||||
|
||||
func (s *ConcurrentLinkedStack[T]) RemoveAll(c Collection[T]) bool {
|
||||
return RemoveAll[T](s, c)
|
||||
}
|
||||
|
||||
func (s *ConcurrentLinkedStack[T]) RetainAll(c Collection[T]) bool {
|
||||
return RetainAll[T](s, c)
|
||||
}
|
||||
|
||||
func (s *ConcurrentLinkedStack[T]) Clear() {
|
||||
s.head = nil
|
||||
s.size.Store(0)
|
||||
}
|
||||
|
||||
func (s *ConcurrentLinkedStack[T]) MutableIterator() MutableIterator[T] {
|
||||
return &concurrentLinkedStackIterator[T]{s.head, nil}
|
||||
}
|
||||
|
||||
func (i *concurrentLinkedStackIterator[T]) HasNext() bool {
|
||||
return i.node.next != nil
|
||||
}
|
||||
|
||||
func (i *concurrentLinkedStackIterator[T]) Next() (T, exceptions.Exception) {
|
||||
if i.node == nil {
|
||||
return lang.Nil[T](), exceptions.NewIndexOutOfBound("", nil)
|
||||
}
|
||||
return c.node.value, nil
|
||||
value := i.node.value
|
||||
i.node = i.node.next
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (c *concurrentLinkedStackIterator[T]) Remove() exceptions.Exception {
|
||||
if c.node == nil {
|
||||
func (i *concurrentLinkedStackIterator[T]) Remove() exceptions.Exception {
|
||||
if i.node == nil {
|
||||
return exceptions.NewIndexOutOfBound("", nil)
|
||||
}
|
||||
next := c.node.next
|
||||
|
||||
p := (*unsafe.Pointer)(unsafe.Pointer(&c.prev.next))
|
||||
atomic.CompareAndSwapPointer(p, unsafe.Pointer(&*c.node), unsafe.Pointer(&*next))
|
||||
i.node.deleted = true
|
||||
i.node = i.node.next
|
||||
i.stack.size.Add(-1)
|
||||
i.stack.deleted.Add(1)
|
||||
i.stack.CleanDeleted()
|
||||
return nil
|
||||
}
|
||||
|
126
collections/CopyOnWriteList.go
Normal file
126
collections/CopyOnWriteList.go
Normal file
@ -0,0 +1,126 @@
|
||||
package collections
|
||||
|
||||
import (
|
||||
"github.com/tursom/GoCollections/exceptions"
|
||||
"github.com/tursom/GoCollections/lang"
|
||||
)
|
||||
|
||||
type (
|
||||
CopyOnWriteList[E lang.Object] struct {
|
||||
lang.BaseObject
|
||||
arr []E
|
||||
}
|
||||
|
||||
copyOnWriteListIterator[E lang.Object] struct {
|
||||
lang.BaseObject
|
||||
list *CopyOnWriteList[E]
|
||||
arr []E
|
||||
index int
|
||||
}
|
||||
)
|
||||
|
||||
func (l *CopyOnWriteList[E]) Iterator() Iterator[E] {
|
||||
return l.MutableIterator()
|
||||
}
|
||||
|
||||
func (l *CopyOnWriteList[E]) Size() int {
|
||||
return len(l.arr)
|
||||
}
|
||||
|
||||
func (l *CopyOnWriteList[E]) IsEmpty() bool {
|
||||
return l.Size() == 0
|
||||
}
|
||||
|
||||
func (l *CopyOnWriteList[E]) Contains(element E) bool {
|
||||
return Contains[E](l, element)
|
||||
}
|
||||
|
||||
func (l *CopyOnWriteList[E]) ContainsAll(c Collection[E]) bool {
|
||||
return ContainsAll[E](l, c)
|
||||
}
|
||||
|
||||
func (l *CopyOnWriteList[E]) MutableIterator() MutableIterator[E] {
|
||||
return ©OnWriteListIterator[E]{
|
||||
list: l,
|
||||
arr: l.arr,
|
||||
index: 0,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *CopyOnWriteList[E]) Add(element E) bool {
|
||||
l.arr = append(l.arr, element)
|
||||
return true
|
||||
}
|
||||
|
||||
func (l *CopyOnWriteList[E]) Remove(element E) exceptions.Exception {
|
||||
return Remove[E](l, element)
|
||||
}
|
||||
|
||||
func (l *CopyOnWriteList[E]) AddAll(c Collection[E]) bool {
|
||||
_ = Loop[E](c, func(element E) exceptions.Exception {
|
||||
l.arr = append(l.arr, element)
|
||||
return nil
|
||||
})
|
||||
return true
|
||||
}
|
||||
|
||||
func (l *CopyOnWriteList[E]) RemoveAll(c Collection[E]) bool {
|
||||
return RemoveAll[E](l, c)
|
||||
}
|
||||
|
||||
func (l *CopyOnWriteList[E]) RetainAll(c Collection[E]) bool {
|
||||
return RetainAll[E](l, c)
|
||||
}
|
||||
|
||||
func (l *CopyOnWriteList[E]) Clear() {
|
||||
l.arr = make([]E, 0)
|
||||
}
|
||||
|
||||
func (l *CopyOnWriteList[E]) Get(index int) (E, exceptions.Exception) {
|
||||
if index < 0 || index >= l.Size() {
|
||||
return lang.Nil[E](), exceptions.NewIndexOutOfBound("", nil)
|
||||
}
|
||||
return l.arr[index], nil
|
||||
}
|
||||
|
||||
func (l *CopyOnWriteList[E]) SubList(from, to int) List[E] {
|
||||
return l.SubList(from, to)
|
||||
}
|
||||
|
||||
func (l *CopyOnWriteList[E]) Set(index int, element E) exceptions.Exception {
|
||||
if index < 0 || index >= l.Size() {
|
||||
return exceptions.NewIndexOutOfBound("", nil)
|
||||
}
|
||||
l.arr[index] = element
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *CopyOnWriteList[E]) AddAtIndex(index int, element E) bool {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (l *CopyOnWriteList[E]) RemoveAt(index int) exceptions.Exception {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (l *CopyOnWriteList[E]) SubMutableList(from, to int) MutableList[E] {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (c *copyOnWriteListIterator[E]) HasNext() bool {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (c *copyOnWriteListIterator[E]) Next() (E, exceptions.Exception) {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (c *copyOnWriteListIterator[E]) Remove() exceptions.Exception {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
}
|
@ -13,13 +13,12 @@ type Iterable[T any] interface {
|
||||
}
|
||||
|
||||
type MutableIterator[T any] interface {
|
||||
HasNext() bool
|
||||
Next() (T, exceptions.Exception)
|
||||
Iterator[T]
|
||||
Remove() exceptions.Exception
|
||||
}
|
||||
|
||||
type MutableIterable[T any] interface {
|
||||
Iterator() Iterator[T]
|
||||
Iterable[T]
|
||||
MutableIterator() MutableIterator[T]
|
||||
}
|
||||
|
||||
|
@ -6,11 +6,8 @@ import (
|
||||
)
|
||||
|
||||
type Queue[T lang.Object] interface {
|
||||
// Iterator MutableIterable
|
||||
Iterator() Iterator[T]
|
||||
// MutableIterator MutableIterable
|
||||
MutableIterator() *linkedListIterator[T]
|
||||
MutableIterable[T]
|
||||
|
||||
Push(element T) exceptions.Exception
|
||||
Offer() (T, exceptions.Exception)
|
||||
Offer(element T) exceptions.Exception
|
||||
Poll() (T, exceptions.Exception)
|
||||
}
|
||||
|
@ -3,10 +3,7 @@ package collections
|
||||
import "github.com/tursom/GoCollections/exceptions"
|
||||
|
||||
type Stack[T any] interface {
|
||||
// Iterator MutableIterable
|
||||
Iterator() Iterator[T]
|
||||
// MutableIterator MutableIterable
|
||||
MutableIterator() MutableIterator[T]
|
||||
MutableIterable[T]
|
||||
|
||||
Push(element T) exceptions.Exception
|
||||
Pop() (T, exceptions.Exception)
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
type Exception interface {
|
||||
Cause() Exception
|
||||
Error() string
|
||||
ErrorMessage() string
|
||||
StackTrace() []StackTrace
|
||||
PrintStackTrace()
|
||||
PrintStackTraceTo(writer io.Writer)
|
||||
@ -46,7 +47,7 @@ func BuildStackTraceByArray(builder *strings.Builder, trace []StackTrace) {
|
||||
}
|
||||
|
||||
func BuildStackTrace(builder *strings.Builder, e Exception, exceptionMsg string) {
|
||||
builder.WriteString(fmt.Sprintln(exceptionMsg, e.Error()))
|
||||
builder.WriteString(fmt.Sprintln(exceptionMsg, e.ErrorMessage()))
|
||||
if e.StackTrace() == nil {
|
||||
return
|
||||
}
|
||||
|
@ -60,6 +60,10 @@ func (o RuntimeException) Error() string {
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
func (o RuntimeException) ErrorMessage() string {
|
||||
return o.exceptionMessage
|
||||
}
|
||||
|
||||
func (o RuntimeException) StackTrace() []StackTrace {
|
||||
return o.stackTrace
|
||||
}
|
||||
|
@ -32,10 +32,10 @@ func Cast[T any](v any) T {
|
||||
}
|
||||
}
|
||||
|
||||
func ForceCast[T any](v *any) T {
|
||||
func ForceCast[T any](v unsafe.Pointer) T {
|
||||
if v == nil {
|
||||
return Nil[T]()
|
||||
} else {
|
||||
return Cast[T](unsafe.Pointer(v))
|
||||
return Cast[T](v)
|
||||
}
|
||||
}
|
||||
|
37
lang/atomic/Bool.go
Normal file
37
lang/atomic/Bool.go
Normal file
@ -0,0 +1,37 @@
|
||||
package atomic
|
||||
|
||||
type Bool struct {
|
||||
i Int32
|
||||
}
|
||||
|
||||
func (v *Bool) Load() (val bool) {
|
||||
return v.i.Load() != 0
|
||||
}
|
||||
|
||||
func (v *Bool) Store(val bool) {
|
||||
if val {
|
||||
v.i.Store(1)
|
||||
} else {
|
||||
v.i.Store(0)
|
||||
}
|
||||
}
|
||||
|
||||
func (v *Bool) Swap(new bool) (old bool) {
|
||||
n := int32(0)
|
||||
if new {
|
||||
n = 1
|
||||
}
|
||||
return v.i.Swap(n) != 0
|
||||
}
|
||||
|
||||
func (v *Bool) CompareAndSwap(old, new bool) (swapped bool) {
|
||||
o := int32(0)
|
||||
if old {
|
||||
o = 1
|
||||
}
|
||||
n := int32(0)
|
||||
if new {
|
||||
n = 1
|
||||
}
|
||||
return v.i.CompareAndSwap(o, n)
|
||||
}
|
29
lang/atomic/Int32.go
Normal file
29
lang/atomic/Int32.go
Normal file
@ -0,0 +1,29 @@
|
||||
package atomic
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
type Int32 struct {
|
||||
i int32
|
||||
}
|
||||
|
||||
func (v *Int32) Load() (val int32) {
|
||||
return atomic.LoadInt32(&v.i)
|
||||
}
|
||||
|
||||
func (v *Int32) Store(val int32) {
|
||||
atomic.StoreInt32(&v.i, val)
|
||||
}
|
||||
|
||||
func (v *Int32) Swap(new int32) (old int32) {
|
||||
return atomic.SwapInt32(&v.i, new)
|
||||
}
|
||||
|
||||
func (v *Int32) CompareAndSwap(old, new int32) (swapped bool) {
|
||||
return atomic.CompareAndSwapInt32(&v.i, old, new)
|
||||
}
|
||||
|
||||
func (v *Int32) Add(i int32) (new int32) {
|
||||
return atomic.AddInt32(&v.i, i)
|
||||
}
|
29
lang/atomic/Int64.go
Normal file
29
lang/atomic/Int64.go
Normal file
@ -0,0 +1,29 @@
|
||||
package atomic
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
type Int64 struct {
|
||||
i int64
|
||||
}
|
||||
|
||||
func (v *Int64) Load() (val int64) {
|
||||
return atomic.LoadInt64(&v.i)
|
||||
}
|
||||
|
||||
func (v *Int64) Store(val int64) {
|
||||
atomic.StoreInt64(&v.i, val)
|
||||
}
|
||||
|
||||
func (v *Int64) Swap(new int64) (old int64) {
|
||||
return atomic.SwapInt64(&v.i, new)
|
||||
}
|
||||
|
||||
func (v *Int64) CompareAndSwap(old, new int64) (swapped bool) {
|
||||
return atomic.CompareAndSwapInt64(&v.i, old, new)
|
||||
}
|
||||
|
||||
func (v *Int64) Add(i int64) (new int64) {
|
||||
return atomic.AddInt64(&v.i, i)
|
||||
}
|
46
lang/atomic/Reference.go
Normal file
46
lang/atomic/Reference.go
Normal file
@ -0,0 +1,46 @@
|
||||
package atomic
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type Reference[T any] struct {
|
||||
reference *T
|
||||
}
|
||||
|
||||
func NewReference[T any](reference *T) *Reference[T] {
|
||||
return &Reference[T]{reference}
|
||||
}
|
||||
|
||||
func (v *Reference[T]) Load() (val *T) {
|
||||
return LoadPointer(&v.reference)
|
||||
}
|
||||
|
||||
func (v *Reference[T]) Store(val *T) {
|
||||
StorePointer(&v.reference, val)
|
||||
}
|
||||
|
||||
func (v *Reference[T]) Swap(new *T) (old *T) {
|
||||
return SwapPointer(&v.reference, new)
|
||||
}
|
||||
|
||||
func (v *Reference[T]) CompareAndSwap(old, new *T) (swapped bool) {
|
||||
return CompareAndSwapPointer(&v.reference, old, new)
|
||||
}
|
||||
|
||||
func LoadPointer[T any](addr **T) (val *T) {
|
||||
return (*T)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(addr))))
|
||||
}
|
||||
|
||||
func StorePointer[T any](addr **T, val *T) {
|
||||
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(addr)), unsafe.Pointer(val))
|
||||
}
|
||||
|
||||
func SwapPointer[T any](addr **T, new *T) (old *T) {
|
||||
return (*T)(atomic.SwapPointer((*unsafe.Pointer)(unsafe.Pointer(addr)), unsafe.Pointer(new)))
|
||||
}
|
||||
|
||||
func CompareAndSwapPointer[T any](addr **T, old, new *T) (swapped bool) {
|
||||
return atomic.CompareAndSwapPointer((*unsafe.Pointer)(unsafe.Pointer(addr)), unsafe.Pointer(old), unsafe.Pointer(new))
|
||||
}
|
15
lang/atomic/Reference_test.go
Normal file
15
lang/atomic/Reference_test.go
Normal file
@ -0,0 +1,15 @@
|
||||
package atomic
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/tursom/GoCollections/lang"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAtomic_Store(t *testing.T) {
|
||||
a := &Reference[lang.Int]{}
|
||||
var i lang.Int = 1
|
||||
a.Store(&i)
|
||||
i = 2
|
||||
fmt.Println(a.Load())
|
||||
}
|
29
lang/atomic/UInt32.go
Normal file
29
lang/atomic/UInt32.go
Normal file
@ -0,0 +1,29 @@
|
||||
package atomic
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
type UInt32 struct {
|
||||
i uint32
|
||||
}
|
||||
|
||||
func (v *UInt32) Load() (val uint32) {
|
||||
return atomic.LoadUint32(&v.i)
|
||||
}
|
||||
|
||||
func (v *UInt32) Store(val uint32) {
|
||||
atomic.StoreUint32(&v.i, val)
|
||||
}
|
||||
|
||||
func (v *UInt32) Swap(new uint32) (old uint32) {
|
||||
return atomic.SwapUint32(&v.i, new)
|
||||
}
|
||||
|
||||
func (v *UInt32) CompareAndSwap(old, new uint32) (swapped bool) {
|
||||
return atomic.CompareAndSwapUint32(&v.i, old, new)
|
||||
}
|
||||
|
||||
func (v *UInt32) Add(i uint32) (new uint32) {
|
||||
return atomic.AddUint32(&v.i, i)
|
||||
}
|
29
lang/atomic/UInt64.go
Normal file
29
lang/atomic/UInt64.go
Normal file
@ -0,0 +1,29 @@
|
||||
package atomic
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
type UInt64 struct {
|
||||
i uint64
|
||||
}
|
||||
|
||||
func (v *UInt64) Load() (val uint64) {
|
||||
return atomic.LoadUint64(&v.i)
|
||||
}
|
||||
|
||||
func (v *UInt64) Store(val uint64) {
|
||||
atomic.StoreUint64(&v.i, val)
|
||||
}
|
||||
|
||||
func (v *UInt64) Swap(new uint64) (old uint64) {
|
||||
return atomic.SwapUint64(&v.i, new)
|
||||
}
|
||||
|
||||
func (v *UInt64) CompareAndSwap(old, new uint64) (swapped bool) {
|
||||
return atomic.CompareAndSwapUint64(&v.i, old, new)
|
||||
}
|
||||
|
||||
func (v *UInt64) Add(i uint64) (new uint64) {
|
||||
return atomic.AddUint64(&v.i, i)
|
||||
}
|
Loading…
Reference in New Issue
Block a user