github.com/qioalice/ekago/v3@v3.3.2-0.20221202205325-5c262d586ee4/ekaerr/namespace_private.go (about)

     1  // Copyright © 2020. All rights reserved.
     2  // Author: Ilya Stroy.
     3  // Contacts: iyuryevich@pm.me, https://github.com/qioalice
     4  // License: https://opensource.org/licenses/MIT
     5  
     6  package ekaerr
     7  
     8  import (
     9  	"sync"
    10  	"sync/atomic"
    11  )
    12  
    13  //noinspection GoSnakeCaseUsage
    14  const (
    15  	// _ERR_NAMESPACE_ARRAY_CACHE describes how many registered Namespaces will be
    16  	// stored into internal array instead of map.
    17  	// See registeredClassesArr, registeredClassesMap and classByID() for mor details.
    18  	_ERR_NAMESPACE_ARRAY_CACHE = 16
    19  )
    20  
    21  var (
    22  	// isCustomNamespaceDefined reports whether at least one custom namespace
    23  	// has been defined.
    24  	//
    25  	// DO NOT USE IT DIRECTLY! Use customNamespaceDefined() instead.
    26  	isCustomNamespaceDefined int32
    27  
    28  	// registeredNamespacesArr is a registered Namespaces storage.
    29  	// First N namespaces (_ERR_NAMESPACE_ARRAY_CACHE) will be saved into this array,
    30  	// others to the registeredNamespacesMap.
    31  	//
    32  	// Because array accessing faster than map's one it's an array, but
    33  	// user can define more than N namespaces. It's very rarely case, because
    34  	// I guess N is high enough but if that will happen, new namespaces will be stored
    35  	// into map. So, if in your app you have more than N error namespaces, guess
    36  	// performance array > map is not important to you.
    37  	//
    38  	// It's made to provide (*Error).Namespace() method working.
    39  	registeredNamespacesArr [_ERR_NAMESPACE_ARRAY_CACHE]Namespace
    40  
    41  	// registeredNamespacesMap used to save registered Namespaces when you have their
    42  	// more than N (_ERR_NAMESPACE_ARRAY_CACHE).
    43  	registeredNamespacesMap = struct {
    44  		sync.RWMutex
    45  		m map[NamespaceID]Namespace
    46  	}{
    47  		m: make(map[NamespaceID]Namespace),
    48  	}
    49  )
    50  
    51  // customNamespaceDefined reports whether at least one custom namespace has been
    52  // created by the user. Thread-safety.
    53  func customNamespaceDefined() bool {
    54  	return atomic.LoadInt32(&isCustomNamespaceDefined) != 0
    55  }
    56  
    57  // newNamespace is a Namespace's constructor.
    58  // There are several steps:
    59  //
    60  // 1. Getting a new available Namespace's ID.
    61  //
    62  // 2. Create a new Namespace object using provided 'name'.
    63  //
    64  // 3. Save it into internal Namespace's storage basing on its (Namespace's) ID.
    65  //
    66  // 4. If it was first call newNamespace() with 'custom' == true,
    67  //    regenerate all existed Classes' names adding namespace's names to the
    68  //    their full names.
    69  //
    70  // 5. Done.
    71  func newNamespace(name string, custom bool) Namespace {
    72  
    73  	if custom {
    74  		firstCustomNamespace :=
    75  			atomic.CompareAndSwapInt32(&isCustomNamespaceDefined, 0, 1)
    76  		if firstCustomNamespace {
    77  			rebuiltExistedClassNames()
    78  		}
    79  	}
    80  
    81  	n := Namespace{
    82  		id:   newNamespaceID(),
    83  		name: name,
    84  	}
    85  
    86  	if n.id >= _ERR_NAMESPACE_ARRAY_CACHE {
    87  		registeredNamespacesMap.Lock()
    88  		defer registeredNamespacesMap.Unlock()
    89  		registeredNamespacesMap.m[n.id] = n
    90  	} else {
    91  		registeredNamespacesMap.m[n.id] = n
    92  	}
    93  
    94  	return n
    95  }