xref: /f-stack/freebsd/contrib/ck/src/ck_array.c (revision 22ce4aff)
1*22ce4affSfengbojiang /*
2*22ce4affSfengbojiang  * Copyright 2013-2015 Samy Al Bahra
3*22ce4affSfengbojiang  * Copyright 2013-2014 AppNexus, Inc.
4*22ce4affSfengbojiang  * All rights reserved.
5*22ce4affSfengbojiang  *
6*22ce4affSfengbojiang  * Redistribution and use in source and binary forms, with or without
7*22ce4affSfengbojiang  * modification, are permitted provided that the following conditions
8*22ce4affSfengbojiang  * are met:
9*22ce4affSfengbojiang  * 1. Redistributions of source code must retain the above copyright
10*22ce4affSfengbojiang  *    notice, this list of conditions and the following disclaimer.
11*22ce4affSfengbojiang  * 2. Redistributions in binary form must reproduce the above copyright
12*22ce4affSfengbojiang  *    notice, this list of conditions and the following disclaimer in the
13*22ce4affSfengbojiang  *    documentation and/or other materials provided with the distribution.
14*22ce4affSfengbojiang  *
15*22ce4affSfengbojiang  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16*22ce4affSfengbojiang  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17*22ce4affSfengbojiang  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18*22ce4affSfengbojiang  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19*22ce4affSfengbojiang  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20*22ce4affSfengbojiang  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21*22ce4affSfengbojiang  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22*22ce4affSfengbojiang  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23*22ce4affSfengbojiang  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24*22ce4affSfengbojiang  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25*22ce4affSfengbojiang  * SUCH DAMAGE.
26*22ce4affSfengbojiang  */
27*22ce4affSfengbojiang 
28*22ce4affSfengbojiang #include <ck_array.h>
29*22ce4affSfengbojiang #include <ck_cc.h>
30*22ce4affSfengbojiang #include <ck_pr.h>
31*22ce4affSfengbojiang #include <ck_stdbool.h>
32*22ce4affSfengbojiang #include <ck_string.h>
33*22ce4affSfengbojiang 
34*22ce4affSfengbojiang static struct _ck_array *
ck_array_create(struct ck_malloc * allocator,unsigned int length)35*22ce4affSfengbojiang ck_array_create(struct ck_malloc *allocator, unsigned int length)
36*22ce4affSfengbojiang {
37*22ce4affSfengbojiang 	struct _ck_array *active;
38*22ce4affSfengbojiang 
39*22ce4affSfengbojiang 	active = allocator->malloc(sizeof(struct _ck_array) + sizeof(void *) * length);
40*22ce4affSfengbojiang 	if (active == NULL)
41*22ce4affSfengbojiang 		return NULL;
42*22ce4affSfengbojiang 
43*22ce4affSfengbojiang 	active->n_committed = 0;
44*22ce4affSfengbojiang 	active->length = length;
45*22ce4affSfengbojiang 
46*22ce4affSfengbojiang 	return active;
47*22ce4affSfengbojiang }
48*22ce4affSfengbojiang 
49*22ce4affSfengbojiang bool
ck_array_init(struct ck_array * array,unsigned int mode,struct ck_malloc * allocator,unsigned int length)50*22ce4affSfengbojiang ck_array_init(struct ck_array *array, unsigned int mode, struct ck_malloc *allocator, unsigned int length)
51*22ce4affSfengbojiang {
52*22ce4affSfengbojiang 	struct _ck_array *active;
53*22ce4affSfengbojiang 
54*22ce4affSfengbojiang 	(void)mode;
55*22ce4affSfengbojiang 
56*22ce4affSfengbojiang 	if (allocator->realloc == NULL ||
57*22ce4affSfengbojiang 	    allocator->malloc == NULL ||
58*22ce4affSfengbojiang 	    allocator->free == NULL ||
59*22ce4affSfengbojiang 	    length == 0)
60*22ce4affSfengbojiang 		return false;
61*22ce4affSfengbojiang 
62*22ce4affSfengbojiang 	active = ck_array_create(allocator, length);
63*22ce4affSfengbojiang 	if (active == NULL)
64*22ce4affSfengbojiang 		return false;
65*22ce4affSfengbojiang 
66*22ce4affSfengbojiang 	array->n_entries = 0;
67*22ce4affSfengbojiang 	array->allocator = allocator;
68*22ce4affSfengbojiang 	array->active = active;
69*22ce4affSfengbojiang 	array->transaction = NULL;
70*22ce4affSfengbojiang 	return true;
71*22ce4affSfengbojiang }
72*22ce4affSfengbojiang 
73*22ce4affSfengbojiang bool
ck_array_put(struct ck_array * array,void * value)74*22ce4affSfengbojiang ck_array_put(struct ck_array *array, void *value)
75*22ce4affSfengbojiang {
76*22ce4affSfengbojiang 	struct _ck_array *target;
77*22ce4affSfengbojiang 	unsigned int size;
78*22ce4affSfengbojiang 
79*22ce4affSfengbojiang 	/*
80*22ce4affSfengbojiang 	 * If no transaction copy has been necessary, attempt to do in-place
81*22ce4affSfengbojiang 	 * modification of the array.
82*22ce4affSfengbojiang 	 */
83*22ce4affSfengbojiang 	if (array->transaction == NULL) {
84*22ce4affSfengbojiang 		target = array->active;
85*22ce4affSfengbojiang 
86*22ce4affSfengbojiang 		if (array->n_entries == target->length) {
87*22ce4affSfengbojiang 			size = target->length << 1;
88*22ce4affSfengbojiang 
89*22ce4affSfengbojiang 			target = array->allocator->realloc(target,
90*22ce4affSfengbojiang 			    sizeof(struct _ck_array) + sizeof(void *) * array->n_entries,
91*22ce4affSfengbojiang 			    sizeof(struct _ck_array) + sizeof(void *) * size,
92*22ce4affSfengbojiang 			    true);
93*22ce4affSfengbojiang 
94*22ce4affSfengbojiang 			if (target == NULL)
95*22ce4affSfengbojiang 				return false;
96*22ce4affSfengbojiang 
97*22ce4affSfengbojiang 			ck_pr_store_uint(&target->length, size);
98*22ce4affSfengbojiang 
99*22ce4affSfengbojiang 			/* Serialize with respect to contents. */
100*22ce4affSfengbojiang 			ck_pr_fence_store();
101*22ce4affSfengbojiang 			ck_pr_store_ptr(&array->active, target);
102*22ce4affSfengbojiang 		}
103*22ce4affSfengbojiang 
104*22ce4affSfengbojiang 		target->values[array->n_entries++] = value;
105*22ce4affSfengbojiang 		return true;
106*22ce4affSfengbojiang 	}
107*22ce4affSfengbojiang 
108*22ce4affSfengbojiang 	target = array->transaction;
109*22ce4affSfengbojiang 	if (array->n_entries == target->length) {
110*22ce4affSfengbojiang 		size = target->length << 1;
111*22ce4affSfengbojiang 
112*22ce4affSfengbojiang 		target = array->allocator->realloc(target,
113*22ce4affSfengbojiang 		    sizeof(struct _ck_array) + sizeof(void *) * array->n_entries,
114*22ce4affSfengbojiang 		    sizeof(struct _ck_array) + sizeof(void *) * size,
115*22ce4affSfengbojiang 		    true);
116*22ce4affSfengbojiang 
117*22ce4affSfengbojiang 		if (target == NULL)
118*22ce4affSfengbojiang 			return false;
119*22ce4affSfengbojiang 
120*22ce4affSfengbojiang 		target->length = size;
121*22ce4affSfengbojiang 		array->transaction = target;
122*22ce4affSfengbojiang 	}
123*22ce4affSfengbojiang 
124*22ce4affSfengbojiang 	target->values[array->n_entries++] = value;
125*22ce4affSfengbojiang 	return false;
126*22ce4affSfengbojiang }
127*22ce4affSfengbojiang 
128*22ce4affSfengbojiang int
ck_array_put_unique(struct ck_array * array,void * value)129*22ce4affSfengbojiang ck_array_put_unique(struct ck_array *array, void *value)
130*22ce4affSfengbojiang {
131*22ce4affSfengbojiang 	unsigned int i, limit;
132*22ce4affSfengbojiang 	void **v;
133*22ce4affSfengbojiang 
134*22ce4affSfengbojiang 	limit = array->n_entries;
135*22ce4affSfengbojiang 	if (array->transaction != NULL) {
136*22ce4affSfengbojiang 		v = array->transaction->values;
137*22ce4affSfengbojiang 	} else {
138*22ce4affSfengbojiang 		v = array->active->values;
139*22ce4affSfengbojiang 	}
140*22ce4affSfengbojiang 
141*22ce4affSfengbojiang 	for (i = 0; i < limit; i++) {
142*22ce4affSfengbojiang 		if (v[i] == value)
143*22ce4affSfengbojiang 			return 1;
144*22ce4affSfengbojiang 	}
145*22ce4affSfengbojiang 
146*22ce4affSfengbojiang 	return -!ck_array_put(array, value);
147*22ce4affSfengbojiang }
148*22ce4affSfengbojiang 
149*22ce4affSfengbojiang bool
ck_array_remove(struct ck_array * array,void * value)150*22ce4affSfengbojiang ck_array_remove(struct ck_array *array, void *value)
151*22ce4affSfengbojiang {
152*22ce4affSfengbojiang 	struct _ck_array *target;
153*22ce4affSfengbojiang 	unsigned int i;
154*22ce4affSfengbojiang 
155*22ce4affSfengbojiang 	if (array->transaction != NULL) {
156*22ce4affSfengbojiang 		target = array->transaction;
157*22ce4affSfengbojiang 
158*22ce4affSfengbojiang 		for (i = 0; i < array->n_entries; i++) {
159*22ce4affSfengbojiang 			if (target->values[i] == value) {
160*22ce4affSfengbojiang 				target->values[i] = target->values[--array->n_entries];
161*22ce4affSfengbojiang 				return true;
162*22ce4affSfengbojiang 			}
163*22ce4affSfengbojiang 		}
164*22ce4affSfengbojiang 
165*22ce4affSfengbojiang 		return false;
166*22ce4affSfengbojiang 	}
167*22ce4affSfengbojiang 
168*22ce4affSfengbojiang 	target = array->active;
169*22ce4affSfengbojiang 
170*22ce4affSfengbojiang 	for (i = 0; i < array->n_entries; i++) {
171*22ce4affSfengbojiang 		if (target->values[i] == value)
172*22ce4affSfengbojiang 			break;
173*22ce4affSfengbojiang 	}
174*22ce4affSfengbojiang 
175*22ce4affSfengbojiang 	if (i == array->n_entries)
176*22ce4affSfengbojiang 		return false;
177*22ce4affSfengbojiang 
178*22ce4affSfengbojiang 	/* If there are pending additions, immediately eliminate the operation. */
179*22ce4affSfengbojiang 	if (target->n_committed != array->n_entries) {
180*22ce4affSfengbojiang 		ck_pr_store_ptr(&target->values[i], target->values[--array->n_entries]);
181*22ce4affSfengbojiang 		return true;
182*22ce4affSfengbojiang 	}
183*22ce4affSfengbojiang 
184*22ce4affSfengbojiang 	/*
185*22ce4affSfengbojiang 	 * The assumption is that these allocations are small to begin with.
186*22ce4affSfengbojiang 	 * If there is no immediate opportunity for transaction, allocate a
187*22ce4affSfengbojiang 	 * transactional array which will be applied upon commit time.
188*22ce4affSfengbojiang 	 */
189*22ce4affSfengbojiang 	target = ck_array_create(array->allocator, array->n_entries);
190*22ce4affSfengbojiang 	if (target == NULL)
191*22ce4affSfengbojiang 		return false;
192*22ce4affSfengbojiang 
193*22ce4affSfengbojiang 	memcpy(target->values, array->active->values, sizeof(void *) * array->n_entries);
194*22ce4affSfengbojiang 	target->length = array->n_entries;
195*22ce4affSfengbojiang 	target->n_committed = array->n_entries;
196*22ce4affSfengbojiang 	target->values[i] = target->values[--array->n_entries];
197*22ce4affSfengbojiang 
198*22ce4affSfengbojiang 	array->transaction = target;
199*22ce4affSfengbojiang 	return true;
200*22ce4affSfengbojiang }
201*22ce4affSfengbojiang 
202*22ce4affSfengbojiang bool
ck_array_commit(ck_array_t * array)203*22ce4affSfengbojiang ck_array_commit(ck_array_t *array)
204*22ce4affSfengbojiang {
205*22ce4affSfengbojiang 	struct _ck_array *m = array->transaction;
206*22ce4affSfengbojiang 
207*22ce4affSfengbojiang 	if (m != NULL) {
208*22ce4affSfengbojiang 		struct _ck_array *p;
209*22ce4affSfengbojiang 
210*22ce4affSfengbojiang 		m->n_committed = array->n_entries;
211*22ce4affSfengbojiang 		ck_pr_fence_store();
212*22ce4affSfengbojiang 		p = array->active;
213*22ce4affSfengbojiang 		ck_pr_store_ptr(&array->active, m);
214*22ce4affSfengbojiang 		array->allocator->free(p, sizeof(struct _ck_array) +
215*22ce4affSfengbojiang 		    p->length * sizeof(void *), true);
216*22ce4affSfengbojiang 		array->transaction = NULL;
217*22ce4affSfengbojiang 
218*22ce4affSfengbojiang 		return true;
219*22ce4affSfengbojiang 	}
220*22ce4affSfengbojiang 
221*22ce4affSfengbojiang 	ck_pr_fence_store();
222*22ce4affSfengbojiang 	ck_pr_store_uint(&array->active->n_committed, array->n_entries);
223*22ce4affSfengbojiang 	return true;
224*22ce4affSfengbojiang }
225*22ce4affSfengbojiang 
226*22ce4affSfengbojiang void
ck_array_deinit(struct ck_array * array,bool defer)227*22ce4affSfengbojiang ck_array_deinit(struct ck_array *array, bool defer)
228*22ce4affSfengbojiang {
229*22ce4affSfengbojiang 
230*22ce4affSfengbojiang 	array->allocator->free(array->active,
231*22ce4affSfengbojiang 	    sizeof(struct _ck_array) + sizeof(void *) * array->active->length, defer);
232*22ce4affSfengbojiang 
233*22ce4affSfengbojiang 	if (array->transaction != NULL) {
234*22ce4affSfengbojiang 		array->allocator->free(array->transaction,
235*22ce4affSfengbojiang 		    sizeof(struct _ck_array) + sizeof(void *) * array->transaction->length, defer);
236*22ce4affSfengbojiang 	}
237*22ce4affSfengbojiang 
238*22ce4affSfengbojiang 	array->transaction = array->active = NULL;
239*22ce4affSfengbojiang 	return;
240*22ce4affSfengbojiang }
241