mirror of
https://github.com/tursom/GoCollections.git
synced 2025-01-30 02:20:13 +08:00
add ThreadLocal and Context
This commit is contained in:
parent
9602d80b4e
commit
81cc3651c8
@ -8,27 +8,29 @@ import (
|
||||
|
||||
type (
|
||||
//HashMap
|
||||
//TODO impl
|
||||
HashMap[K lang.Object, V any] struct {
|
||||
NodeMap[K, V]
|
||||
slot []*hashMapNode[K, V]
|
||||
loadFactor float32
|
||||
size int
|
||||
}
|
||||
|
||||
abstractHashMapNode[K lang.Object, V any] struct {
|
||||
m *HashMap[K, V]
|
||||
hash int32
|
||||
}
|
||||
|
||||
hashMapNode[K lang.Object, V any] struct {
|
||||
lang.BaseObject
|
||||
m *HashMap[K, V]
|
||||
abstractHashMapNode[K, V]
|
||||
key K
|
||||
value V
|
||||
next *hashMapNode[K, V]
|
||||
hash int32
|
||||
}
|
||||
|
||||
emptyHashMapSlot[K lang.Object, V any] struct {
|
||||
lang.BaseObject
|
||||
m *HashMap[K, V]
|
||||
hashCode int32
|
||||
index int
|
||||
abstractHashMapNode[K, V]
|
||||
}
|
||||
)
|
||||
|
||||
@ -45,23 +47,23 @@ func NewHashMapInitCap[K lang.Object, V any](initialCapacity int, loadFactor flo
|
||||
return m
|
||||
}
|
||||
|
||||
func (h *HashMap[K, V]) String() string {
|
||||
return MapToString[K, V](h).String()
|
||||
func (m *HashMap[K, V]) String() string {
|
||||
return MapToString[K, V](m).String()
|
||||
}
|
||||
|
||||
func (h *HashMap[K, V]) findSlot(k K) MapNode[K, V] {
|
||||
func (m *HashMap[K, V]) findSlot(k K) MapNode[K, V] {
|
||||
hashCode := lang.HashCode(k)
|
||||
hashCode ^= hashCode >> 16
|
||||
index := int(hashCode) % len(h.slot)
|
||||
root := h.slot[index]
|
||||
index := int(hashCode) % len(m.slot)
|
||||
root := m.slot[index]
|
||||
if root == nil {
|
||||
return &emptyHashMapSlot[K, V]{m: h, hashCode: hashCode, index: index}
|
||||
return &emptyHashMapSlot[K, V]{abstractHashMapNode: abstractHashMapNode[K, V]{m: m, hash: hashCode}}
|
||||
}
|
||||
return root
|
||||
}
|
||||
|
||||
func (h *HashMap[K, V]) Loop(f func(K, V) exceptions.Exception) (err exceptions.Exception) {
|
||||
for _, node := range h.slot {
|
||||
func (m *HashMap[K, V]) Loop(f func(K, V) exceptions.Exception) (err exceptions.Exception) {
|
||||
for _, node := range m.slot {
|
||||
for node != nil {
|
||||
err = f(node.GetKey(), node.GetValue())
|
||||
if err != nil {
|
||||
@ -73,32 +75,74 @@ func (h *HashMap[K, V]) Loop(f func(K, V) exceptions.Exception) (err exceptions.
|
||||
return
|
||||
}
|
||||
|
||||
func (m *HashMap[K, V]) resize() {
|
||||
slot := m.slot
|
||||
resize := len(slot)
|
||||
load := int(float32(m.size) / m.loadFactor)
|
||||
for load < resize {
|
||||
resize >>= 1
|
||||
}
|
||||
for load > resize {
|
||||
resize <<= 1
|
||||
}
|
||||
if resize == len(slot) {
|
||||
return
|
||||
}
|
||||
m.slot = make([]*hashMapNode[K, V], resize)
|
||||
for _, node := range slot {
|
||||
for node != nil {
|
||||
next := node.next
|
||||
index := node.index()
|
||||
node.next = m.slot[index]
|
||||
m.slot[index] = node
|
||||
node = next
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *HashMap[K, V]) resizeFromRemove() {
|
||||
if len(m.slot) > int(float32(m.size)/m.loadFactor) {
|
||||
m.resize()
|
||||
}
|
||||
}
|
||||
|
||||
func (m *HashMap[K, V]) resizeFromAdd() {
|
||||
if len(m.slot) < int(float32(m.size)/m.loadFactor) {
|
||||
m.resize()
|
||||
}
|
||||
}
|
||||
|
||||
func (n *abstractHashMapNode[K, V]) index() int {
|
||||
return int(n.hash) % len(n.m.slot)
|
||||
}
|
||||
|
||||
func (e *emptyHashMapSlot[K, V]) GetKey() K {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
return lang.Nil[K]()
|
||||
}
|
||||
|
||||
func (e *emptyHashMapSlot[K, V]) GetValue() V {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
return lang.Nil[V]()
|
||||
}
|
||||
|
||||
func (e *emptyHashMapSlot[K, V]) SetValue(value V) {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
func (e *emptyHashMapSlot[K, V]) SetValue(_ V) {
|
||||
}
|
||||
|
||||
func (e *emptyHashMapSlot[K, V]) CreateNext(key K) MapNode[K, V] {
|
||||
index := e.index()
|
||||
node := &hashMapNode[K, V]{
|
||||
key: key,
|
||||
hash: lang.HashCode(key),
|
||||
key: key,
|
||||
abstractHashMapNode: abstractHashMapNode[K, V]{m: e.m, hash: lang.HashCode(key)},
|
||||
next: e.m.slot[index],
|
||||
}
|
||||
e.m.slot[e.index] = node
|
||||
e.m.slot[index] = node
|
||||
e.m.size++
|
||||
e.m.resizeFromAdd()
|
||||
return node
|
||||
}
|
||||
|
||||
func (e *emptyHashMapSlot[K, V]) GetNext() MapNode[K, V] {
|
||||
node := e.m.slot[e.index]
|
||||
node := e.m.slot[e.index()]
|
||||
// required
|
||||
if node == nil {
|
||||
return nil
|
||||
}
|
||||
@ -106,9 +150,11 @@ func (e *emptyHashMapSlot[K, V]) GetNext() MapNode[K, V] {
|
||||
}
|
||||
|
||||
func (e *emptyHashMapSlot[K, V]) RemoveNext() {
|
||||
node := e.m.slot[e.index]
|
||||
node := e.m.slot[e.index()]
|
||||
if node != nil {
|
||||
e.m.slot[e.index] = node.next
|
||||
e.m.slot[e.index()] = node.next
|
||||
e.m.size--
|
||||
e.m.resizeFromRemove()
|
||||
}
|
||||
}
|
||||
|
||||
@ -129,7 +175,16 @@ func (s *hashMapNode[K, V]) SetValue(value V) {
|
||||
}
|
||||
|
||||
func (s *hashMapNode[K, V]) CreateNext(key K) MapNode[K, V] {
|
||||
s.next = &hashMapNode[K, V]{key: key, next: s.next, hash: lang.HashCode(key)}
|
||||
s.next = &hashMapNode[K, V]{
|
||||
key: key,
|
||||
next: s.next,
|
||||
abstractHashMapNode: abstractHashMapNode[K, V]{
|
||||
m: s.m,
|
||||
hash: lang.HashCode(key),
|
||||
},
|
||||
}
|
||||
s.m.size++
|
||||
s.m.resizeFromAdd()
|
||||
return s.next
|
||||
}
|
||||
|
||||
@ -143,5 +198,7 @@ func (s *hashMapNode[K, V]) GetNext() MapNode[K, V] {
|
||||
func (s *hashMapNode[K, V]) RemoveNext() {
|
||||
if s.next != nil {
|
||||
s.next = s.next.next
|
||||
s.m.size--
|
||||
s.m.resizeFromRemove()
|
||||
}
|
||||
}
|
||||
|
@ -13,4 +13,6 @@ func TestHashMap_put(t *testing.T) {
|
||||
m.Put(lang.Int(i), i+1)
|
||||
}
|
||||
fmt.Println(m)
|
||||
m.resize()
|
||||
fmt.Println(m)
|
||||
}
|
||||
|
@ -14,8 +14,12 @@ type (
|
||||
|
||||
Map[K lang.Object, V any] interface {
|
||||
MapLooper[K, V]
|
||||
Put(k K, v V) (bool, exceptions.Exception)
|
||||
Get(k K) (V, bool, exceptions.Exception)
|
||||
}
|
||||
|
||||
MutableMap[K lang.Object, V any] interface {
|
||||
Map[K, V]
|
||||
Put(k K, v V) (bool, exceptions.Exception)
|
||||
Remove(k K) (V, bool, exceptions.Exception)
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
package exceptions
|
||||
|
||||
var ElementFound = NewRuntimeException("", DefaultExceptionConfig().SetGetStackTrace(false).SetExceptionName("ElementFound"))
|
||||
var ElementNotFound = NewRuntimeException("", DefaultExceptionConfig().SetGetStackTrace(false).SetExceptionName("ElementNotFound"))
|
||||
var CollectionLoopFinished = NewRuntimeException("", DefaultExceptionConfig().SetGetStackTrace(false).SetExceptionName("CollectionLoopFinished"))
|
||||
var ElementFound = NewRuntimeException("", DefaultExceptionConfig().SetGetStackTrace(false).SetExceptionName("github.com.tursom.GoCollections.exceptions.ElementFound"))
|
||||
var ElementNotFound = NewElementNotFoundException("", nil)
|
||||
var CollectionLoopFinished = NewRuntimeException("", DefaultExceptionConfig().SetGetStackTrace(false).SetExceptionName("github.com.tursom.GoCollections.exceptions.CollectionLoopFinished"))
|
||||
|
@ -6,6 +6,7 @@ type ElementNotFoundException struct {
|
||||
|
||||
func NewElementNotFoundException(message string, config *ExceptionConfig) *ElementNotFoundException {
|
||||
return &ElementNotFoundException{
|
||||
NewRuntimeException(message, config.AddSkipStack(1).SetExceptionName("ElementNotFoundException")),
|
||||
NewRuntimeException(message, config.AddSkipStack(1).
|
||||
SetExceptionName("github.com.tursom.GoCollections.exceptions.ElementNotFoundException")),
|
||||
}
|
||||
}
|
||||
|
@ -48,7 +48,8 @@ func BuildStackTraceByArray(builder *strings.Builder, trace []StackTrace) {
|
||||
}
|
||||
|
||||
func BuildStackTrace(builder *strings.Builder, e Exception) {
|
||||
builder.WriteString(fmt.Sprintf("exception caused %s: %s\n", e.Name(), e.Message()))
|
||||
builder.WriteString(e.Error())
|
||||
builder.WriteString("\n")
|
||||
if e.StackTrace() == nil {
|
||||
return
|
||||
}
|
||||
|
@ -7,6 +7,10 @@ type ExceptionConfig struct {
|
||||
ExceptionName string
|
||||
}
|
||||
|
||||
func Cfg() *ExceptionConfig {
|
||||
return DefaultExceptionConfig()
|
||||
}
|
||||
|
||||
func DefaultExceptionConfig() *ExceptionConfig {
|
||||
return &ExceptionConfig{
|
||||
SkipStack: 0,
|
||||
|
@ -6,6 +6,7 @@ type IllegalParameterException struct {
|
||||
|
||||
func NewIllegalParameterException(message string, config *ExceptionConfig) *IllegalParameterException {
|
||||
return &IllegalParameterException{
|
||||
NewRuntimeException(message, config.AddSkipStack(1).SetExceptionName("IllegalParameterException")),
|
||||
NewRuntimeException(message, config.AddSkipStack(1).
|
||||
SetExceptionName("github.com.tursom.GoCollections.exceptions.IllegalParameterException")),
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,8 @@ type IndexOutOfBound struct {
|
||||
|
||||
func NewIndexOutOfBound(message string, config *ExceptionConfig) *IndexOutOfBound {
|
||||
return &IndexOutOfBound{
|
||||
NewRuntimeException(message, config.AddSkipStack(1).SetExceptionName("IndexOutOfBound")),
|
||||
NewRuntimeException(message, config.AddSkipStack(1).
|
||||
SetExceptionName("github.com.tursom.GoCollections.exceptions.IndexOutOfBound")),
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,7 +15,7 @@ func CatchIndexOutOfBound[T any](f func() T, config *ExceptionConfig) (r T, err
|
||||
defer func() {
|
||||
r := recover()
|
||||
if r != nil {
|
||||
err = NewIndexOutOfBound("", config.AddSkipStack(3).SetCause(PackageAny(r)))
|
||||
err = NewIndexOutOfBound("", config.AddSkipStack(3).SetCause(r))
|
||||
}
|
||||
}()
|
||||
r = f()
|
||||
|
@ -11,7 +11,8 @@ type NPE struct {
|
||||
|
||||
func NewNPE(message string, config *ExceptionConfig) *NPE {
|
||||
return &NPE{
|
||||
NewRuntimeException(message, config.AddSkipStack(1).SetExceptionName("NPE")),
|
||||
NewRuntimeException(message, config.AddSkipStack(1).
|
||||
SetExceptionName("github.com.tursom.GoCollections.exceptions.NPE")),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ type OperationNotSupportedException struct {
|
||||
|
||||
func NewOperationNotSupportedException(message string, config *ExceptionConfig) *OperationNotSupportedException {
|
||||
return &OperationNotSupportedException{
|
||||
NewRuntimeException(message, config.AddSkipStack(1).SetExceptionName("OperationNotSupportedException")),
|
||||
NewRuntimeException(message, config.AddSkipStack(1).
|
||||
SetExceptionName("github.com.tursom.GoCollections.exceptions.OperationNotSupportedException")),
|
||||
}
|
||||
}
|
||||
|
@ -21,8 +21,9 @@ func NewPackageException(err any, config *ExceptionConfig) *PackageException {
|
||||
t := reflect.TypeOf(err)
|
||||
message = fmt.Sprintf("%s (%s)", message, t.Name())
|
||||
return &PackageException{
|
||||
RuntimeException: NewRuntimeException(message, config.AddSkipStack(1).SetExceptionName("PackageException")),
|
||||
err: err,
|
||||
RuntimeException: NewRuntimeException(message, config.AddSkipStack(1).
|
||||
SetExceptionName("github.com.tursom.GoCollections.exceptions.PackageException")),
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package exceptions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/tursom/GoCollections/lang"
|
||||
"io"
|
||||
"os"
|
||||
@ -36,7 +37,7 @@ func NewRuntimeException(message string, config *ExceptionConfig) RuntimeExcepti
|
||||
}
|
||||
}
|
||||
|
||||
exceptionName := "RuntimeException"
|
||||
exceptionName := "github.com.tursom.GoCollections.exceptions.RuntimeException"
|
||||
if len(config.ExceptionName) != 0 {
|
||||
exceptionName = config.ExceptionName
|
||||
}
|
||||
@ -55,9 +56,17 @@ func (o RuntimeException) Cause() Exception {
|
||||
}
|
||||
|
||||
func (o RuntimeException) Error() string {
|
||||
builder := strings.Builder{}
|
||||
o.BuildPrintStackTrace(&builder)
|
||||
return builder.String()
|
||||
message := o.message
|
||||
if len(message) == 0 {
|
||||
if o.cause != nil {
|
||||
message = fmt.Sprintf("%s: %s", o.Name(), o.cause.Error())
|
||||
} else {
|
||||
message = o.Name()
|
||||
}
|
||||
} else {
|
||||
message = fmt.Sprintf("%s: %s", o.Name(), message)
|
||||
}
|
||||
return message
|
||||
}
|
||||
|
||||
func (o RuntimeException) Message() string {
|
||||
@ -77,7 +86,9 @@ func (o RuntimeException) PrintStackTrace() {
|
||||
}
|
||||
|
||||
func (o RuntimeException) PrintStackTraceTo(writer io.Writer) {
|
||||
bytes := []byte(o.Error())
|
||||
builder := strings.Builder{}
|
||||
o.BuildPrintStackTrace(&builder)
|
||||
bytes := []byte(builder.String())
|
||||
writeBytes := 0
|
||||
for writeBytes < len(bytes) {
|
||||
write, err := writer.Write(bytes[writeBytes:])
|
||||
|
12
exceptions/RuntimeException_test.go
Normal file
12
exceptions/RuntimeException_test.go
Normal file
@ -0,0 +1,12 @@
|
||||
package exceptions
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRuntimeException_PrintStackTrace(t *testing.T) {
|
||||
exception := NewRuntimeException("test1", DefaultExceptionConfig().SetCause(1))
|
||||
exception = NewRuntimeException("test2", DefaultExceptionConfig().SetCause(exception))
|
||||
exception = NewRuntimeException("", DefaultExceptionConfig().SetCause(exception))
|
||||
exception.PrintStackTrace()
|
||||
}
|
13
exceptions/StackTrace_test.go
Normal file
13
exceptions/StackTrace_test.go
Normal file
@ -0,0 +1,13 @@
|
||||
package exceptions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func TestGetStackTrace(t *testing.T) {
|
||||
fmt.Println(unsafe.Sizeof(StackTrace{}))
|
||||
fmt.Println(unsafe.Sizeof(make([]StackTrace, 0, 16)))
|
||||
fmt.Println(unsafe.Sizeof(make([]StackTrace, 0, 16)) + unsafe.Sizeof(StackTrace{})*16)
|
||||
}
|
@ -12,7 +12,8 @@ type TypeCastException struct {
|
||||
|
||||
func NewTypeCastException(message string, config *ExceptionConfig) *TypeCastException {
|
||||
return &TypeCastException{
|
||||
NewRuntimeException(message, config.AddSkipStack(1).SetExceptionName("TypeCastException")),
|
||||
NewRuntimeException(message, config.AddSkipStack(1).
|
||||
SetExceptionName("github.com.tursom.GoCollections.exceptions.TypeCastException")),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ type WrongCallHostException struct {
|
||||
|
||||
func NewWrongCallHostException(message string) WrongCallHostException {
|
||||
return WrongCallHostException{
|
||||
NewRuntimeException(message, DefaultExceptionConfig().AddSkipStack(1).SetExceptionName("WrongCallHostException")),
|
||||
NewRuntimeException(message, DefaultExceptionConfig().AddSkipStack(1).
|
||||
SetExceptionName("github.com.tursom.GoCollections.exceptions.WrongCallHostException")),
|
||||
}
|
||||
}
|
||||
|
5
go.mod
5
go.mod
@ -2,4 +2,7 @@ module github.com/tursom/GoCollections
|
||||
|
||||
go 1.18
|
||||
|
||||
require github.com/petermattis/goid v0.0.0-20220302125637-5f11c28912df
|
||||
require (
|
||||
github.com/petermattis/goid v0.0.0-20220302125637-5f11c28912df
|
||||
github.com/timandy/routine v1.0.5
|
||||
)
|
||||
|
@ -32,10 +32,10 @@ func Cast[T any](v any) T {
|
||||
}
|
||||
}
|
||||
|
||||
func ForceCast[T any](v unsafe.Pointer) T {
|
||||
func ForceCast[T any](v unsafe.Pointer) *T {
|
||||
if v == nil {
|
||||
return Nil[T]()
|
||||
return nil
|
||||
} else {
|
||||
return Cast[T](v)
|
||||
return (*T)(v)
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,10 @@ type (
|
||||
|
||||
Any = Object
|
||||
|
||||
IsBaseObject interface {
|
||||
AsBaseObject() *BaseObject
|
||||
}
|
||||
|
||||
BaseObject struct {
|
||||
}
|
||||
)
|
||||
@ -54,6 +58,10 @@ func (b *BaseObject) AsObject() Object {
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *BaseObject) AsBaseObject() *BaseObject {
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *BaseObject) Equals(o Object) bool {
|
||||
return b == o
|
||||
}
|
||||
@ -73,3 +81,14 @@ func (b *BaseObject) ToString() String {
|
||||
func (b *BaseObject) HashCode() int32 {
|
||||
return Hash64(b)
|
||||
}
|
||||
|
||||
func (b *BaseObject) Compare(t IsBaseObject) int {
|
||||
o := t.AsBaseObject()
|
||||
if b == o {
|
||||
return 0
|
||||
} else if uintptr(unsafe.Pointer(b)) > uintptr(unsafe.Pointer(o)) {
|
||||
return 1
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
74
lang/ThreadLocal.go
Normal file
74
lang/ThreadLocal.go
Normal file
@ -0,0 +1,74 @@
|
||||
package lang
|
||||
|
||||
import (
|
||||
"github.com/timandy/routine"
|
||||
)
|
||||
|
||||
//goland:noinspection GoUnusedGlobalVariable
|
||||
var (
|
||||
ThreadLocalGo = routine.Go
|
||||
ThreadLocalGoWait = routine.GoWait
|
||||
ThreadLocalGoWaitResult = routine.GoWaitResult
|
||||
)
|
||||
|
||||
type (
|
||||
ThreadLocal[T any] interface {
|
||||
Object
|
||||
Get() T
|
||||
Put(value T)
|
||||
Remove()
|
||||
}
|
||||
|
||||
threadLocalImpl[T any] struct {
|
||||
BaseObject
|
||||
threadLocal routine.ThreadLocal
|
||||
}
|
||||
)
|
||||
|
||||
func GoId() int64 {
|
||||
return routine.Goid()
|
||||
}
|
||||
|
||||
//goland:noinspection GoUnusedExportedFunction
|
||||
func NewThreadLocal[T any]() ThreadLocal[T] {
|
||||
return &threadLocalImpl[T]{
|
||||
threadLocal: routine.NewInheritableThreadLocal(),
|
||||
}
|
||||
}
|
||||
|
||||
//goland:noinspection GoUnusedExportedFunction
|
||||
func NewThreadLocalWithInitial[T any](supplier func() T) ThreadLocal[T] {
|
||||
return &threadLocalImpl[T]{
|
||||
threadLocal: routine.NewThreadLocalWithInitial(func() routine.Any {
|
||||
return supplier()
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
//goland:noinspection GoUnusedExportedFunction
|
||||
func NewInheritableThreadLocal[T any]() ThreadLocal[T] {
|
||||
return &threadLocalImpl[T]{
|
||||
threadLocal: routine.NewInheritableThreadLocal(),
|
||||
}
|
||||
}
|
||||
|
||||
//goland:noinspection GoUnusedExportedFunction
|
||||
func NewInheritableThreadLocalWithInitial[T any](supplier func() T) ThreadLocal[T] {
|
||||
return &threadLocalImpl[T]{
|
||||
threadLocal: routine.NewInheritableThreadLocalWithInitial(func() routine.Any {
|
||||
return supplier()
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func (t *threadLocalImpl[T]) Get() T {
|
||||
return Cast[T](t.threadLocal.Get())
|
||||
}
|
||||
|
||||
func (t *threadLocalImpl[T]) Put(value T) {
|
||||
t.threadLocal.Set(value)
|
||||
}
|
||||
|
||||
func (t *threadLocalImpl[T]) Remove() {
|
||||
t.threadLocal.Remove()
|
||||
}
|
15
lang/ThreadLocal_test.go
Normal file
15
lang/ThreadLocal_test.go
Normal file
@ -0,0 +1,15 @@
|
||||
package lang
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestThreadLocalImpl(t1 *testing.T) {
|
||||
local := NewThreadLocal[int]()
|
||||
fmt.Println(local.Get())
|
||||
local.Put(1)
|
||||
fmt.Println(local.Get())
|
||||
local.Remove()
|
||||
fmt.Println(local.Get())
|
||||
}
|
110
lang/atomic/Array.go
Normal file
110
lang/atomic/Array.go
Normal file
@ -0,0 +1,110 @@
|
||||
package atomic
|
||||
|
||||
type (
|
||||
Array[T any] struct {
|
||||
atomic *Atomic[T]
|
||||
array []T
|
||||
}
|
||||
Int32Array struct {
|
||||
Array[int32]
|
||||
}
|
||||
Int64Array struct {
|
||||
Array[int64]
|
||||
}
|
||||
UInt32Array struct {
|
||||
Array[uint32]
|
||||
}
|
||||
UInt64Array struct {
|
||||
Array[uint64]
|
||||
}
|
||||
)
|
||||
|
||||
func NewArray[T any](size int) *Array[*T] {
|
||||
return &Array[*T]{
|
||||
atomic: GetAtomic[T](),
|
||||
array: make([]*T, size),
|
||||
}
|
||||
}
|
||||
|
||||
func CapArray[T any](array []*T) *Array[*T] {
|
||||
return &Array[*T]{
|
||||
atomic: GetAtomic[T](),
|
||||
array: array,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInt32Array(size int) *Int32Array {
|
||||
return &Int32Array{
|
||||
Array[int32]{
|
||||
atomic: &Int32F,
|
||||
array: make([]int32, size),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func NewInt64Array(size int) *Int64Array {
|
||||
return &Int64Array{
|
||||
Array[int64]{
|
||||
atomic: &Int64F,
|
||||
array: make([]int64, size),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func NewUInt32Array(size int) *UInt32Array {
|
||||
return &UInt32Array{
|
||||
Array[uint32]{
|
||||
atomic: &UInt32F,
|
||||
array: make([]uint32, size),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func NewUInt64Array(size int) *UInt64Array {
|
||||
return &UInt64Array{
|
||||
Array[uint64]{
|
||||
atomic: &UInt64F,
|
||||
array: make([]uint64, size),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Array[T]) Len() int {
|
||||
return len(a.array)
|
||||
}
|
||||
|
||||
func (a *Array[T]) Array() []T {
|
||||
return a.array
|
||||
}
|
||||
|
||||
func (a *Array[T]) Get(index int) T {
|
||||
return a.atomic.Load(&a.array[index])
|
||||
}
|
||||
|
||||
func (a *Array[T]) Set(index int, p T) {
|
||||
a.atomic.Store(&a.array[index], p)
|
||||
}
|
||||
|
||||
func (a *Array[T]) Swap(index int, p T) (old T) {
|
||||
return a.atomic.Swap(&a.array[index], p)
|
||||
}
|
||||
|
||||
func (a *Array[T]) CompareAndSwap(index int, old, new T) (swapped bool) {
|
||||
return a.atomic.CompareAndSwap(&a.array[index], old, new)
|
||||
}
|
||||
|
||||
func (a *Int32Array) Add(index int, value int32) {
|
||||
AddInt32(&a.array[index], value)
|
||||
}
|
||||
|
||||
func (a *Int64Array) Add(index int, value int64) {
|
||||
AddInt64(&a.array[index], value)
|
||||
}
|
||||
|
||||
func (a *UInt32Array) Add(index int, value uint32) {
|
||||
AddUInt32(&a.array[index], value)
|
||||
}
|
||||
|
||||
func (a *UInt64Array) Add(index int, value uint64) {
|
||||
AddUInt64(&a.array[index], value)
|
||||
}
|
@ -5,6 +5,58 @@ import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type (
|
||||
Atomic[T any] struct {
|
||||
Swap func(addr *T, new T) (old T)
|
||||
CompareAndSwap func(addr *T, old, new T) (swapped bool)
|
||||
Load func(addr *T) (val T)
|
||||
Store func(addr *T, val T)
|
||||
}
|
||||
)
|
||||
|
||||
//goland:noinspection GoUnusedGlobalVariable
|
||||
var (
|
||||
Int32F = Atomic[int32]{
|
||||
SwapInt32,
|
||||
CompareAndSwapInt32,
|
||||
LoadInt32,
|
||||
StoreInt32,
|
||||
}
|
||||
Int64F = Atomic[int64]{
|
||||
SwapInt64,
|
||||
CompareAndSwapInt64,
|
||||
LoadInt64,
|
||||
StoreInt64,
|
||||
}
|
||||
UInt32F = Atomic[uint32]{
|
||||
SwapUInt32,
|
||||
CompareAndSwapUInt32,
|
||||
LoadUint32,
|
||||
StoreUInt32,
|
||||
}
|
||||
UInt64F = Atomic[uint64]{
|
||||
SwapUInt64,
|
||||
CompareAndSwapUInt64,
|
||||
LoadUint64,
|
||||
StoreUInt64,
|
||||
}
|
||||
PointerF = Atomic[unsafe.Pointer]{
|
||||
UnsafeSwapPointer,
|
||||
UnsafeCompareAndSwapPointer,
|
||||
UnsafeLoadPointer,
|
||||
UnsafeStorePointer,
|
||||
}
|
||||
)
|
||||
|
||||
func GetAtomic[T any]() *Atomic[*T] {
|
||||
return &Atomic[*T]{
|
||||
SwapPointer[T],
|
||||
CompareAndSwapPointer[T],
|
||||
LoadPointer[T],
|
||||
StorePointer[T],
|
||||
}
|
||||
}
|
||||
|
||||
func SwapInt32(addr *int32, new int32) (old int32) {
|
||||
return atomic.SwapInt32(addr, new)
|
||||
}
|
||||
@ -13,11 +65,11 @@ func SwapInt64(addr *int64, new int64) (old int64) {
|
||||
return atomic.SwapInt64(addr, new)
|
||||
}
|
||||
|
||||
func SwapUint32(addr *uint32, new uint32) (old uint32) {
|
||||
func SwapUInt32(addr *uint32, new uint32) (old uint32) {
|
||||
return atomic.SwapUint32(addr, new)
|
||||
}
|
||||
|
||||
func SwapUint64(addr *uint64, new uint64) (old uint64) {
|
||||
func SwapUInt64(addr *uint64, new uint64) (old uint64) {
|
||||
return atomic.SwapUint64(addr, new)
|
||||
}
|
||||
|
||||
@ -37,11 +89,11 @@ func CompareAndSwapInt64(addr *int64, old, new int64) (swapped bool) {
|
||||
return atomic.CompareAndSwapInt64(addr, old, new)
|
||||
}
|
||||
|
||||
func CompareAndSwapUint32(addr *uint32, old, new uint32) (swapped bool) {
|
||||
func CompareAndSwapUInt32(addr *uint32, old, new uint32) (swapped bool) {
|
||||
return atomic.CompareAndSwapUint32(addr, old, new)
|
||||
}
|
||||
|
||||
func CompareAndSwapUint64(addr *uint64, old, new uint64) (swapped bool) {
|
||||
func CompareAndSwapUInt64(addr *uint64, old, new uint64) (swapped bool) {
|
||||
return atomic.CompareAndSwapUint64(addr, old, new)
|
||||
}
|
||||
|
||||
@ -57,7 +109,7 @@ func AddInt32(addr *int32, delta int32) (new int32) {
|
||||
return atomic.AddInt32(addr, delta)
|
||||
}
|
||||
|
||||
func AddUint32(addr *uint32, delta uint32) (new uint32) {
|
||||
func AddUInt32(addr *uint32, delta uint32) (new uint32) {
|
||||
return atomic.AddUint32(addr, delta)
|
||||
}
|
||||
|
||||
@ -65,7 +117,7 @@ func AddInt64(addr *int64, delta int64) (new int64) {
|
||||
return atomic.AddInt64(addr, delta)
|
||||
}
|
||||
|
||||
func AddUint64(addr *uint64, delta uint64) (new uint64) {
|
||||
func AddUInt64(addr *uint64, delta uint64) (new uint64) {
|
||||
return atomic.AddUint64(addr, delta)
|
||||
}
|
||||
|
||||
@ -105,11 +157,11 @@ func StoreInt64(addr *int64, val int64) {
|
||||
atomic.StoreInt64(addr, val)
|
||||
}
|
||||
|
||||
func StoreUint32(addr *uint32, val uint32) {
|
||||
func StoreUInt32(addr *uint32, val uint32) {
|
||||
atomic.StoreUint32(addr, val)
|
||||
}
|
||||
|
||||
func StoreUint64(addr *uint64, val uint64) {
|
||||
func StoreUInt64(addr *uint64, val uint64) {
|
||||
atomic.StoreUint64(addr, val)
|
||||
}
|
||||
|
||||
|
@ -5,9 +5,21 @@ import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type Reference[T any] struct {
|
||||
reference *T
|
||||
}
|
||||
//goland:noinspection GoUnusedGlobalVariable
|
||||
var (
|
||||
UnsafeLoadPointer = atomic.LoadPointer
|
||||
UnsafeStorePointer = atomic.StorePointer
|
||||
UnsafeSwapPointer = atomic.SwapPointer
|
||||
UnsafeCompareAndSwapPointer = atomic.CompareAndSwapPointer
|
||||
)
|
||||
|
||||
type (
|
||||
Pointer = unsafe.Pointer
|
||||
PPointer = *unsafe.Pointer
|
||||
Reference[T any] struct {
|
||||
reference *T
|
||||
}
|
||||
)
|
||||
|
||||
func NewReference[T any](reference *T) *Reference[T] {
|
||||
return &Reference[T]{reference}
|
||||
@ -29,18 +41,22 @@ func (v *Reference[T]) CompareAndSwap(old, new *T) (swapped bool) {
|
||||
return CompareAndSwapPointer(&v.reference, old, new)
|
||||
}
|
||||
|
||||
func AsPPointer[T any](p **T) *unsafe.Pointer {
|
||||
return (*unsafe.Pointer)(unsafe.Pointer(p))
|
||||
}
|
||||
|
||||
func LoadPointer[T any](addr **T) (val *T) {
|
||||
return (*T)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(addr))))
|
||||
return (*T)(atomic.LoadPointer(AsPPointer(addr)))
|
||||
}
|
||||
|
||||
func StorePointer[T any](addr **T, val *T) {
|
||||
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(addr)), unsafe.Pointer(val))
|
||||
atomic.StorePointer(AsPPointer(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)))
|
||||
return (*T)(atomic.SwapPointer(AsPPointer(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))
|
||||
return atomic.CompareAndSwapPointer(AsPPointer(addr), Pointer(old), Pointer(new))
|
||||
}
|
||||
|
@ -7,11 +7,11 @@ import (
|
||||
)
|
||||
|
||||
func AsList[T lang.Object](arr []T) collections.List[T] {
|
||||
return &arrayList[T]{arr}
|
||||
return &arrayList[T]{array: arr}
|
||||
}
|
||||
|
||||
func CheckedGet[T any](array []T, index int) (T, exceptions.Exception) {
|
||||
return exceptions.CatchIndexOutOfBound(func() T {
|
||||
return array[index]
|
||||
}, exceptions.DefaultExceptionConfig().AddSkipStack(3))
|
||||
}, exceptions.Cfg().AddSkipStack(3))
|
||||
}
|
||||
|
107
util/Context.go
Normal file
107
util/Context.go
Normal file
@ -0,0 +1,107 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"github.com/tursom/GoCollections/lang"
|
||||
"github.com/tursom/GoCollections/lang/atomic"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
contextId atomic.Int32
|
||||
)
|
||||
|
||||
type (
|
||||
Context struct {
|
||||
lang.BaseObject
|
||||
contextId int32
|
||||
keyId atomic.Int32
|
||||
}
|
||||
ContextMap interface {
|
||||
Get(key *ContextKey[any]) (any, bool)
|
||||
Set(key *ContextKey[any], value any)
|
||||
}
|
||||
ContextKey[T any] struct {
|
||||
lang.BaseObject
|
||||
contextId int32
|
||||
id int32
|
||||
}
|
||||
contextMapImpl struct {
|
||||
lang.BaseObject
|
||||
contextId int32
|
||||
array []any
|
||||
}
|
||||
concurrentContextMap struct {
|
||||
contextMapImpl
|
||||
lock sync.Mutex
|
||||
}
|
||||
)
|
||||
|
||||
func NewContext() *Context {
|
||||
return &Context{
|
||||
contextId: contextId.Add(1),
|
||||
}
|
||||
}
|
||||
|
||||
func AllocateContextKey[T any](ctx *Context) *ContextKey[T] {
|
||||
return &ContextKey[T]{
|
||||
contextId: ctx.contextId,
|
||||
id: ctx.keyId.Add(1) - 1,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Context) NewMap() ContextMap {
|
||||
return &contextMapImpl{
|
||||
contextId: c.contextId,
|
||||
//array: make([]any, c.keyId.Load()),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Context) NewConcurrentMap() ContextMap {
|
||||
return &concurrentContextMap{
|
||||
contextMapImpl: contextMapImpl{
|
||||
contextId: c.contextId,
|
||||
//array: make([]any, c.keyId.Load()),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (k *ContextKey[T]) Get(m ContextMap) T {
|
||||
value, _ := k.TryGet(m)
|
||||
return value
|
||||
}
|
||||
|
||||
func (k *ContextKey[T]) TryGet(m ContextMap) (T, bool) {
|
||||
value, ok := m.Get(k.asNormalKey())
|
||||
return lang.Cast[T](value), ok
|
||||
}
|
||||
|
||||
func (k *ContextKey[T]) Set(m ContextMap, value T) {
|
||||
m.Set(k.asNormalKey(), value)
|
||||
}
|
||||
|
||||
func (m *contextMapImpl) Get(key *ContextKey[any]) (any, bool) {
|
||||
if len(m.array) < int(key.id) {
|
||||
return nil, false
|
||||
} else {
|
||||
return m.array[key.id], true
|
||||
}
|
||||
}
|
||||
|
||||
func (m *contextMapImpl) Set(key *ContextKey[any], value any) {
|
||||
if len(m.array) < int(key.id) {
|
||||
newArray := make([]any, key.id)
|
||||
copy(newArray, m.array)
|
||||
m.array = newArray
|
||||
}
|
||||
m.array[key.id] = value
|
||||
}
|
||||
|
||||
func (m *concurrentContextMap) Set(key *ContextKey[any], value any) {
|
||||
m.lock.Lock()
|
||||
defer m.lock.Unlock()
|
||||
m.contextMapImpl.Set(key, value)
|
||||
}
|
||||
|
||||
func (k *ContextKey[T]) asNormalKey() *ContextKey[any] {
|
||||
return (*ContextKey[any])(k)
|
||||
}
|
20
util/Context_test.go
Normal file
20
util/Context_test.go
Normal file
@ -0,0 +1,20 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestContextKey(t *testing.T) {
|
||||
ctx := NewContext()
|
||||
key := AllocateContextKey[int](ctx)
|
||||
|
||||
m := ctx.NewConcurrentMap()
|
||||
|
||||
fmt.Println(key.Get(m))
|
||||
fmt.Println(key.TryGet(m))
|
||||
|
||||
key.Set(m, 100)
|
||||
fmt.Println(key.Get(m))
|
||||
fmt.Println(key.TryGet(m))
|
||||
}
|
@ -7,6 +7,7 @@ import (
|
||||
)
|
||||
|
||||
type arrayList[T lang.Object] struct {
|
||||
lang.BaseObject
|
||||
array []T
|
||||
}
|
||||
|
||||
@ -35,7 +36,7 @@ func (a *arrayList[T]) Get(index int) (T, exceptions.Exception) {
|
||||
}
|
||||
|
||||
func (a *arrayList[T]) SubList(from, to int) collections.List[T] {
|
||||
return &arrayList[T]{a.array[from:to]}
|
||||
return &arrayList[T]{array: a.array[from:to]}
|
||||
}
|
||||
|
||||
type arrayListIterator[T lang.Object] struct {
|
||||
@ -51,7 +52,7 @@ func (a *arrayListIterator[T]) Next() (r T, err exceptions.Exception) {
|
||||
defer func() {
|
||||
r := recover()
|
||||
if r != nil {
|
||||
err = exceptions.NewNPE(r, nil)
|
||||
err = exceptions.NewNPE("", exceptions.Cfg().SetCause(r))
|
||||
}
|
||||
}()
|
||||
i := a.index
|
||||
|
@ -7,7 +7,7 @@ import (
|
||||
)
|
||||
|
||||
func Test_arrayList_Get(t *testing.T) {
|
||||
l := &arrayList[lang.Int]{[]lang.Int{1, 2}}
|
||||
l := arrayList[lang.Int]{array: []lang.Int{1, 2}}
|
||||
for i := 0; i < l.Size()+1; i++ {
|
||||
r, err := l.Get(i)
|
||||
if err != nil {
|
||||
|
Loading…
Reference in New Issue
Block a user