github.com/tursom/GoCollections@v0.3.10/util/Context.go (about)

     1  /*
     2   * Copyright (c) 2022 tursom. All rights reserved.
     3   * Use of this source code is governed by a GPL-3
     4   * license that can be found in the LICENSE file.
     5   */
     6  
     7  package util
     8  
     9  import (
    10  	"sync"
    11  	"unsafe"
    12  
    13  	"github.com/tursom/GoCollections/lang"
    14  	"github.com/tursom/GoCollections/lang/atomic"
    15  )
    16  
    17  var (
    18  	contextId atomic.Int32
    19  )
    20  
    21  type (
    22  	Context struct {
    23  		lang.BaseObject
    24  		contextId int32
    25  		keyId     atomic.Int32
    26  	}
    27  	ContextMap interface {
    28  		Get(key *ContextKey[any]) (any, bool)
    29  		Set(key *ContextKey[any], value any)
    30  	}
    31  	ContextKey[T any] struct {
    32  		lang.BaseObject
    33  		contextId int32
    34  		id        int32
    35  		supplier  func() any
    36  	}
    37  	contextMapImpl struct {
    38  		lang.BaseObject
    39  		contextId int32
    40  		array     []any
    41  	}
    42  	concurrentContextMap struct {
    43  		contextMapImpl
    44  		lock sync.Mutex
    45  	}
    46  )
    47  
    48  func NewContext() *Context {
    49  	return &Context{
    50  		contextId: contextId.Add(1),
    51  	}
    52  }
    53  
    54  func AllocateContextKey[T any](ctx *Context) *ContextKey[T] {
    55  	return AllocateContextKeyWithDefault[T](ctx, nil)
    56  }
    57  
    58  func AllocateContextKeyWithDefault[T any](ctx *Context, supplier func() T) *ContextKey[T] {
    59  	var s func() any
    60  	if supplier != nil {
    61  		s = func() any {
    62  			return supplier()
    63  		}
    64  	}
    65  	return &ContextKey[T]{
    66  		contextId: ctx.contextId,
    67  		id:        ctx.keyId.Add(1) - 1,
    68  		supplier:  s,
    69  	}
    70  }
    71  
    72  func (c *Context) NewMap() ContextMap {
    73  	return &contextMapImpl{
    74  		contextId: c.contextId,
    75  		//array:     make([]any, c.keyId.Load()),
    76  	}
    77  }
    78  
    79  func (c *Context) NewConcurrentMap() ContextMap {
    80  	return &concurrentContextMap{
    81  		contextMapImpl: contextMapImpl{
    82  			contextId: c.contextId,
    83  			//array:     make([]any, c.keyId.Load()),
    84  		},
    85  	}
    86  }
    87  
    88  func (k *ContextKey[T]) Get(m ContextMap) T {
    89  	value, _ := k.TryGet(m)
    90  	return value
    91  }
    92  
    93  func (k *ContextKey[T]) TryGet(m ContextMap) (T, bool) {
    94  	value, ok := m.Get(k.asNormalKey())
    95  	return lang.Cast[T](value), ok
    96  }
    97  
    98  func (k *ContextKey[T]) Set(m ContextMap, value T) {
    99  	m.Set(k.asNormalKey(), value)
   100  }
   101  
   102  func (m *contextMapImpl) Get(key *ContextKey[any]) (any, bool) {
   103  	if len(m.array) <= int(key.id) {
   104  		if key.supplier == nil {
   105  			return nil, false
   106  		} else {
   107  			supplier := key.supplier()
   108  			m.Set(key, supplier)
   109  			return supplier, true
   110  		}
   111  	} else {
   112  		return m.array[key.id], true
   113  	}
   114  }
   115  
   116  func (m *contextMapImpl) Set(key *ContextKey[any], value any) {
   117  	if len(m.array) <= int(key.id) {
   118  		newArray := make([]any, key.id+1)
   119  		copy(newArray, m.array)
   120  		m.array = newArray
   121  	}
   122  	m.array[key.id] = value
   123  }
   124  
   125  func (m *concurrentContextMap) Get(key *ContextKey[any]) (any, bool) {
   126  	if len(m.array) <= int(key.id) && key.supplier != nil {
   127  		m.Set(key, key.supplier())
   128  	}
   129  	return m.contextMapImpl.Get(key)
   130  }
   131  
   132  func (m *concurrentContextMap) Set(key *ContextKey[any], value any) {
   133  	m.lock.Lock()
   134  	defer m.lock.Unlock()
   135  	m.contextMapImpl.Set(key, value)
   136  }
   137  
   138  //goland:noinspection GoRedundantConversion
   139  func (k *ContextKey[T]) asNormalKey() *ContextKey[any] {
   140  	return (*ContextKey[any])(unsafe.Pointer(k))
   141  }