mirror of
https://github.com/tursom/GoCollections.git
synced 2025-03-28 05:30:09 +08:00
add ThreadLocal and Context
This commit is contained in:
parent
9602d80b4e
commit
81cc3651c8
@ -8,27 +8,29 @@ import (
|
|||||||
|
|
||||||
type (
|
type (
|
||||||
//HashMap
|
//HashMap
|
||||||
//TODO impl
|
|
||||||
HashMap[K lang.Object, V any] struct {
|
HashMap[K lang.Object, V any] struct {
|
||||||
NodeMap[K, V]
|
NodeMap[K, V]
|
||||||
slot []*hashMapNode[K, V]
|
slot []*hashMapNode[K, V]
|
||||||
loadFactor float32
|
loadFactor float32
|
||||||
|
size int
|
||||||
|
}
|
||||||
|
|
||||||
|
abstractHashMapNode[K lang.Object, V any] struct {
|
||||||
|
m *HashMap[K, V]
|
||||||
|
hash int32
|
||||||
}
|
}
|
||||||
|
|
||||||
hashMapNode[K lang.Object, V any] struct {
|
hashMapNode[K lang.Object, V any] struct {
|
||||||
lang.BaseObject
|
lang.BaseObject
|
||||||
m *HashMap[K, V]
|
abstractHashMapNode[K, V]
|
||||||
key K
|
key K
|
||||||
value V
|
value V
|
||||||
next *hashMapNode[K, V]
|
next *hashMapNode[K, V]
|
||||||
hash int32
|
|
||||||
}
|
}
|
||||||
|
|
||||||
emptyHashMapSlot[K lang.Object, V any] struct {
|
emptyHashMapSlot[K lang.Object, V any] struct {
|
||||||
lang.BaseObject
|
lang.BaseObject
|
||||||
m *HashMap[K, V]
|
abstractHashMapNode[K, V]
|
||||||
hashCode int32
|
|
||||||
index int
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -45,23 +47,23 @@ func NewHashMapInitCap[K lang.Object, V any](initialCapacity int, loadFactor flo
|
|||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HashMap[K, V]) String() string {
|
func (m *HashMap[K, V]) String() string {
|
||||||
return MapToString[K, V](h).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 := lang.HashCode(k)
|
||||||
hashCode ^= hashCode >> 16
|
hashCode ^= hashCode >> 16
|
||||||
index := int(hashCode) % len(h.slot)
|
index := int(hashCode) % len(m.slot)
|
||||||
root := h.slot[index]
|
root := m.slot[index]
|
||||||
if root == nil {
|
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
|
return root
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HashMap[K, V]) Loop(f func(K, V) exceptions.Exception) (err exceptions.Exception) {
|
func (m *HashMap[K, V]) Loop(f func(K, V) exceptions.Exception) (err exceptions.Exception) {
|
||||||
for _, node := range h.slot {
|
for _, node := range m.slot {
|
||||||
for node != nil {
|
for node != nil {
|
||||||
err = f(node.GetKey(), node.GetValue())
|
err = f(node.GetKey(), node.GetValue())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -73,32 +75,74 @@ func (h *HashMap[K, V]) Loop(f func(K, V) exceptions.Exception) (err exceptions.
|
|||||||
return
|
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 {
|
func (e *emptyHashMapSlot[K, V]) GetKey() K {
|
||||||
//TODO implement me
|
return lang.Nil[K]()
|
||||||
panic("implement me")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *emptyHashMapSlot[K, V]) GetValue() V {
|
func (e *emptyHashMapSlot[K, V]) GetValue() V {
|
||||||
//TODO implement me
|
return lang.Nil[V]()
|
||||||
panic("implement me")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *emptyHashMapSlot[K, V]) SetValue(value V) {
|
func (e *emptyHashMapSlot[K, V]) SetValue(_ V) {
|
||||||
//TODO implement me
|
|
||||||
panic("implement me")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *emptyHashMapSlot[K, V]) CreateNext(key K) MapNode[K, V] {
|
func (e *emptyHashMapSlot[K, V]) CreateNext(key K) MapNode[K, V] {
|
||||||
|
index := e.index()
|
||||||
node := &hashMapNode[K, V]{
|
node := &hashMapNode[K, V]{
|
||||||
key: key,
|
key: key,
|
||||||
hash: lang.HashCode(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
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *emptyHashMapSlot[K, V]) GetNext() MapNode[K, V] {
|
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 {
|
if node == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -106,9 +150,11 @@ func (e *emptyHashMapSlot[K, V]) GetNext() MapNode[K, V] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *emptyHashMapSlot[K, V]) RemoveNext() {
|
func (e *emptyHashMapSlot[K, V]) RemoveNext() {
|
||||||
node := e.m.slot[e.index]
|
node := e.m.slot[e.index()]
|
||||||
if node != nil {
|
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] {
|
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
|
return s.next
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,5 +198,7 @@ func (s *hashMapNode[K, V]) GetNext() MapNode[K, V] {
|
|||||||
func (s *hashMapNode[K, V]) RemoveNext() {
|
func (s *hashMapNode[K, V]) RemoveNext() {
|
||||||
if s.next != nil {
|
if s.next != nil {
|
||||||
s.next = s.next.next
|
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)
|
m.Put(lang.Int(i), i+1)
|
||||||
}
|
}
|
||||||
fmt.Println(m)
|
fmt.Println(m)
|
||||||
|
m.resize()
|
||||||
|
fmt.Println(m)
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,12 @@ type (
|
|||||||
|
|
||||||
Map[K lang.Object, V any] interface {
|
Map[K lang.Object, V any] interface {
|
||||||
MapLooper[K, V]
|
MapLooper[K, V]
|
||||||
Put(k K, v V) (bool, exceptions.Exception)
|
|
||||||
Get(k K) (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)
|
Remove(k K) (V, bool, exceptions.Exception)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
package exceptions
|
package exceptions
|
||||||
|
|
||||||
var ElementFound = NewRuntimeException("", DefaultExceptionConfig().SetGetStackTrace(false).SetExceptionName("ElementFound"))
|
var ElementFound = NewRuntimeException("", DefaultExceptionConfig().SetGetStackTrace(false).SetExceptionName("github.com.tursom.GoCollections.exceptions.ElementFound"))
|
||||||
var ElementNotFound = NewRuntimeException("", DefaultExceptionConfig().SetGetStackTrace(false).SetExceptionName("ElementNotFound"))
|
var ElementNotFound = NewElementNotFoundException("", nil)
|
||||||
var CollectionLoopFinished = NewRuntimeException("", DefaultExceptionConfig().SetGetStackTrace(false).SetExceptionName("CollectionLoopFinished"))
|
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 {
|
func NewElementNotFoundException(message string, config *ExceptionConfig) *ElementNotFoundException {
|
||||||
return &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) {
|
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 {
|
if e.StackTrace() == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,10 @@ type ExceptionConfig struct {
|
|||||||
ExceptionName string
|
ExceptionName string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Cfg() *ExceptionConfig {
|
||||||
|
return DefaultExceptionConfig()
|
||||||
|
}
|
||||||
|
|
||||||
func DefaultExceptionConfig() *ExceptionConfig {
|
func DefaultExceptionConfig() *ExceptionConfig {
|
||||||
return &ExceptionConfig{
|
return &ExceptionConfig{
|
||||||
SkipStack: 0,
|
SkipStack: 0,
|
||||||
|
@ -6,6 +6,7 @@ type IllegalParameterException struct {
|
|||||||
|
|
||||||
func NewIllegalParameterException(message string, config *ExceptionConfig) *IllegalParameterException {
|
func NewIllegalParameterException(message string, config *ExceptionConfig) *IllegalParameterException {
|
||||||
return &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 {
|
func NewIndexOutOfBound(message string, config *ExceptionConfig) *IndexOutOfBound {
|
||||||
return &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() {
|
defer func() {
|
||||||
r := recover()
|
r := recover()
|
||||||
if r != nil {
|
if r != nil {
|
||||||
err = NewIndexOutOfBound("", config.AddSkipStack(3).SetCause(PackageAny(r)))
|
err = NewIndexOutOfBound("", config.AddSkipStack(3).SetCause(r))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
r = f()
|
r = f()
|
||||||
|
@ -11,7 +11,8 @@ type NPE struct {
|
|||||||
|
|
||||||
func NewNPE(message string, config *ExceptionConfig) *NPE {
|
func NewNPE(message string, config *ExceptionConfig) *NPE {
|
||||||
return &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 {
|
func NewOperationNotSupportedException(message string, config *ExceptionConfig) *OperationNotSupportedException {
|
||||||
return &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)
|
t := reflect.TypeOf(err)
|
||||||
message = fmt.Sprintf("%s (%s)", message, t.Name())
|
message = fmt.Sprintf("%s (%s)", message, t.Name())
|
||||||
return &PackageException{
|
return &PackageException{
|
||||||
RuntimeException: NewRuntimeException(message, config.AddSkipStack(1).SetExceptionName("PackageException")),
|
RuntimeException: NewRuntimeException(message, config.AddSkipStack(1).
|
||||||
err: err,
|
SetExceptionName("github.com.tursom.GoCollections.exceptions.PackageException")),
|
||||||
|
err: err,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package exceptions
|
package exceptions
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"github.com/tursom/GoCollections/lang"
|
"github.com/tursom/GoCollections/lang"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"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 {
|
if len(config.ExceptionName) != 0 {
|
||||||
exceptionName = config.ExceptionName
|
exceptionName = config.ExceptionName
|
||||||
}
|
}
|
||||||
@ -55,9 +56,17 @@ func (o RuntimeException) Cause() Exception {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (o RuntimeException) Error() string {
|
func (o RuntimeException) Error() string {
|
||||||
builder := strings.Builder{}
|
message := o.message
|
||||||
o.BuildPrintStackTrace(&builder)
|
if len(message) == 0 {
|
||||||
return builder.String()
|
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 {
|
func (o RuntimeException) Message() string {
|
||||||
@ -77,7 +86,9 @@ func (o RuntimeException) PrintStackTrace() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (o RuntimeException) PrintStackTraceTo(writer io.Writer) {
|
func (o RuntimeException) PrintStackTraceTo(writer io.Writer) {
|
||||||
bytes := []byte(o.Error())
|
builder := strings.Builder{}
|
||||||
|
o.BuildPrintStackTrace(&builder)
|
||||||
|
bytes := []byte(builder.String())
|
||||||
writeBytes := 0
|
writeBytes := 0
|
||||||
for writeBytes < len(bytes) {
|
for writeBytes < len(bytes) {
|
||||||
write, err := writer.Write(bytes[writeBytes:])
|
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 {
|
func NewTypeCastException(message string, config *ExceptionConfig) *TypeCastException {
|
||||||
return &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 {
|
func NewWrongCallHostException(message string) WrongCallHostException {
|
||||||
return 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
|
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 {
|
if v == nil {
|
||||||
return Nil[T]()
|
return nil
|
||||||
} else {
|
} else {
|
||||||
return Cast[T](v)
|
return (*T)(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,10 @@ type (
|
|||||||
|
|
||||||
Any = Object
|
Any = Object
|
||||||
|
|
||||||
|
IsBaseObject interface {
|
||||||
|
AsBaseObject() *BaseObject
|
||||||
|
}
|
||||||
|
|
||||||
BaseObject struct {
|
BaseObject struct {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -54,6 +58,10 @@ func (b *BaseObject) AsObject() Object {
|
|||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *BaseObject) AsBaseObject() *BaseObject {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
func (b *BaseObject) Equals(o Object) bool {
|
func (b *BaseObject) Equals(o Object) bool {
|
||||||
return b == o
|
return b == o
|
||||||
}
|
}
|
||||||
@ -73,3 +81,14 @@ func (b *BaseObject) ToString() String {
|
|||||||
func (b *BaseObject) HashCode() int32 {
|
func (b *BaseObject) HashCode() int32 {
|
||||||
return Hash64(b)
|
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"
|
"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) {
|
func SwapInt32(addr *int32, new int32) (old int32) {
|
||||||
return atomic.SwapInt32(addr, new)
|
return atomic.SwapInt32(addr, new)
|
||||||
}
|
}
|
||||||
@ -13,11 +65,11 @@ func SwapInt64(addr *int64, new int64) (old int64) {
|
|||||||
return atomic.SwapInt64(addr, new)
|
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)
|
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)
|
return atomic.SwapUint64(addr, new)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,11 +89,11 @@ func CompareAndSwapInt64(addr *int64, old, new int64) (swapped bool) {
|
|||||||
return atomic.CompareAndSwapInt64(addr, old, new)
|
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)
|
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)
|
return atomic.CompareAndSwapUint64(addr, old, new)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,7 +109,7 @@ func AddInt32(addr *int32, delta int32) (new int32) {
|
|||||||
return atomic.AddInt32(addr, delta)
|
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)
|
return atomic.AddUint32(addr, delta)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,7 +117,7 @@ func AddInt64(addr *int64, delta int64) (new int64) {
|
|||||||
return atomic.AddInt64(addr, delta)
|
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)
|
return atomic.AddUint64(addr, delta)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,11 +157,11 @@ func StoreInt64(addr *int64, val int64) {
|
|||||||
atomic.StoreInt64(addr, val)
|
atomic.StoreInt64(addr, val)
|
||||||
}
|
}
|
||||||
|
|
||||||
func StoreUint32(addr *uint32, val uint32) {
|
func StoreUInt32(addr *uint32, val uint32) {
|
||||||
atomic.StoreUint32(addr, val)
|
atomic.StoreUint32(addr, val)
|
||||||
}
|
}
|
||||||
|
|
||||||
func StoreUint64(addr *uint64, val uint64) {
|
func StoreUInt64(addr *uint64, val uint64) {
|
||||||
atomic.StoreUint64(addr, val)
|
atomic.StoreUint64(addr, val)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,9 +5,21 @@ import (
|
|||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Reference[T any] struct {
|
//goland:noinspection GoUnusedGlobalVariable
|
||||||
reference *T
|
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] {
|
func NewReference[T any](reference *T) *Reference[T] {
|
||||||
return &Reference[T]{reference}
|
return &Reference[T]{reference}
|
||||||
@ -29,18 +41,22 @@ func (v *Reference[T]) CompareAndSwap(old, new *T) (swapped bool) {
|
|||||||
return CompareAndSwapPointer(&v.reference, old, new)
|
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) {
|
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) {
|
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) {
|
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) {
|
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] {
|
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) {
|
func CheckedGet[T any](array []T, index int) (T, exceptions.Exception) {
|
||||||
return exceptions.CatchIndexOutOfBound(func() T {
|
return exceptions.CatchIndexOutOfBound(func() T {
|
||||||
return array[index]
|
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 {
|
type arrayList[T lang.Object] struct {
|
||||||
|
lang.BaseObject
|
||||||
array []T
|
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] {
|
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 {
|
type arrayListIterator[T lang.Object] struct {
|
||||||
@ -51,7 +52,7 @@ func (a *arrayListIterator[T]) Next() (r T, err exceptions.Exception) {
|
|||||||
defer func() {
|
defer func() {
|
||||||
r := recover()
|
r := recover()
|
||||||
if r != nil {
|
if r != nil {
|
||||||
err = exceptions.NewNPE(r, nil)
|
err = exceptions.NewNPE("", exceptions.Cfg().SetCause(r))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
i := a.index
|
i := a.index
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func Test_arrayList_Get(t *testing.T) {
|
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++ {
|
for i := 0; i < l.Size()+1; i++ {
|
||||||
r, err := l.Get(i)
|
r, err := l.Get(i)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Loading…
Reference in New Issue
Block a user