1 | /* |
2 | Copyright (c) 2012, Broadcom Europe Ltd |
3 | All rights reserved. |
4 | |
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the following conditions are met: |
7 | * Redistributions of source code must retain the above copyright |
8 | notice, this list of conditions and the following disclaimer. |
9 | * Redistributions in binary form must reproduce the above copyright |
10 | notice, this list of conditions and the following disclaimer in the |
11 | documentation and/or other materials provided with the distribution. |
12 | * Neither the name of the copyright holder nor the |
13 | names of its contributors may be used to endorse or promote products |
14 | derived from this software without specific prior written permission. |
15 | |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY |
20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ |
27 | #include <stdlib.h> |
28 | #include <stdio.h> |
29 | #include <string.h> |
30 | |
31 | #include "containers/core/containers_common.h" |
32 | #include "containers/core/containers_list.h" |
33 | |
34 | /****************************************************************************** |
35 | Defines and constants. |
36 | ******************************************************************************/ |
37 | |
38 | /****************************************************************************** |
39 | Type definitions |
40 | ******************************************************************************/ |
41 | |
42 | /****************************************************************************** |
43 | Function prototypes |
44 | ******************************************************************************/ |
45 | |
46 | /****************************************************************************** |
47 | Local Functions |
48 | ******************************************************************************/ |
49 | |
50 | /** Find an entry in the list, or the insertion point. |
51 | * Uses binary sub-division to find the search item. If index is not NULL, the |
52 | * index of the matching entry, or the point at which to insert if not found, is |
53 | * written to that address. |
54 | * |
55 | * \param list The list to be searched. |
56 | * \param entry The entry for which to search. |
57 | * \param index Set to index of match, or insertion point if not found. May be NULL. |
58 | * \return True if a match was found, false if not. */ |
59 | static bool vc_containers_list_find_index(const VC_CONTAINERS_LIST_T *list, |
60 | const void *entry, |
61 | uint32_t *index) |
62 | { |
63 | const char *entries = (const char *)list->entries; |
64 | size_t entry_size = list->entry_size; |
65 | VC_CONTAINERS_LIST_COMPARATOR_T comparator = list->comparator; |
66 | uint32_t start = 0, end = list->size; |
67 | uint32_t mid = end >> 1; |
68 | bool match = false; |
69 | |
70 | while (mid < end) |
71 | { |
72 | int comparison = comparator(entry, entries + mid * entry_size); |
73 | |
74 | if (comparison < 0) |
75 | end = mid; |
76 | else if (comparison > 0) |
77 | start = mid + 1; |
78 | else { |
79 | match = true; |
80 | break; |
81 | } |
82 | |
83 | mid = (start + end) >> 1; |
84 | } |
85 | |
86 | if (index) *index = mid; |
87 | return match; |
88 | } |
89 | |
90 | /****************************************************************************** |
91 | Functions exported as part of the API |
92 | ******************************************************************************/ |
93 | |
94 | /*****************************************************************************/ |
95 | VC_CONTAINERS_LIST_T *vc_containers_list_create(uint32_t capacity, |
96 | size_t entry_size, |
97 | VC_CONTAINERS_LIST_COMPARATOR_T comparator) |
98 | { |
99 | VC_CONTAINERS_LIST_T *list; |
100 | |
101 | list = (VC_CONTAINERS_LIST_T *)malloc(sizeof(VC_CONTAINERS_LIST_T)); |
102 | if (!list) |
103 | return NULL; |
104 | |
105 | /* Ensure non-zero capacity, as that signifies a read-only list */ |
106 | if (!capacity) capacity = 1; |
107 | |
108 | list->entries = malloc(capacity * entry_size); |
109 | if (!list->entries) |
110 | { |
111 | free(list); |
112 | return NULL; |
113 | } |
114 | |
115 | list->size = 0; |
116 | list->capacity = capacity; |
117 | list->entry_size = entry_size; |
118 | list->comparator = comparator; |
119 | |
120 | return list; |
121 | } |
122 | |
123 | /*****************************************************************************/ |
124 | void vc_containers_list_destroy(VC_CONTAINERS_LIST_T *list) |
125 | { |
126 | /* Avoid trying to destroy read-only lists */ |
127 | if (list && list->capacity) |
128 | { |
129 | if (list->entries) |
130 | free(list->entries); |
131 | free(list); |
132 | } |
133 | } |
134 | |
135 | /*****************************************************************************/ |
136 | void vc_containers_list_reset(VC_CONTAINERS_LIST_T *list) |
137 | { |
138 | /* Avoid trying to reset read-only lists */ |
139 | if (list && list->capacity) |
140 | list->size = 0; |
141 | } |
142 | |
143 | /*****************************************************************************/ |
144 | bool vc_containers_list_insert(VC_CONTAINERS_LIST_T *list, |
145 | void *new_entry, |
146 | bool allow_duplicates) |
147 | { |
148 | uint32_t insert_idx; |
149 | char *insert_ptr; |
150 | size_t entry_size; |
151 | bool match; |
152 | |
153 | if (!list || !list->capacity) return false; |
154 | |
155 | entry_size = list->entry_size; |
156 | match = vc_containers_list_find_index(list, new_entry, &insert_idx); |
157 | insert_ptr = (char *)list->entries + entry_size * insert_idx; |
158 | |
159 | if (!match || allow_duplicates) |
160 | { |
161 | /* Ensure there is space for the new entry */ |
162 | if (list->size == list->capacity) |
163 | { |
164 | void *new_entries = realloc(list->entries, (list->size + 1) * entry_size); |
165 | |
166 | if (!new_entries) |
167 | return false; |
168 | list->entries = new_entries; |
169 | list->capacity++; |
170 | } |
171 | |
172 | /* Move up anything above the insertion point */ |
173 | if (insert_idx < list->size) |
174 | memmove(insert_ptr + entry_size, insert_ptr, (list->size - insert_idx) * entry_size); |
175 | |
176 | list->size++; |
177 | } |
178 | |
179 | /* Copy in the new entry (overwriting the old one if necessary) */ |
180 | memcpy(insert_ptr, new_entry, list->entry_size); |
181 | |
182 | return true; |
183 | } |
184 | |
185 | /*****************************************************************************/ |
186 | bool vc_containers_list_find_entry(const VC_CONTAINERS_LIST_T *list, |
187 | void *entry) |
188 | { |
189 | uint32_t index; |
190 | size_t entry_size; |
191 | |
192 | if (!vc_containers_list_find_index(list, entry, &index)) |
193 | return false; |
194 | |
195 | entry_size = list->entry_size; |
196 | memcpy(entry, (const char *)list->entries + entry_size * index, entry_size); |
197 | |
198 | return true; |
199 | } |
200 | |
201 | /*****************************************************************************/ |
202 | void vc_containers_list_validate(const VC_CONTAINERS_LIST_T *list) |
203 | { |
204 | uint32_t ii, entry_size; |
205 | const uint8_t *entry_ptr; |
206 | |
207 | vc_container_assert(list); |
208 | vc_container_assert(!list->capacity || list->size <= list->capacity); |
209 | vc_container_assert(list->entry_size); |
210 | vc_container_assert(list->comparator); |
211 | vc_container_assert(list->entries); |
212 | |
213 | /* Check all entries are in sorted order */ |
214 | entry_ptr = (const uint8_t *)list->entries; |
215 | entry_size = list->entry_size; |
216 | for (ii = 1; ii < list->size; ii++) |
217 | { |
218 | vc_container_assert(list->comparator(entry_ptr, entry_ptr + entry_size) <= 0); |
219 | entry_ptr += entry_size; |
220 | } |
221 | } |
222 | |