vector.c 3.83 KB
Newer Older
Swann Perarnau's avatar
Swann Perarnau committed
1
2
3
4
5
6
7
8
9
10
/*******************************************************************************
 * Copyright 2019 UChicago Argonne, LLC.
 * (c.f. AUTHORS, LICENSE)
 *
 * This file is part of the AML project.
 * For more info, see https://xgitlab.cels.anl.gov/argo/aml
 *
 * SPDX-License-Identifier: BSD-3-Clause
*******************************************************************************/

11
#include "aml.h"
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <assert.h>
#include <errno.h>

/*******************************************************************************
 * Vector type:
 * generic vector of elements, with contiguous allocation: elements are part of
 * the vector.
 * This type supports one unusual feature: elements must contain an int key, at
 * a static offset, and this key as configurable "null" value.
 ******************************************************************************/

int aml_vector_resize(struct aml_vector *vec, size_t newsize)
{
	assert(vec != NULL);
	/* we don't shrink */
27
	if (vec->nbelems > newsize)
28
29
30
31
		return 0;

	vec->ptr = realloc(vec->ptr, newsize * vec->sz);
	assert(vec->ptr != NULL);
32
	for (size_t i = vec->nbelems; i < newsize; i++) {
33
34
		vec->ptr[i] = calloc(1, vec->sz);
		assert(vec->ptr[i] != NULL);
35
36
37
38
39
40
41
		int *k = AML_VECTOR_KEY_P(vec, i);
		*k = vec->na;
	}
	vec->nbelems = newsize;
	return 0;
}

42
size_t aml_vector_size(const struct aml_vector *vec)
43
44
45
46
47
48
49
50
51
{
	assert(vec != NULL);
	return vec->nbelems;
}

/* returns pointer to elements at index id */
void *aml_vector_get(struct aml_vector *vec, int id)
{
	assert(vec != NULL);
52
53
54
55
56
57
58
	if (id == vec->na || id < 0)
		return NULL;

	size_t idx = (size_t)id;

	if (idx < vec->nbelems)
		return AML_VECTOR_ELT_P(vec, idx);
59
60
61
62
	else
		return NULL;
}

63
64
65
66
67
68
69
70
71
72
73
int aml_vector_getid(struct aml_vector *vec, void *elem)
{
	assert(vec != NULL);
	assert(elem != NULL);

	for (size_t i = 0; i < vec->nbelems; i++)
		if (vec->ptr[i] == elem)
			return i;
	return vec->na;
}

74
/* return index of first element with key */
75
int aml_vector_find(const struct aml_vector *vec, int key)
76
77
{
	assert(vec != NULL);
78
	for (size_t i = 0; i < vec->nbelems; i++) {
79
		int *k = AML_VECTOR_KEY_P(vec, i);
80
81

		if (*k == key)
82
83
84
85
86
87
88
89
90
			return i;
	}
	return vec->na;
}

void *aml_vector_add(struct aml_vector *vec)
{
	assert(vec != NULL);
	int idx = aml_vector_find(vec, vec->na);
91
92

	if (idx == vec->na) {
93
94
		/* exponential growth, good to amortize cost */
		idx = vec->nbelems;
95
		aml_vector_resize(vec, vec->nbelems * 2);
96
97
98
99
100
101
102
103
104
105
106
107
108
109
	}
	return AML_VECTOR_ELT_P(vec, idx);
}

void aml_vector_remove(struct aml_vector *vec, void *elem)
{
	assert(vec != NULL);
	assert(elem != NULL);

	int *k = AML_VECTOR_ELTKEY_P(vec, elem);
	*k = vec->na;
}

/*******************************************************************************
110
 * Create/Destroy:
111
112
 ******************************************************************************/

113
114
115
116
int aml_vector_create(struct aml_vector **vec, size_t reserve, size_t size,
		      size_t key, int na)
{
	struct aml_vector *ret = NULL;
117
	void **ptr;
118
119
120
121
122
123
124
125
126
127

	if (vec == NULL)
		return -AML_EINVAL;

	ret = malloc(sizeof(struct aml_vector));
	if (ret == NULL) {
		*vec = NULL;
		return -AML_ENOMEM;
	}

128
	ptr = calloc(reserve, sizeof(void *));
129
130
131
	if (ptr == NULL) {
		free(ret);
		*vec = NULL;
132
		return -AML_ENOMEM;
133
	}
134

135
136
137
138
139
140
141
142
143
144
145
146
	for (size_t i = 0; i < reserve; i++) {
		ptr[i] = calloc(1, size);
		if (ptr[i] == NULL) {
			/* avoid issues with size_t and negative values */
			for (size_t j = 0; j + 1 <= i; j++)
				free(ptr[i]);
			free(ret);
			*vec = NULL;
			return -AML_ENOMEM;
		}
	}

147
148
149
150
151
152
153
	ret->sz = size;
	ret->off = key;
	ret->na = na;
	ret->nbelems = reserve;
	ret->ptr = ptr;
	for (size_t i = 0; i < ret->nbelems; i++) {
		int *k = AML_VECTOR_KEY_P(ret, i);
154
155
		*k = na;
	}
156
157

	*vec = ret;
158
159
160
	return 0;
}

161
void aml_vector_destroy(struct aml_vector **vec)
162
{
163
164
	struct aml_vector *v;

165
166
167
	if (vec == NULL)
		return;

168
169
	v = *vec;
	if (v == NULL)
170
		return;
171

172
173
174
	for (size_t i = 0; i < v->nbelems; i++)
		free(v->ptr[i]);

175
176
	free(v->ptr);
	free(v);
177
	*vec = NULL;
178
}