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 }