174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
1
|
/*
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
2
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
3
|
*
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
4
|
* Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
5
|
*
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
6
|
* Redistribution and use in source and binary forms, with or without
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
7
|
* modification, are permitted provided that the following conditions are met:
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
8
|
*
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
9
|
* 1. Redistributions of source code must retain the above copyright
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
10
|
* notice, this list of conditions and the following disclaimer.
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
11
|
*
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
12
|
* 2. Redistributions in binary form must reproduce the above copyright
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
13
|
* notice, this list of conditions and the following disclaimer in the
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
14
|
* documentation and/or other materials provided with the distribution.
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
15
|
*
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
16
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
17
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
18
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
19
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
20
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
21
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
22
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
23
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
24
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
25
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
26
|
* POSSIBILITY OF SUCH DAMAGE.
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
27
|
*/
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
28
|
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
29
|
#include "cx/list.h"
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
30
|
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
31
|
#include <string.h>
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
32
|
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
33
|
// <editor-fold desc="Store Pointers Functionality">
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
34
|
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
35
|
static _Thread_local cx_compare_func cx_pl_cmpfunc_impl;
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
36
|
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
37
|
static int cx_pl_cmpfunc(
|
|
324
|
38
|
const void *l,
|
|
|
39
|
const void *r
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
40
|
) {
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
41
|
void *const *lptr = l;
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
42
|
void *const *rptr = r;
|
|
324
|
43
|
const void *left = lptr == NULL ? NULL : *lptr;
|
|
|
44
|
const void *right = rptr == NULL ? NULL : *rptr;
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
45
|
return cx_pl_cmpfunc_impl(left, right);
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
46
|
}
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
47
|
|
|
324
|
48
|
static void cx_pl_hack_cmpfunc(const struct cx_list_s *list) {
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
49
|
// cast away const - this is the hacky thing
|
|
324
|
50
|
struct cx_collection_s *l = (struct cx_collection_s*) &list->collection;
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
51
|
cx_pl_cmpfunc_impl = l->cmpfunc;
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
52
|
l->cmpfunc = cx_pl_cmpfunc;
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
53
|
}
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
54
|
|
|
324
|
55
|
static void cx_pl_unhack_cmpfunc(const struct cx_list_s *list) {
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
56
|
// cast away const - this is the hacky thing
|
|
324
|
57
|
struct cx_collection_s *l = (struct cx_collection_s*) &list->collection;
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
58
|
l->cmpfunc = cx_pl_cmpfunc_impl;
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
59
|
}
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
60
|
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
61
|
static void cx_pl_destructor(struct cx_list_s *list) {
|
|
440
|
62
|
list->climpl->deallocate(list);
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
63
|
}
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
64
|
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
65
|
static int cx_pl_insert_element(
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
66
|
struct cx_list_s *list,
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
67
|
size_t index,
|
|
324
|
68
|
const void *element
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
69
|
) {
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
70
|
return list->climpl->insert_element(list, index, &element);
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
71
|
}
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
72
|
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
73
|
static size_t cx_pl_insert_array(
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
74
|
struct cx_list_s *list,
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
75
|
size_t index,
|
|
324
|
76
|
const void *array,
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
77
|
size_t n
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
78
|
) {
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
79
|
return list->climpl->insert_array(list, index, array, n);
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
80
|
}
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
81
|
|
|
324
|
82
|
static size_t cx_pl_insert_sorted(
|
|
|
83
|
struct cx_list_s *list,
|
|
|
84
|
const void *array,
|
|
|
85
|
size_t n
|
|
|
86
|
) {
|
|
|
87
|
cx_pl_hack_cmpfunc(list);
|
|
|
88
|
size_t result = list->climpl->insert_sorted(list, array, n);
|
|
|
89
|
cx_pl_unhack_cmpfunc(list);
|
|
|
90
|
return result;
|
|
|
91
|
}
|
|
|
92
|
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
93
|
static int cx_pl_insert_iter(
|
|
324
|
94
|
struct cx_iterator_s *iter,
|
|
|
95
|
const void *elem,
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
96
|
int prepend
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
97
|
) {
|
|
324
|
98
|
struct cx_list_s *list = iter->src_handle.m;
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
99
|
return list->climpl->insert_iter(iter, &elem, prepend);
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
100
|
}
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
101
|
|
|
440
|
102
|
static size_t cx_pl_remove(
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
103
|
struct cx_list_s *list,
|
|
440
|
104
|
size_t index,
|
|
|
105
|
size_t num,
|
|
|
106
|
void *targetbuf
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
107
|
) {
|
|
440
|
108
|
return list->climpl->remove(list, index, num, targetbuf);
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
109
|
}
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
110
|
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
111
|
static void cx_pl_clear(struct cx_list_s *list) {
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
112
|
list->climpl->clear(list);
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
113
|
}
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
114
|
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
115
|
static int cx_pl_swap(
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
116
|
struct cx_list_s *list,
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
117
|
size_t i,
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
118
|
size_t j
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
119
|
) {
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
120
|
return list->climpl->swap(list, i, j);
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
121
|
}
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
122
|
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
123
|
static void *cx_pl_at(
|
|
324
|
124
|
const struct cx_list_s *list,
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
125
|
size_t index
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
126
|
) {
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
127
|
void **ptr = list->climpl->at(list, index);
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
128
|
return ptr == NULL ? NULL : *ptr;
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
129
|
}
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
130
|
|
|
253
|
131
|
static ssize_t cx_pl_find_remove(
|
|
|
132
|
struct cx_list_s *list,
|
|
324
|
133
|
const void *elem,
|
|
253
|
134
|
bool remove
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
135
|
) {
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
136
|
cx_pl_hack_cmpfunc(list);
|
|
253
|
137
|
ssize_t ret = list->climpl->find_remove(list, &elem, remove);
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
138
|
cx_pl_unhack_cmpfunc(list);
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
139
|
return ret;
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
140
|
}
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
141
|
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
142
|
static void cx_pl_sort(struct cx_list_s *list) {
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
143
|
cx_pl_hack_cmpfunc(list);
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
144
|
list->climpl->sort(list);
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
145
|
cx_pl_unhack_cmpfunc(list);
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
146
|
}
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
147
|
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
148
|
static int cx_pl_compare(
|
|
324
|
149
|
const struct cx_list_s *list,
|
|
|
150
|
const struct cx_list_s *other
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
151
|
) {
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
152
|
cx_pl_hack_cmpfunc(list);
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
153
|
int ret = list->climpl->compare(list, other);
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
154
|
cx_pl_unhack_cmpfunc(list);
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
155
|
return ret;
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
156
|
}
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
157
|
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
158
|
static void cx_pl_reverse(struct cx_list_s *list) {
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
159
|
list->climpl->reverse(list);
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
160
|
}
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
161
|
|
|
324
|
162
|
static void *cx_pl_iter_current(const void *it) {
|
|
|
163
|
const struct cx_iterator_s *iter = it;
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
164
|
void **ptr = iter->base.current_impl(it);
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
165
|
return ptr == NULL ? NULL : *ptr;
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
166
|
}
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
167
|
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
168
|
static struct cx_iterator_s cx_pl_iterator(
|
|
324
|
169
|
const struct cx_list_s *list,
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
170
|
size_t index,
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
171
|
bool backwards
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
172
|
) {
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
173
|
struct cx_iterator_s iter = list->climpl->iterator(list, index, backwards);
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
174
|
iter.base.current_impl = iter.base.current;
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
175
|
iter.base.current = cx_pl_iter_current;
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
176
|
return iter;
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
177
|
}
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
178
|
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
179
|
static cx_list_class cx_pointer_list_class = {
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
180
|
cx_pl_destructor,
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
181
|
cx_pl_insert_element,
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
182
|
cx_pl_insert_array,
|
|
324
|
183
|
cx_pl_insert_sorted,
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
184
|
cx_pl_insert_iter,
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
185
|
cx_pl_remove,
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
186
|
cx_pl_clear,
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
187
|
cx_pl_swap,
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
188
|
cx_pl_at,
|
|
253
|
189
|
cx_pl_find_remove,
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
190
|
cx_pl_sort,
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
191
|
cx_pl_compare,
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
192
|
cx_pl_reverse,
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
193
|
cx_pl_iterator,
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
194
|
};
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
195
|
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
196
|
void cxListStoreObjects(CxList *list) {
|
|
324
|
197
|
list->collection.store_pointer = false;
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
198
|
if (list->climpl != NULL) {
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
199
|
list->cl = list->climpl;
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
200
|
list->climpl = NULL;
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
201
|
}
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
202
|
}
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
203
|
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
204
|
void cxListStorePointers(CxList *list) {
|
|
324
|
205
|
list->collection.elem_size = sizeof(void *);
|
|
|
206
|
list->collection.store_pointer = true;
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
207
|
list->climpl = list->cl;
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
208
|
list->cl = &cx_pointer_list_class;
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
209
|
}
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
210
|
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
211
|
// </editor-fold>
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
212
|
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
213
|
// <editor-fold desc="empty list implementation">
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
214
|
|
|
440
|
215
|
static void cx_emptyl_noop(cx_attr_unused CxList *list) {
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
216
|
// this is a noop, but MUST be implemented
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
217
|
}
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
218
|
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
219
|
static void *cx_emptyl_at(
|
|
440
|
220
|
cx_attr_unused const struct cx_list_s *list,
|
|
|
221
|
cx_attr_unused size_t index
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
222
|
) {
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
223
|
return NULL;
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
224
|
}
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
225
|
|
|
253
|
226
|
static ssize_t cx_emptyl_find_remove(
|
|
440
|
227
|
cx_attr_unused struct cx_list_s *list,
|
|
|
228
|
cx_attr_unused const void *elem,
|
|
|
229
|
cx_attr_unused bool remove
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
230
|
) {
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
231
|
return -1;
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
232
|
}
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
233
|
|
|
440
|
234
|
static bool cx_emptyl_iter_valid(cx_attr_unused const void *iter) {
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
235
|
return false;
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
236
|
}
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
237
|
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
238
|
static CxIterator cx_emptyl_iterator(
|
|
324
|
239
|
const struct cx_list_s *list,
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
240
|
size_t index,
|
|
440
|
241
|
cx_attr_unused bool backwards
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
242
|
) {
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
243
|
CxIterator iter = {0};
|
|
324
|
244
|
iter.src_handle.c = list;
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
245
|
iter.index = index;
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
246
|
iter.base.valid = cx_emptyl_iter_valid;
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
247
|
return iter;
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
248
|
}
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
249
|
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
250
|
static cx_list_class cx_empty_list_class = {
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
251
|
cx_emptyl_noop,
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
252
|
NULL,
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
253
|
NULL,
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
254
|
NULL,
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
255
|
NULL,
|
|
324
|
256
|
NULL,
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
257
|
cx_emptyl_noop,
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
258
|
NULL,
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
259
|
cx_emptyl_at,
|
|
253
|
260
|
cx_emptyl_find_remove,
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
261
|
cx_emptyl_noop,
|
|
324
|
262
|
NULL,
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
263
|
cx_emptyl_noop,
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
264
|
cx_emptyl_iterator,
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
265
|
};
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
266
|
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
267
|
CxList cx_empty_list = {
|
|
324
|
268
|
{
|
|
|
269
|
NULL,
|
|
|
270
|
NULL,
|
|
|
271
|
0,
|
|
|
272
|
0,
|
|
|
273
|
NULL,
|
|
|
274
|
NULL,
|
|
|
275
|
NULL,
|
|
|
276
|
false
|
|
|
277
|
},
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
278
|
&cx_empty_list_class,
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
279
|
NULL
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
280
|
};
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
281
|
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
282
|
CxList *const cxEmptyList = &cx_empty_list;
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
283
|
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
284
|
// </editor-fold>
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
285
|
|
|
324
|
286
|
#define invoke_list_func(name, list, ...) \
|
|
|
287
|
((list)->climpl == NULL ? (list)->cl->name : (list)->climpl->name) \
|
|
|
288
|
(list, __VA_ARGS__)
|
|
|
289
|
|
|
|
290
|
size_t cx_list_default_insert_array(
|
|
|
291
|
struct cx_list_s *list,
|
|
|
292
|
size_t index,
|
|
|
293
|
const void *data,
|
|
|
294
|
size_t n
|
|
|
295
|
) {
|
|
|
296
|
size_t elem_size = list->collection.elem_size;
|
|
|
297
|
const char *src = data;
|
|
|
298
|
size_t i = 0;
|
|
|
299
|
for (; i < n; i++) {
|
|
440
|
300
|
if (0 != invoke_list_func(
|
|
|
301
|
insert_element, list, index + i,
|
|
|
302
|
src + (i * elem_size))) return i;
|
|
324
|
303
|
}
|
|
|
304
|
return i;
|
|
|
305
|
}
|
|
|
306
|
|
|
|
307
|
size_t cx_list_default_insert_sorted(
|
|
|
308
|
struct cx_list_s *list,
|
|
|
309
|
const void *sorted_data,
|
|
|
310
|
size_t n
|
|
|
311
|
) {
|
|
|
312
|
// corner case
|
|
|
313
|
if (n == 0) return 0;
|
|
|
314
|
|
|
|
315
|
size_t elem_size = list->collection.elem_size;
|
|
|
316
|
cx_compare_func cmp = list->collection.cmpfunc;
|
|
|
317
|
const char *src = sorted_data;
|
|
|
318
|
|
|
|
319
|
// track indices and number of inserted items
|
|
|
320
|
size_t di = 0, si = 0, inserted = 0;
|
|
|
321
|
|
|
|
322
|
// search the list for insertion points
|
|
|
323
|
for (; di < list->collection.size; di++) {
|
|
|
324
|
const void *list_elm = invoke_list_func(at, list, di);
|
|
|
325
|
|
|
|
326
|
// compare current list element with first source element
|
|
|
327
|
// if less or equal, skip
|
|
|
328
|
if (cmp(list_elm, src) <= 0) {
|
|
|
329
|
continue;
|
|
|
330
|
}
|
|
|
331
|
|
|
|
332
|
// determine number of consecutive elements that can be inserted
|
|
|
333
|
size_t ins = 1;
|
|
|
334
|
const char *next = src;
|
|
|
335
|
while (++si < n) {
|
|
|
336
|
next += elem_size;
|
|
|
337
|
// once we become larger than the list elem, break
|
|
|
338
|
if (cmp(list_elm, next) <= 0) {
|
|
|
339
|
break;
|
|
|
340
|
}
|
|
|
341
|
// otherwise, we can insert one more
|
|
|
342
|
ins++;
|
|
|
343
|
}
|
|
|
344
|
|
|
|
345
|
// insert the elements at location si
|
|
|
346
|
if (ins == 1) {
|
|
440
|
347
|
if (0 != invoke_list_func(
|
|
|
348
|
insert_element, list, di, src)) return inserted;
|
|
324
|
349
|
} else {
|
|
|
350
|
size_t r = invoke_list_func(insert_array, list, di, src, ins);
|
|
|
351
|
if (r < ins) return inserted + r;
|
|
|
352
|
}
|
|
|
353
|
inserted += ins;
|
|
|
354
|
di += ins;
|
|
|
355
|
|
|
|
356
|
// everything inserted?
|
|
|
357
|
if (inserted == n) return inserted;
|
|
|
358
|
src = next;
|
|
|
359
|
}
|
|
|
360
|
|
|
|
361
|
// insert remaining items
|
|
|
362
|
if (si < n) {
|
|
|
363
|
inserted += invoke_list_func(insert_array, list, di, src, n - si);
|
|
|
364
|
}
|
|
|
365
|
|
|
|
366
|
return inserted;
|
|
|
367
|
}
|
|
|
368
|
|
|
|
369
|
void cx_list_default_sort(struct cx_list_s *list) {
|
|
|
370
|
size_t elem_size = list->collection.elem_size;
|
|
|
371
|
size_t list_size = list->collection.size;
|
|
|
372
|
void *tmp = malloc(elem_size * list_size);
|
|
|
373
|
if (tmp == NULL) abort();
|
|
|
374
|
|
|
|
375
|
// copy elements from source array
|
|
|
376
|
char *loc = tmp;
|
|
|
377
|
for (size_t i = 0; i < list_size; i++) {
|
|
|
378
|
void *src = invoke_list_func(at, list, i);
|
|
|
379
|
memcpy(loc, src, elem_size);
|
|
|
380
|
loc += elem_size;
|
|
|
381
|
}
|
|
|
382
|
|
|
|
383
|
// qsort
|
|
|
384
|
qsort(tmp, list_size, elem_size,
|
|
|
385
|
list->collection.cmpfunc);
|
|
|
386
|
|
|
|
387
|
// copy elements back
|
|
|
388
|
loc = tmp;
|
|
|
389
|
for (size_t i = 0; i < list_size; i++) {
|
|
|
390
|
void *dest = invoke_list_func(at, list, i);
|
|
|
391
|
memcpy(dest, loc, elem_size);
|
|
|
392
|
loc += elem_size;
|
|
|
393
|
}
|
|
|
394
|
|
|
|
395
|
free(tmp);
|
|
|
396
|
}
|
|
|
397
|
|
|
|
398
|
int cx_list_default_swap(struct cx_list_s *list, size_t i, size_t j) {
|
|
|
399
|
if (i == j) return 0;
|
|
|
400
|
if (i >= list->collection.size) return 1;
|
|
|
401
|
if (j >= list->collection.size) return 1;
|
|
|
402
|
|
|
|
403
|
size_t elem_size = list->collection.elem_size;
|
|
|
404
|
|
|
|
405
|
void *tmp = malloc(elem_size);
|
|
|
406
|
if (tmp == NULL) return 1;
|
|
|
407
|
|
|
|
408
|
void *ip = invoke_list_func(at, list, i);
|
|
|
409
|
void *jp = invoke_list_func(at, list, j);
|
|
|
410
|
|
|
|
411
|
memcpy(tmp, ip, elem_size);
|
|
|
412
|
memcpy(ip, jp, elem_size);
|
|
|
413
|
memcpy(jp, tmp, elem_size);
|
|
|
414
|
|
|
|
415
|
free(tmp);
|
|
|
416
|
|
|
|
417
|
return 0;
|
|
|
418
|
}
|
|
|
419
|
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
420
|
int cxListCompare(
|
|
324
|
421
|
const CxList *list,
|
|
|
422
|
const CxList *other
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
423
|
) {
|
|
324
|
424
|
bool cannot_optimize = false;
|
|
|
425
|
|
|
|
426
|
// if one is storing pointers but the other is not
|
|
|
427
|
cannot_optimize |= list->collection.store_pointer ^ other->collection.store_pointer;
|
|
|
428
|
|
|
|
429
|
// if one class is wrapped but the other is not
|
|
|
430
|
cannot_optimize |= (list->climpl == NULL) ^ (other->climpl == NULL);
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
431
|
|
|
324
|
432
|
// if the compare functions do not match or both are NULL
|
|
|
433
|
if (!cannot_optimize) {
|
|
|
434
|
cx_compare_func list_cmp = (cx_compare_func) (list->climpl != NULL ?
|
|
|
435
|
list->climpl->compare : list->cl->compare);
|
|
|
436
|
cx_compare_func other_cmp = (cx_compare_func) (other->climpl != NULL ?
|
|
|
437
|
other->climpl->compare : other->cl->compare);
|
|
|
438
|
cannot_optimize |= list_cmp != other_cmp;
|
|
|
439
|
cannot_optimize |= list_cmp == NULL;
|
|
|
440
|
}
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
441
|
|
|
324
|
442
|
if (cannot_optimize) {
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
443
|
// lists are definitely different - cannot use internal compare function
|
|
324
|
444
|
if (list->collection.size == other->collection.size) {
|
|
253
|
445
|
CxIterator left = list->cl->iterator(list, 0, false);
|
|
|
446
|
CxIterator right = other->cl->iterator(other, 0, false);
|
|
324
|
447
|
for (size_t i = 0; i < list->collection.size; i++) {
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
448
|
void *leftValue = cxIteratorCurrent(left);
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
449
|
void *rightValue = cxIteratorCurrent(right);
|
|
324
|
450
|
int d = list->collection.cmpfunc(leftValue, rightValue);
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
451
|
if (d != 0) {
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
452
|
return d;
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
453
|
}
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
454
|
cxIteratorNext(left);
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
455
|
cxIteratorNext(right);
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
456
|
}
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
457
|
return 0;
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
458
|
} else {
|
|
324
|
459
|
return list->collection.size < other->collection.size ? -1 : 1;
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
460
|
}
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
461
|
} else {
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
462
|
// lists are compatible
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
463
|
return list->cl->compare(list, other);
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
464
|
}
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
465
|
}
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
466
|
|
|
324
|
467
|
CxIterator cxListMutIteratorAt(
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
468
|
CxList *list,
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
469
|
size_t index
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
470
|
) {
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
471
|
CxIterator it = list->cl->iterator(list, index, false);
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
472
|
it.base.mutating = true;
|
|
324
|
473
|
return it;
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
474
|
}
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
475
|
|
|
324
|
476
|
CxIterator cxListMutBackwardsIteratorAt(
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
477
|
CxList *list,
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
478
|
size_t index
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
479
|
) {
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
480
|
CxIterator it = list->cl->iterator(list, index, true);
|
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
481
|
it.base.mutating = true;
|
|
324
|
482
|
return it;
|
174
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff
changeset
|
483
|
}
|
|
440
|
484
|
|
|
|
485
|
void cxListFree(CxList *list) {
|
|
|
486
|
if (list == NULL) return;
|
|
|
487
|
list->cl->deallocate(list);
|
|
|
488
|
}
|