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