mirror of https://github.com/openssl/openssl.git
				
				
				
			
		
			
				
	
	
		
			156 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
			
		
		
	
	
			156 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
| The sparse_array.c file contains an implementation of a sparse array that
 | |
| attempts to be both space and time efficient.
 | |
| 
 | |
| The sparse array is represented using a tree structure.  Each node in the
 | |
| tree contains a block of pointers to either the user supplied leaf values or
 | |
| to another node.
 | |
| 
 | |
| There are a number of parameters used to define the block size:
 | |
| 
 | |
|     OPENSSL_SA_BLOCK_BITS   Specifies the number of bits covered by each block
 | |
|     SA_BLOCK_MAX            Specifies the number of pointers in each block
 | |
|     SA_BLOCK_MASK           Specifies a bit mask to perform modulo block size
 | |
|     SA_BLOCK_MAX_LEVELS     Indicates the maximum possible height of the tree
 | |
| 
 | |
| These constants are inter-related:
 | |
|     SA_BLOCK_MAX        = 2 ^ OPENSSL_SA_BLOCK_BITS
 | |
|     SA_BLOCK_MASK       = SA_BLOCK_MAX - 1
 | |
|     SA_BLOCK_MAX_LEVELS = number of bits in size_t divided by
 | |
|                           OPENSSL_SA_BLOCK_BITS rounded up to the next multiple
 | |
|                           of OPENSSL_SA_BLOCK_BITS
 | |
| 
 | |
| OPENSSL_SA_BLOCK_BITS can be defined at compile time and this overrides the
 | |
| built in setting.
 | |
| 
 | |
| As a space and performance optimisation, the height of the tree is usually
 | |
| less than the maximum possible height.  Only sufficient height is allocated to
 | |
| accommodate the largest index added to the data structure.
 | |
| 
 | |
| The largest index used to add a value to the array determines the tree height:
 | |
| 
 | |
|         +----------------------+---------------------+
 | |
|         | Largest Added Index  |   Height of Tree    |
 | |
|         +----------------------+---------------------+
 | |
|         | SA_BLOCK_MAX     - 1 |          1          |
 | |
|         | SA_BLOCK_MAX ^ 2 - 1 |          2          |
 | |
|         | SA_BLOCK_MAX ^ 3 - 1 |          3          |
 | |
|         | ...                  |          ...        |
 | |
|         | size_t max           | SA_BLOCK_MAX_LEVELS |
 | |
|         +----------------------+---------------------+
 | |
| 
 | |
| The tree height is dynamically increased as needed based on additions.
 | |
| 
 | |
| An empty tree is represented by a NULL root pointer.  Inserting a value at
 | |
| index 0 results in the allocation of a top level node full of null pointers
 | |
| except for the single pointer to the user's data (N = SA_BLOCK_MAX for
 | |
| brevity):
 | |
| 
 | |
|         +----+
 | |
|         |Root|
 | |
|         |Node|
 | |
|         +-+--+
 | |
|           |
 | |
|           |
 | |
|           |
 | |
|           v
 | |
|         +-+-+---+---+---+---+
 | |
|         | 0 | 1 | 2 |...|N-1|
 | |
|         |   |nil|nil|...|nil|
 | |
|         +-+-+---+---+---+---+
 | |
|           |
 | |
|           |
 | |
|           |
 | |
|           v
 | |
|         +-+--+
 | |
|         |User|
 | |
|         |Data|
 | |
|         +----+
 | |
|     Index 0
 | |
| 
 | |
| 
 | |
| Inserting at element 2N+1 creates a new root node and pushes down the old root
 | |
| node.  It then creates a second second level node to hold the pointer to the
 | |
| user's new data:
 | |
| 
 | |
|         +----+
 | |
|         |Root|
 | |
|         |Node|
 | |
|         +-+--+
 | |
|           |
 | |
|           |
 | |
|           |
 | |
|           v
 | |
|         +-+-+---+---+---+---+
 | |
|         | 0 | 1 | 2 |...|N-1|
 | |
|         |   |nil|   |...|nil|
 | |
|         +-+-+---+-+-+---+---+
 | |
|           |       |
 | |
|           |       +------------------+
 | |
|           |                          |
 | |
|           v                          v
 | |
|         +-+-+---+---+---+---+      +-+-+---+---+---+---+
 | |
|         | 0 | 1 | 2 |...|N-1|      | 0 | 1 | 2 |...|N-1|
 | |
|         |nil|   |nil|...|nil|      |nil|   |nil|...|nil|
 | |
|         +-+-+---+---+---+---+      +---+-+-+---+---+---+
 | |
|           |                              |
 | |
|           |                              |
 | |
|           |                              |
 | |
|           v                              v
 | |
|         +-+--+                         +-+--+
 | |
|         |User|                         |User|
 | |
|         |Data|                         |Data|
 | |
|         +----+                         +----+
 | |
|     Index 0                       Index 2N+1
 | |
| 
 | |
| 
 | |
| The nodes themselves are allocated in a sparse manner.  Only nodes which exist
 | |
| along a path from the root of the tree to an added leaf will be allocated.
 | |
| The complexity is hidden and nodes are allocated on an as needed basis.
 | |
| Because the data is expected to be sparse this doesn't result in a large waste
 | |
| of space.
 | |
| 
 | |
| Values can be removed from the sparse array by setting their index position to
 | |
| NULL.  The data structure does not attempt to reclaim nodes or reduce the
 | |
| height of the tree on removal.  For example, now setting index 0 to NULL would
 | |
| result in:
 | |
| 
 | |
|         +----+
 | |
|         |Root|
 | |
|         |Node|
 | |
|         +-+--+
 | |
|           |
 | |
|           |
 | |
|           |
 | |
|           v
 | |
|         +-+-+---+---+---+---+
 | |
|         | 0 | 1 | 2 |...|N-1|
 | |
|         |   |nil|   |...|nil|
 | |
|         +-+-+---+-+-+---+---+
 | |
|           |       |
 | |
|           |       +------------------+
 | |
|           |                          |
 | |
|           v                          v
 | |
|         +-+-+---+---+---+---+      +-+-+---+---+---+---+
 | |
|         | 0 | 1 | 2 |...|N-1|      | 0 | 1 | 2 |...|N-1|
 | |
|         |nil|nil|nil|...|nil|      |nil|   |nil|...|nil|
 | |
|         +---+---+---+---+---+      +---+-+-+---+---+---+
 | |
|                                          |
 | |
|                                          |
 | |
|                                          |
 | |
|                                          v
 | |
|                                        +-+--+
 | |
|                                        |User|
 | |
|                                        |Data|
 | |
|                                        +----+
 | |
|                                   Index 2N+1
 | |
| 
 | |
| 
 | |
| Accesses to elements in the sparse array take O(log n) time where n is the
 | |
| largest element.  The base of the logarithm is SA_BLOCK_MAX, so for moderately
 | |
| small indices (e.g. NIDs), single level (constant time) access is achievable.
 | |
| Space usage is O(minimum(m, n log(n)) where m is the number of elements in the
 | |
| array.
 | |
| 
 | |
| Note: sparse arrays only include pointers to types.  Thus, SPARSE_ARRAY_OF(char)
 | |
| can be used to store a string.
 |