123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155 |
- 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.
|