github.com/qioalice/ekago/v3@v3.3.2-0.20221202205325-5c262d586ee4/ekaerr/class_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  )
    11  
    12  //noinspection GoSnakeCaseUsage
    13  
    14  const (
    15  	// _ERR_CLASS_ARRAY_CACHE describes how many registered Classes will be
    16  	// stored into internal array instead of map.
    17  	// See registeredClassesArr, registeredClassesMap and classByID() for mor details.
    18  	_ERR_CLASS_ARRAY_CACHE = 128
    19  )
    20  
    21  var (
    22  	// invalidClass is a special Class object that will be returned if we can not
    23  	// provide a natural Class object. For example at the: (*Error)(nil).Class().
    24  	invalidClass = Class{id: _ERR_INVALID_CLASS_ID}
    25  
    26  	// registeredClassesArr is a registered Classes storage.
    27  	// First N classes (_ERR_CLASS_ARRAY_CACHE) will be saved into this array,
    28  	// others to the registeredClassesMap.
    29  	//
    30  	// Because array accessing faster than map's one it's an array, but
    31  	// user can define more than N classes. It's very rarely case, because
    32  	// I guess N is high enough but if that will happen, new classes will be stored
    33  	// into map. So, if in your app you have more than N error classes, guess
    34  	// performance array > map is not important to you.
    35  	//
    36  	// It's made to provide (*Error).Class() method working.
    37  	registeredClassesArr [_ERR_CLASS_ARRAY_CACHE]Class
    38  
    39  	// registeredClassesMap used to save registered Classes when you have their
    40  	// more than N (_ERR_CLASS_ARRAY_CACHE).
    41  	registeredClassesMap = struct {
    42  		sync.RWMutex
    43  		m map[ClassID]Class
    44  	}{
    45  		m: make(map[ClassID]Class),
    46  	}
    47  )
    48  
    49  // fullClassName generates and returns full Class's name
    50  // using 'className' as Class's name, and 'namespaceName' as Namespace's
    51  // (or get a Namespace object from the pool using 'namespaceID' if 'namespaceName' is empty).
    52  func fullClassName(className, namespaceName string, namespaceID NamespaceID) string {
    53  
    54  	if namespaceName == "" {
    55  		namespaceName = namespaceByID(namespaceID, false).name
    56  	}
    57  	return namespaceName + "::" + className
    58  }
    59  
    60  // rebuiltExistedClassNames changes the names of existed (registered) Classes
    61  // (in the pool) use fullClassName() for their full names.
    62  // It guarantees that this function will be called only once when the first custom
    63  // namespace will be created.
    64  func rebuiltExistedClassNames() {
    65  	registeredClassesMap.Lock()
    66  	defer registeredClassesMap.Unlock()
    67  
    68  	for i, cls := range registeredClassesArr {
    69  		registeredClassesArr[i].fullName =
    70  			fullClassName(cls.fullName, "", cls.namespaceID)
    71  	}
    72  
    73  	for clsID, cls := range registeredClassesMap.m {
    74  		cls.fullName = fullClassName(cls.fullName, "", cls.namespaceID)
    75  		registeredClassesMap.m[clsID] = cls
    76  	}
    77  }
    78  
    79  // newClass is a Class's constructor.
    80  // There are several steps:
    81  //
    82  // 1. Getting a new available Class's ID.
    83  // 2. Create a new Class object using provided 'parentID', 'namespaceID', 'name'.
    84  // 3. Save it into the internal Class's storage basing on the its (Class's) ID.
    85  func newClass(parentID ClassID, namespaceID NamespaceID, name, fullName string) Class {
    86  
    87  	c := Class{
    88  		id:          newClassID(),
    89  		parentID:    parentID,
    90  		namespaceID: namespaceID,
    91  		name:        name,
    92  		fullName:    fullName,
    93  	}
    94  
    95  	if c.id >= _ERR_CLASS_ARRAY_CACHE {
    96  		registeredClassesMap.Lock()
    97  		defer registeredClassesMap.Unlock()
    98  		registeredClassesMap.m[c.id] = c
    99  	} else {
   100  		registeredClassesArr[c.id] = c
   101  	}
   102  
   103  	return c
   104  }