source: mainline/uspace/lib/c/generic/adt/dyn_array.c@ 1be7bee

Last change on this file since 1be7bee was c2d50c8, checked in by Matthieu Riolo <matthieu.riolo@…>, 6 years ago

dyn_array: Add concat and clear_range operations

  • Property mode set to 100644
File size: 5.2 KB
Line 
1/*
2 * Copyright (c) 2015 Michal Koutny
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
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libc
30 * @{
31 */
32/** @file
33 *
34 * Implementation of dynamic array that grows or shrinks based upon no. of
35 * items it contains. Non-negligible part of implementation is in @ref
36 * dyn_array.h because of type genericity.
37 */
38
39#include <assert.h>
40#include <errno.h>
41#include <adt/dyn_array.h>
42#include <macros.h>
43#include <mem.h>
44#include <stdlib.h>
45
46
47
48
49static int dyn_array_realloc(dyn_array_t *da, size_t capacity)
50{
51 if (capacity == da->capacity) {
52 return EOK;
53 }
54
55 void *new_data = realloc(da->_data, da->_item_size * capacity);
56 if (new_data) {
57 da->_data = new_data;
58 da->capacity = capacity;
59 }
60 return (new_data == NULL) ? ENOMEM : EOK;
61}
62
63void dyn_array_destroy(dyn_array_t *da)
64{
65 dyn_array_clear(da);
66 free(da->_data);
67 da->capacity = 0;
68}
69
70/** Remove item at given position, shift rest of array */
71void dyn_array_remove(dyn_array_t *da, size_t index)
72{
73 assert(index < da->size);
74 _dyn_array_unshift(da, index, 1);
75 int rc = dyn_array_reserve(da, da->size);
76 assert(rc == EOK);
77}
78
79/** Clear dynamic array (empty) */
80void dyn_array_clear(dyn_array_t *da)
81{
82 da->size = 0;
83}
84
85/** Clear subsequence of array
86 *
87 * @param[in/out] da
88 * @param[in] begin index of first item to remove
89 * @param[in] end index behind last item to remove
90 */
91void dyn_array_clear_range(dyn_array_t *da, size_t begin, size_t end)
92{
93 assert(begin < da->size);
94 assert(end <= da->size);
95
96 _dyn_array_unshift(da, begin, end - begin);
97 int rc = dyn_array_reserve(da, da->size);
98 assert(rc == EOK);
99}
100
101/** Concatenate two arrays
102 *
103 * @param[in/out] da1 first array and concatenated output
104 * @param[in] da2 second array, it is untouched
105 *
106 * @return EOK on success
107 * @return ENOMEM when allocation fails
108 */
109int dyn_array_concat(dyn_array_t *da1, dyn_array_t *da2)
110{
111 assert(da1->_item_size == da2->_item_size);
112
113 int rc = dyn_array_reserve(da1, da1->size + da2->size);
114 if (rc != EOK) {
115 return rc;
116 }
117 void *dst = da1->_data + da1->size * da1->_item_size;
118 void *src = da2->_data;
119 size_t size = da1->_item_size * da2->size;
120 memcpy(dst, src, size);
121 da1->size += da2->size;
122
123 return EOK;
124}
125
126/** Grows/shrinks array so that it effeciently stores desired capacity
127 *
128 * @param da
129 * @param[in] desired capacity of array (items)
130 *
131 * @return EOK
132 * @return ENOMEM
133 */
134int dyn_array_reserve(dyn_array_t *da, size_t capacity)
135{
136 const size_t factor = 2;
137 size_t new_capacity;
138 if (capacity > da->capacity) {
139 new_capacity = max(da->capacity * factor, capacity);
140 } else if (capacity < da->capacity / factor) {
141 new_capacity = min(da->capacity / factor, capacity);
142 } else {
143 new_capacity = capacity;
144 }
145
146 return dyn_array_realloc(da, new_capacity);
147}
148
149void _dyn_array_initialize(dyn_array_t *da, size_t item_size)
150{
151 da->_item_size = item_size;
152 da->_data = NULL;
153
154 da->capacity = 0;
155 da->size = 0;
156}
157
158/** Shift block of array
159 *
160 * Extends size of dynamic array, assumes sufficient capacity.
161 *
162 * @param da
163 * @param[in] index first item shifted
164 * @param[in] offset shift in no. of items
165 */
166void _dyn_array_shift(dyn_array_t *da, size_t index, size_t offset)
167{
168 assert(da->capacity >= da->size + offset);
169
170 void *src = da->_data + index * da->_item_size;
171 void *dst = da->_data + (index + offset) * da->_item_size;
172 size_t size = (da->size - index) * da->_item_size;
173 memmove(dst, src, size);
174 da->size += offset;
175}
176
177/** Unshift block of array
178 *
179 * Reduce size of dynamic array
180 *
181 * @param da
182 * @param[in] index first item unshifted (removed)
183 * @param[in] offset shift in no. of items
184 */
185void _dyn_array_unshift(dyn_array_t *da, size_t index, size_t offset)
186{
187 void *src = da->_data + (index + offset) * da->_item_size;
188 void *dst = da->_data + index * da->_item_size;
189 size_t size = (da->size - index - offset) * da->_item_size;
190 memmove(dst, src, size);
191 da->size -= offset;
192}
193
194
195/** @}
196 */
Note: See TracBrowser for help on using the repository browser.