1321936Shselasky/*
2321936Shselasky * Copyright (c) 2011 Intel Corporation.  All rights reserved.
3321936Shselasky *
4321936Shselasky * This software is available to you under a choice of one of two
5321936Shselasky * licenses.  You may choose to be licensed under the terms of the GNU
6321936Shselasky * General Public License (GPL) Version 2, available from the file
7321936Shselasky * COPYING in the main directory of this source tree, or the
8321936Shselasky * OpenIB.org BSD license below:
9321936Shselasky *
10321936Shselasky *     Redistribution and use in source and binary forms, with or
11321936Shselasky *     without modification, are permitted provided that the following
12321936Shselasky *     conditions are met:
13321936Shselasky *
14321936Shselasky *      - Redistributions of source code must retain the above
15321936Shselasky *        copyright notice, this list of conditions and the following
16321936Shselasky *        disclaimer.
17321936Shselasky *
18321936Shselasky *      - Redistributions in binary form must reproduce the above
19321936Shselasky *        copyright notice, this list of conditions and the following
20321936Shselasky *        disclaimer in the documentation and/or other materials
21321936Shselasky *        provided with the distribution.
22321936Shselasky *
23321936Shselasky * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24321936Shselasky * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25321936Shselasky * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26321936Shselasky * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27321936Shselasky * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28321936Shselasky * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29321936Shselasky * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30321936Shselasky * SOFTWARE.
31321936Shselasky *
32321936Shselasky */
33321936Shselasky
34321936Shselasky#include <config.h>
35321936Shselasky
36321936Shselasky#include <errno.h>
37321936Shselasky#include <sys/types.h>
38321936Shselasky#include <stdlib.h>
39321936Shselasky
40321936Shselasky#include "indexer.h"
41321936Shselasky
42321936Shselasky/*
43321936Shselasky * Indexer - to find a structure given an index
44321936Shselasky *
45321936Shselasky * We store pointers using a double lookup and return an index to the
46321936Shselasky * user which is then used to retrieve the pointer.  The upper bits of
47321936Shselasky * the index are itself an index into an array of memory allocations.
48321936Shselasky * The lower bits specify the offset into the allocated memory where
49321936Shselasky * the pointer is stored.
50321936Shselasky *
51321936Shselasky * This allows us to adjust the number of pointers stored by the index
52321936Shselasky * list without taking a lock during data lookups.
53321936Shselasky */
54321936Shselasky
55321936Shselaskystatic int idx_grow(struct indexer *idx)
56321936Shselasky{
57321936Shselasky	union idx_entry *entry;
58321936Shselasky	int i, start_index;
59321936Shselasky
60321936Shselasky	if (idx->size >= IDX_ARRAY_SIZE)
61321936Shselasky		goto nomem;
62321936Shselasky
63321936Shselasky	idx->array[idx->size] = calloc(IDX_ENTRY_SIZE, sizeof(union idx_entry));
64321936Shselasky	if (!idx->array[idx->size])
65321936Shselasky		goto nomem;
66321936Shselasky
67321936Shselasky	entry = idx->array[idx->size];
68321936Shselasky	start_index = idx->size << IDX_ENTRY_BITS;
69321936Shselasky	entry[IDX_ENTRY_SIZE - 1].next = idx->free_list;
70321936Shselasky
71321936Shselasky	for (i = IDX_ENTRY_SIZE - 2; i >= 0; i--)
72321936Shselasky		entry[i].next = start_index + i + 1;
73321936Shselasky
74321936Shselasky	/* Index 0 is reserved */
75321936Shselasky	if (start_index == 0)
76321936Shselasky		start_index++;
77321936Shselasky	idx->free_list = start_index;
78321936Shselasky	idx->size++;
79321936Shselasky	return start_index;
80321936Shselasky
81321936Shselaskynomem:
82321936Shselasky	errno = ENOMEM;
83321936Shselasky	return -1;
84321936Shselasky}
85321936Shselasky
86321936Shselaskyint idx_insert(struct indexer *idx, void *item)
87321936Shselasky{
88321936Shselasky	union idx_entry *entry;
89321936Shselasky	int index;
90321936Shselasky
91321936Shselasky	if ((index = idx->free_list) == 0) {
92321936Shselasky		if ((index = idx_grow(idx)) <= 0)
93321936Shselasky			return index;
94321936Shselasky	}
95321936Shselasky
96321936Shselasky	entry = idx->array[idx_array_index(index)];
97321936Shselasky	idx->free_list = entry[idx_entry_index(index)].next;
98321936Shselasky	entry[idx_entry_index(index)].item = item;
99321936Shselasky	return index;
100321936Shselasky}
101321936Shselasky
102321936Shselaskyvoid *idx_remove(struct indexer *idx, int index)
103321936Shselasky{
104321936Shselasky	union idx_entry *entry;
105321936Shselasky	void *item;
106321936Shselasky
107321936Shselasky	entry = idx->array[idx_array_index(index)];
108321936Shselasky	item = entry[idx_entry_index(index)].item;
109321936Shselasky	entry[idx_entry_index(index)].next = idx->free_list;
110321936Shselasky	idx->free_list = index;
111321936Shselasky	return item;
112321936Shselasky}
113321936Shselasky
114321936Shselaskyvoid idx_replace(struct indexer *idx, int index, void *item)
115321936Shselasky{
116321936Shselasky	union idx_entry *entry;
117321936Shselasky
118321936Shselasky	entry = idx->array[idx_array_index(index)];
119321936Shselasky	entry[idx_entry_index(index)].item = item;
120321936Shselasky}
121321936Shselasky
122321936Shselasky
123321936Shselaskystatic int idm_grow(struct index_map *idm, int index)
124321936Shselasky{
125321936Shselasky	idm->array[idx_array_index(index)] = calloc(IDX_ENTRY_SIZE, sizeof(void *));
126321936Shselasky	if (!idm->array[idx_array_index(index)])
127321936Shselasky		goto nomem;
128321936Shselasky
129321936Shselasky	return index;
130321936Shselasky
131321936Shselaskynomem:
132321936Shselasky	errno = ENOMEM;
133321936Shselasky	return -1;
134321936Shselasky}
135321936Shselasky
136321936Shselaskyint idm_set(struct index_map *idm, int index, void *item)
137321936Shselasky{
138321936Shselasky	void **entry;
139321936Shselasky
140321936Shselasky	if (index > IDX_MAX_INDEX) {
141321936Shselasky		errno = ENOMEM;
142321936Shselasky		return -1;
143321936Shselasky	}
144321936Shselasky
145321936Shselasky	if (!idm->array[idx_array_index(index)]) {
146321936Shselasky		if (idm_grow(idm, index) < 0)
147321936Shselasky			return -1;
148321936Shselasky	}
149321936Shselasky
150321936Shselasky	entry = idm->array[idx_array_index(index)];
151321936Shselasky	entry[idx_entry_index(index)] = item;
152321936Shselasky	return index;
153321936Shselasky}
154321936Shselasky
155321936Shselaskyvoid *idm_clear(struct index_map *idm, int index)
156321936Shselasky{
157321936Shselasky	void **entry;
158321936Shselasky	void *item;
159321936Shselasky
160321936Shselasky	entry = idm->array[idx_array_index(index)];
161321936Shselasky	item = entry[idx_entry_index(index)];
162321936Shselasky	entry[idx_entry_index(index)] = NULL;
163321936Shselasky	return item;
164321936Shselasky}
165