1*cfb92d14SAndroid Build Coastguard Worker /*
2*cfb92d14SAndroid Build Coastguard Worker * Copyright (c) 2018, Sam Kumar <[email protected]>
3*cfb92d14SAndroid Build Coastguard Worker * Copyright (c) 2018, University of California, Berkeley
4*cfb92d14SAndroid Build Coastguard Worker * All rights reserved.
5*cfb92d14SAndroid Build Coastguard Worker *
6*cfb92d14SAndroid Build Coastguard Worker * Redistribution and use in source and binary forms, with or without
7*cfb92d14SAndroid Build Coastguard Worker * modification, are permitted provided that the following conditions are met:
8*cfb92d14SAndroid Build Coastguard Worker * 1. Redistributions of source code must retain the above copyright
9*cfb92d14SAndroid Build Coastguard Worker * notice, this list of conditions and the following disclaimer.
10*cfb92d14SAndroid Build Coastguard Worker * 2. Redistributions in binary form must reproduce the above copyright
11*cfb92d14SAndroid Build Coastguard Worker * notice, this list of conditions and the following disclaimer in the
12*cfb92d14SAndroid Build Coastguard Worker * documentation and/or other materials provided with the distribution.
13*cfb92d14SAndroid Build Coastguard Worker * 3. Neither the name of the copyright holder nor the
14*cfb92d14SAndroid Build Coastguard Worker * names of its contributors may be used to endorse or promote products
15*cfb92d14SAndroid Build Coastguard Worker * derived from this software without specific prior written permission.
16*cfb92d14SAndroid Build Coastguard Worker *
17*cfb92d14SAndroid Build Coastguard Worker * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18*cfb92d14SAndroid Build Coastguard Worker * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19*cfb92d14SAndroid Build Coastguard Worker * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20*cfb92d14SAndroid Build Coastguard Worker * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21*cfb92d14SAndroid Build Coastguard Worker * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22*cfb92d14SAndroid Build Coastguard Worker * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23*cfb92d14SAndroid Build Coastguard Worker * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24*cfb92d14SAndroid Build Coastguard Worker * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25*cfb92d14SAndroid Build Coastguard Worker * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26*cfb92d14SAndroid Build Coastguard Worker * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27*cfb92d14SAndroid Build Coastguard Worker * POSSIBILITY OF SUCH DAMAGE.
28*cfb92d14SAndroid Build Coastguard Worker */
29*cfb92d14SAndroid Build Coastguard Worker
30*cfb92d14SAndroid Build Coastguard Worker /* CIRCULAR BUFFER */
31*cfb92d14SAndroid Build Coastguard Worker #include "cbuf.h"
32*cfb92d14SAndroid Build Coastguard Worker #include "bitmap.h"
33*cfb92d14SAndroid Build Coastguard Worker
34*cfb92d14SAndroid Build Coastguard Worker #include <stdint.h>
35*cfb92d14SAndroid Build Coastguard Worker #include <stdlib.h>
36*cfb92d14SAndroid Build Coastguard Worker #include <string.h>
37*cfb92d14SAndroid Build Coastguard Worker #include <sys/types.h>
38*cfb92d14SAndroid Build Coastguard Worker
39*cfb92d14SAndroid Build Coastguard Worker #include <openthread/message.h>
40*cfb92d14SAndroid Build Coastguard Worker #include <openthread/tcp.h>
41*cfb92d14SAndroid Build Coastguard Worker
42*cfb92d14SAndroid Build Coastguard Worker /*
43*cfb92d14SAndroid Build Coastguard Worker * Copiers for copying from/into cbufs into/from arrays or OpenThraed messages
44*cfb92d14SAndroid Build Coastguard Worker */
45*cfb92d14SAndroid Build Coastguard Worker
cbuf_copy_into_buffer(void * buffer,size_t buffer_offset,const void * arr,size_t arr_offset,size_t num_bytes)46*cfb92d14SAndroid Build Coastguard Worker void cbuf_copy_into_buffer(void* buffer, size_t buffer_offset, const void* arr, size_t arr_offset, size_t num_bytes) {
47*cfb92d14SAndroid Build Coastguard Worker uint8_t* bufptr = (uint8_t*) buffer;
48*cfb92d14SAndroid Build Coastguard Worker const uint8_t* arrptr = (const uint8_t*) arr;
49*cfb92d14SAndroid Build Coastguard Worker memcpy(bufptr + buffer_offset, arrptr + arr_offset, num_bytes);
50*cfb92d14SAndroid Build Coastguard Worker }
51*cfb92d14SAndroid Build Coastguard Worker
cbuf_copy_from_buffer(void * arr,size_t arr_offset,const void * buffer,size_t buffer_offset,size_t num_bytes)52*cfb92d14SAndroid Build Coastguard Worker void cbuf_copy_from_buffer(void* arr, size_t arr_offset, const void* buffer, size_t buffer_offset, size_t num_bytes) {
53*cfb92d14SAndroid Build Coastguard Worker uint8_t* arrptr = (uint8_t*) arr;
54*cfb92d14SAndroid Build Coastguard Worker const uint8_t* bufptr = (const uint8_t*) buffer;
55*cfb92d14SAndroid Build Coastguard Worker memcpy(arrptr + arr_offset, bufptr + buffer_offset, num_bytes);
56*cfb92d14SAndroid Build Coastguard Worker }
57*cfb92d14SAndroid Build Coastguard Worker
cbuf_copy_into_message(void * buffer,size_t buffer_offset,const void * arr,size_t arr_offset,size_t num_bytes)58*cfb92d14SAndroid Build Coastguard Worker void cbuf_copy_into_message(void* buffer, size_t buffer_offset, const void* arr, size_t arr_offset, size_t num_bytes) {
59*cfb92d14SAndroid Build Coastguard Worker otMessage* message = (otMessage*) buffer;
60*cfb92d14SAndroid Build Coastguard Worker uint8_t* arrptr = (uint8_t*) arr;
61*cfb92d14SAndroid Build Coastguard Worker otMessageWrite(message, (uint16_t) buffer_offset, arrptr + arr_offset, (uint16_t) num_bytes);
62*cfb92d14SAndroid Build Coastguard Worker }
63*cfb92d14SAndroid Build Coastguard Worker
cbuf_copy_from_message(void * arr,size_t arr_offset,const void * buffer,size_t buffer_offset,size_t num_bytes)64*cfb92d14SAndroid Build Coastguard Worker void cbuf_copy_from_message(void* arr, size_t arr_offset, const void* buffer, size_t buffer_offset, size_t num_bytes) {
65*cfb92d14SAndroid Build Coastguard Worker uint8_t* arrptr = (uint8_t*) arr;
66*cfb92d14SAndroid Build Coastguard Worker const otMessage* message = (const otMessage*) buffer;
67*cfb92d14SAndroid Build Coastguard Worker otMessageRead(message, (uint16_t) buffer_offset, arrptr + arr_offset, (uint16_t) num_bytes);
68*cfb92d14SAndroid Build Coastguard Worker }
69*cfb92d14SAndroid Build Coastguard Worker
70*cfb92d14SAndroid Build Coastguard Worker /*
71*cfb92d14SAndroid Build Coastguard Worker * Cbuf implementation.
72*cfb92d14SAndroid Build Coastguard Worker */
73*cfb92d14SAndroid Build Coastguard Worker
cbuf_init(struct cbufhead * chdr,uint8_t * buf,size_t len)74*cfb92d14SAndroid Build Coastguard Worker void cbuf_init(struct cbufhead* chdr, uint8_t* buf, size_t len) {
75*cfb92d14SAndroid Build Coastguard Worker chdr->r_index = 0;
76*cfb92d14SAndroid Build Coastguard Worker chdr->used = 0;
77*cfb92d14SAndroid Build Coastguard Worker chdr->size = len;
78*cfb92d14SAndroid Build Coastguard Worker chdr->buf = buf;
79*cfb92d14SAndroid Build Coastguard Worker }
80*cfb92d14SAndroid Build Coastguard Worker
cbuf_used_space(struct cbufhead * chdr)81*cfb92d14SAndroid Build Coastguard Worker size_t cbuf_used_space(struct cbufhead* chdr) {
82*cfb92d14SAndroid Build Coastguard Worker return chdr->used;
83*cfb92d14SAndroid Build Coastguard Worker }
84*cfb92d14SAndroid Build Coastguard Worker
cbuf_free_space(struct cbufhead * chdr)85*cfb92d14SAndroid Build Coastguard Worker size_t cbuf_free_space(struct cbufhead* chdr) {
86*cfb92d14SAndroid Build Coastguard Worker return chdr->size - chdr->used;
87*cfb92d14SAndroid Build Coastguard Worker }
88*cfb92d14SAndroid Build Coastguard Worker
cbuf_size(struct cbufhead * chdr)89*cfb92d14SAndroid Build Coastguard Worker size_t cbuf_size(struct cbufhead* chdr) {
90*cfb92d14SAndroid Build Coastguard Worker return chdr->size;
91*cfb92d14SAndroid Build Coastguard Worker }
92*cfb92d14SAndroid Build Coastguard Worker
cbuf_empty(struct cbufhead * chdr)93*cfb92d14SAndroid Build Coastguard Worker bool cbuf_empty(struct cbufhead* chdr) {
94*cfb92d14SAndroid Build Coastguard Worker return chdr->used == 0;
95*cfb92d14SAndroid Build Coastguard Worker }
96*cfb92d14SAndroid Build Coastguard Worker
cbuf_get_w_index(const struct cbufhead * chdr)97*cfb92d14SAndroid Build Coastguard Worker static inline size_t cbuf_get_w_index(const struct cbufhead* chdr) {
98*cfb92d14SAndroid Build Coastguard Worker size_t until_end = chdr->size - chdr->r_index;
99*cfb92d14SAndroid Build Coastguard Worker if (chdr->used < until_end) {
100*cfb92d14SAndroid Build Coastguard Worker return chdr->r_index + chdr->used;
101*cfb92d14SAndroid Build Coastguard Worker } else {
102*cfb92d14SAndroid Build Coastguard Worker return chdr->used - until_end;
103*cfb92d14SAndroid Build Coastguard Worker }
104*cfb92d14SAndroid Build Coastguard Worker }
105*cfb92d14SAndroid Build Coastguard Worker
cbuf_write(struct cbufhead * chdr,const void * data,size_t data_offset,size_t data_len,cbuf_copier_t copy_from)106*cfb92d14SAndroid Build Coastguard Worker size_t cbuf_write(struct cbufhead* chdr, const void* data, size_t data_offset, size_t data_len, cbuf_copier_t copy_from) {
107*cfb92d14SAndroid Build Coastguard Worker size_t free_space = cbuf_free_space(chdr);
108*cfb92d14SAndroid Build Coastguard Worker uint8_t* buf_data;
109*cfb92d14SAndroid Build Coastguard Worker size_t w_index;
110*cfb92d14SAndroid Build Coastguard Worker size_t bytes_to_end;
111*cfb92d14SAndroid Build Coastguard Worker if (free_space < data_len) {
112*cfb92d14SAndroid Build Coastguard Worker data_len = free_space;
113*cfb92d14SAndroid Build Coastguard Worker }
114*cfb92d14SAndroid Build Coastguard Worker buf_data = chdr->buf;
115*cfb92d14SAndroid Build Coastguard Worker w_index = cbuf_get_w_index(chdr);
116*cfb92d14SAndroid Build Coastguard Worker bytes_to_end = chdr->size - w_index;
117*cfb92d14SAndroid Build Coastguard Worker if (data_len <= bytes_to_end) {
118*cfb92d14SAndroid Build Coastguard Worker copy_from(buf_data, w_index, data, data_offset, data_len);
119*cfb92d14SAndroid Build Coastguard Worker } else {
120*cfb92d14SAndroid Build Coastguard Worker copy_from(buf_data, w_index, data, data_offset, bytes_to_end);
121*cfb92d14SAndroid Build Coastguard Worker copy_from(buf_data, 0, data, data_offset + bytes_to_end, data_len - bytes_to_end);
122*cfb92d14SAndroid Build Coastguard Worker }
123*cfb92d14SAndroid Build Coastguard Worker chdr->used += data_len;
124*cfb92d14SAndroid Build Coastguard Worker return data_len;
125*cfb92d14SAndroid Build Coastguard Worker }
126*cfb92d14SAndroid Build Coastguard Worker
cbuf_read_unsafe(struct cbufhead * chdr,void * data,size_t data_offset,size_t numbytes,int pop,cbuf_copier_t copy_into)127*cfb92d14SAndroid Build Coastguard Worker void cbuf_read_unsafe(struct cbufhead* chdr, void* data, size_t data_offset, size_t numbytes, int pop, cbuf_copier_t copy_into) {
128*cfb92d14SAndroid Build Coastguard Worker uint8_t* buf_data = chdr->buf;
129*cfb92d14SAndroid Build Coastguard Worker size_t bytes_to_end = chdr->size - chdr->r_index;
130*cfb92d14SAndroid Build Coastguard Worker if (numbytes < bytes_to_end) {
131*cfb92d14SAndroid Build Coastguard Worker copy_into(data, data_offset, buf_data, chdr->r_index, numbytes);
132*cfb92d14SAndroid Build Coastguard Worker if (pop) {
133*cfb92d14SAndroid Build Coastguard Worker chdr->r_index += numbytes;
134*cfb92d14SAndroid Build Coastguard Worker chdr->used -= numbytes;
135*cfb92d14SAndroid Build Coastguard Worker }
136*cfb92d14SAndroid Build Coastguard Worker } else {
137*cfb92d14SAndroid Build Coastguard Worker copy_into(data, data_offset, buf_data, chdr->r_index, bytes_to_end);
138*cfb92d14SAndroid Build Coastguard Worker copy_into(data, data_offset + bytes_to_end, buf_data, 0, numbytes - bytes_to_end);
139*cfb92d14SAndroid Build Coastguard Worker if (pop) {
140*cfb92d14SAndroid Build Coastguard Worker chdr->r_index = numbytes - bytes_to_end;
141*cfb92d14SAndroid Build Coastguard Worker chdr->used -= numbytes;
142*cfb92d14SAndroid Build Coastguard Worker }
143*cfb92d14SAndroid Build Coastguard Worker }
144*cfb92d14SAndroid Build Coastguard Worker }
145*cfb92d14SAndroid Build Coastguard Worker
cbuf_read(struct cbufhead * chdr,void * data,size_t data_offset,size_t numbytes,int pop,cbuf_copier_t copy_into)146*cfb92d14SAndroid Build Coastguard Worker size_t cbuf_read(struct cbufhead* chdr, void* data, size_t data_offset, size_t numbytes, int pop, cbuf_copier_t copy_into) {
147*cfb92d14SAndroid Build Coastguard Worker size_t used_space = cbuf_used_space(chdr);
148*cfb92d14SAndroid Build Coastguard Worker if (used_space < numbytes) {
149*cfb92d14SAndroid Build Coastguard Worker numbytes = used_space;
150*cfb92d14SAndroid Build Coastguard Worker }
151*cfb92d14SAndroid Build Coastguard Worker cbuf_read_unsafe(chdr, data, data_offset, numbytes, pop, copy_into);
152*cfb92d14SAndroid Build Coastguard Worker return numbytes;
153*cfb92d14SAndroid Build Coastguard Worker }
154*cfb92d14SAndroid Build Coastguard Worker
cbuf_read_offset(struct cbufhead * chdr,void * data,size_t data_offset,size_t numbytes,size_t offset,cbuf_copier_t copy_into)155*cfb92d14SAndroid Build Coastguard Worker size_t cbuf_read_offset(struct cbufhead* chdr, void* data, size_t data_offset, size_t numbytes, size_t offset, cbuf_copier_t copy_into) {
156*cfb92d14SAndroid Build Coastguard Worker size_t used_space = cbuf_used_space(chdr);
157*cfb92d14SAndroid Build Coastguard Worker size_t oldpos;
158*cfb92d14SAndroid Build Coastguard Worker if (used_space <= offset) {
159*cfb92d14SAndroid Build Coastguard Worker return 0;
160*cfb92d14SAndroid Build Coastguard Worker } else if (used_space < offset + numbytes) {
161*cfb92d14SAndroid Build Coastguard Worker numbytes = used_space - offset;
162*cfb92d14SAndroid Build Coastguard Worker }
163*cfb92d14SAndroid Build Coastguard Worker oldpos = chdr->r_index;
164*cfb92d14SAndroid Build Coastguard Worker chdr->r_index = (chdr->r_index + offset) % chdr->size;
165*cfb92d14SAndroid Build Coastguard Worker cbuf_read_unsafe(chdr, data, data_offset, numbytes, 0, copy_into);
166*cfb92d14SAndroid Build Coastguard Worker chdr->r_index = oldpos;
167*cfb92d14SAndroid Build Coastguard Worker return numbytes;
168*cfb92d14SAndroid Build Coastguard Worker }
169*cfb92d14SAndroid Build Coastguard Worker
cbuf_pop(struct cbufhead * chdr,size_t numbytes)170*cfb92d14SAndroid Build Coastguard Worker size_t cbuf_pop(struct cbufhead* chdr, size_t numbytes) {
171*cfb92d14SAndroid Build Coastguard Worker size_t used_space = cbuf_used_space(chdr);
172*cfb92d14SAndroid Build Coastguard Worker if (used_space < numbytes) {
173*cfb92d14SAndroid Build Coastguard Worker numbytes = used_space;
174*cfb92d14SAndroid Build Coastguard Worker }
175*cfb92d14SAndroid Build Coastguard Worker chdr->r_index = (chdr->r_index + numbytes) % chdr->size;
176*cfb92d14SAndroid Build Coastguard Worker chdr->used -= numbytes;
177*cfb92d14SAndroid Build Coastguard Worker return numbytes;
178*cfb92d14SAndroid Build Coastguard Worker }
179*cfb92d14SAndroid Build Coastguard Worker
cbuf_swap(struct cbufhead * chdr,uint8_t * bitmap,size_t start_1,size_t start_2,size_t length)180*cfb92d14SAndroid Build Coastguard Worker static void cbuf_swap(struct cbufhead* chdr, uint8_t* bitmap, size_t start_1, size_t start_2, size_t length) {
181*cfb92d14SAndroid Build Coastguard Worker size_t i;
182*cfb92d14SAndroid Build Coastguard Worker
183*cfb92d14SAndroid Build Coastguard Worker /* Swap the data regions. */
184*cfb92d14SAndroid Build Coastguard Worker for (i = 0; i != length; i++) {
185*cfb92d14SAndroid Build Coastguard Worker uint8_t temp = chdr->buf[start_1 + i];
186*cfb92d14SAndroid Build Coastguard Worker chdr->buf[start_1 + i] = chdr->buf[start_2 + i];
187*cfb92d14SAndroid Build Coastguard Worker chdr->buf[start_2 + i] = temp;
188*cfb92d14SAndroid Build Coastguard Worker }
189*cfb92d14SAndroid Build Coastguard Worker
190*cfb92d14SAndroid Build Coastguard Worker /* Swap the bitmaps. */
191*cfb92d14SAndroid Build Coastguard Worker if (bitmap) {
192*cfb92d14SAndroid Build Coastguard Worker bmp_swap(bitmap, start_1, start_2, length);
193*cfb92d14SAndroid Build Coastguard Worker }
194*cfb92d14SAndroid Build Coastguard Worker }
195*cfb92d14SAndroid Build Coastguard Worker
cbuf_contiguify(struct cbufhead * chdr,uint8_t * bitmap)196*cfb92d14SAndroid Build Coastguard Worker void cbuf_contiguify(struct cbufhead* chdr, uint8_t* bitmap) {
197*cfb92d14SAndroid Build Coastguard Worker /*
198*cfb92d14SAndroid Build Coastguard Worker * We treat contiguify as a special case of rotation. In principle, we
199*cfb92d14SAndroid Build Coastguard Worker * could make this more efficient by inspecting R_INDEX, W_INDEX, and the
200*cfb92d14SAndroid Build Coastguard Worker * bitmap to only move around in-sequence data and buffered out-of-sequence
201*cfb92d14SAndroid Build Coastguard Worker * data, while ignoring the other bytes in the circular buffer. We leave
202*cfb92d14SAndroid Build Coastguard Worker * this as an optimization to implement if/when it becomes necessary.
203*cfb92d14SAndroid Build Coastguard Worker *
204*cfb92d14SAndroid Build Coastguard Worker * The rotation algorithm is recursive. It is parameterized by three
205*cfb92d14SAndroid Build Coastguard Worker * arguments. START_IDX is the index of the first element of the subarray
206*cfb92d14SAndroid Build Coastguard Worker * that is being rotated. END_IDX is one plus the index of the last element
207*cfb92d14SAndroid Build Coastguard Worker * of the subarray that is being rotated. MOVE_TO_START_IDX is the index of
208*cfb92d14SAndroid Build Coastguard Worker * the element that should be located at START_IDX after the rotation.
209*cfb92d14SAndroid Build Coastguard Worker *
210*cfb92d14SAndroid Build Coastguard Worker * The algorithm is as follows. First, identify the largest block of data
211*cfb92d14SAndroid Build Coastguard Worker * starting at MOVE_TO_START_IDX that can be swapped with data starting at
212*cfb92d14SAndroid Build Coastguard Worker * START_IDX. If MOVE_TO_START_IDX is right at the midpoint of the array,
213*cfb92d14SAndroid Build Coastguard Worker * then we're done. If it isn't, then we can treat the block of data that
214*cfb92d14SAndroid Build Coastguard Worker * was just swapped to the beginning of the array as "done", and then
215*cfb92d14SAndroid Build Coastguard Worker * complete the rotation by recursively rotating the rest of the array.
216*cfb92d14SAndroid Build Coastguard Worker *
217*cfb92d14SAndroid Build Coastguard Worker * Here's an example. Suppose that the array is "1 2 3 4 5 6 7 8 9" and
218*cfb92d14SAndroid Build Coastguard Worker * MOVE_TO_START_IDX is the index of the element "3". First, we swap "1 2"
219*cfb92d14SAndroid Build Coastguard Worker * AND "3 4" to get "3 4 1 2 5 6 7 8 9". Then, we recursively rotate the
220*cfb92d14SAndroid Build Coastguard Worker * subarray "1 2 5 6 7 8 9", with MOVE_TO_START_IDX being the index of the
221*cfb92d14SAndroid Build Coastguard Worker * element "5". The final array is "3 4 5 6 7 8 9 1 2".
222*cfb92d14SAndroid Build Coastguard Worker *
223*cfb92d14SAndroid Build Coastguard Worker * Here's another example. Suppose that the array is "1 2 3 4 5 6 7 8 9"
224*cfb92d14SAndroid Build Coastguard Worker * and MOVE_TO_START_IDX is the index of the element "6". First, we swap
225*cfb92d14SAndroid Build Coastguard Worker * "1 2 3 4" and "6 7 8 9" to get "6 7 8 9 5 1 2 3 4". Then, we recursively
226*cfb92d14SAndroid Build Coastguard Worker * rotate the subarray "5 1 2 3 4", with MOVE_TO_START_IDX being the index
227*cfb92d14SAndroid Build Coastguard Worker * of the element "1". The final array is "6 7 8 9 1 2 3 4 5".
228*cfb92d14SAndroid Build Coastguard Worker *
229*cfb92d14SAndroid Build Coastguard Worker * In order for this to work, it's important that the blocks that we
230*cfb92d14SAndroid Build Coastguard Worker * choose are maximally large. If, in the first example, we swap only the
231*cfb92d14SAndroid Build Coastguard Worker * elements "1" and "3", then the algorithm won't work. Note that "1 2" and
232*cfb92d14SAndroid Build Coastguard Worker * "3 4" corresponds to maximally large blocks because if we make the
233*cfb92d14SAndroid Build Coastguard Worker * blocks any bigger, they would overlap (e.g., "1 2 3" and "3 4 5"). In
234*cfb92d14SAndroid Build Coastguard Worker * the second example, the block "6 7 8 9" is maximally large because we
235*cfb92d14SAndroid Build Coastguard Worker * reach the end of the subarray.
236*cfb92d14SAndroid Build Coastguard Worker *
237*cfb92d14SAndroid Build Coastguard Worker * The algorithm above is tail-recursive (i.e., there's no more work to do
238*cfb92d14SAndroid Build Coastguard Worker * after recursively rotating the subarray), so we write it as a while
239*cfb92d14SAndroid Build Coastguard Worker * loop below. Each iteration of the while loop identifies the blocks to
240*cfb92d14SAndroid Build Coastguard Worker * swap, swaps the blocks, and then sets up the indices such that the
241*cfb92d14SAndroid Build Coastguard Worker * next iteration of the loop rotates the appropriate subarray.
242*cfb92d14SAndroid Build Coastguard Worker *
243*cfb92d14SAndroid Build Coastguard Worker * The performance of the algorithm is linear in the length of the array,
244*cfb92d14SAndroid Build Coastguard Worker * with constant space overhead.
245*cfb92d14SAndroid Build Coastguard Worker */
246*cfb92d14SAndroid Build Coastguard Worker size_t start_idx = 0;
247*cfb92d14SAndroid Build Coastguard Worker const size_t end_idx = chdr->size;
248*cfb92d14SAndroid Build Coastguard Worker size_t move_to_start_idx = chdr->r_index;
249*cfb92d14SAndroid Build Coastguard Worker
250*cfb92d14SAndroid Build Coastguard Worker /* Invariant: start_idx <= move_to_start_idx <= end_idx */
251*cfb92d14SAndroid Build Coastguard Worker while (start_idx < move_to_start_idx && move_to_start_idx < end_idx) {
252*cfb92d14SAndroid Build Coastguard Worker size_t distance_from_start = move_to_start_idx - start_idx;
253*cfb92d14SAndroid Build Coastguard Worker size_t distance_to_end = end_idx - move_to_start_idx;
254*cfb92d14SAndroid Build Coastguard Worker if (distance_from_start <= distance_to_end) {
255*cfb92d14SAndroid Build Coastguard Worker cbuf_swap(chdr, bitmap, start_idx, move_to_start_idx, distance_from_start);
256*cfb92d14SAndroid Build Coastguard Worker start_idx = move_to_start_idx;
257*cfb92d14SAndroid Build Coastguard Worker move_to_start_idx = move_to_start_idx + distance_from_start;
258*cfb92d14SAndroid Build Coastguard Worker } else {
259*cfb92d14SAndroid Build Coastguard Worker cbuf_swap(chdr, bitmap, start_idx, move_to_start_idx, distance_to_end);
260*cfb92d14SAndroid Build Coastguard Worker start_idx = start_idx + distance_to_end;
261*cfb92d14SAndroid Build Coastguard Worker // move_to_start_idx does not change
262*cfb92d14SAndroid Build Coastguard Worker }
263*cfb92d14SAndroid Build Coastguard Worker }
264*cfb92d14SAndroid Build Coastguard Worker
265*cfb92d14SAndroid Build Coastguard Worker /* Finally, fix up the indices. */
266*cfb92d14SAndroid Build Coastguard Worker chdr->r_index = 0;
267*cfb92d14SAndroid Build Coastguard Worker }
268*cfb92d14SAndroid Build Coastguard Worker
cbuf_reference(const struct cbufhead * chdr,otLinkedBuffer * first,otLinkedBuffer * second)269*cfb92d14SAndroid Build Coastguard Worker void cbuf_reference(const struct cbufhead* chdr, otLinkedBuffer* first, otLinkedBuffer* second) {
270*cfb92d14SAndroid Build Coastguard Worker size_t until_end = chdr->size - chdr->r_index;
271*cfb92d14SAndroid Build Coastguard Worker if (chdr->used <= until_end) {
272*cfb92d14SAndroid Build Coastguard Worker first->mNext = NULL;
273*cfb92d14SAndroid Build Coastguard Worker first->mData = &chdr->buf[chdr->r_index];
274*cfb92d14SAndroid Build Coastguard Worker first->mLength = (uint16_t) chdr->used;
275*cfb92d14SAndroid Build Coastguard Worker } else {
276*cfb92d14SAndroid Build Coastguard Worker first->mNext = second;
277*cfb92d14SAndroid Build Coastguard Worker first->mData = &chdr->buf[chdr->r_index];
278*cfb92d14SAndroid Build Coastguard Worker first->mLength = (uint16_t) until_end;
279*cfb92d14SAndroid Build Coastguard Worker
280*cfb92d14SAndroid Build Coastguard Worker second->mNext = NULL;
281*cfb92d14SAndroid Build Coastguard Worker second->mData = &chdr->buf[0];
282*cfb92d14SAndroid Build Coastguard Worker second->mLength = (uint16_t) (chdr->used - until_end);
283*cfb92d14SAndroid Build Coastguard Worker }
284*cfb92d14SAndroid Build Coastguard Worker }
285*cfb92d14SAndroid Build Coastguard Worker
cbuf_reass_write(struct cbufhead * chdr,size_t offset,const void * data,size_t data_offset,size_t numbytes,uint8_t * bitmap,size_t * firstindex,cbuf_copier_t copy_from)286*cfb92d14SAndroid Build Coastguard Worker size_t cbuf_reass_write(struct cbufhead* chdr, size_t offset, const void* data, size_t data_offset, size_t numbytes, uint8_t* bitmap, size_t* firstindex, cbuf_copier_t copy_from) {
287*cfb92d14SAndroid Build Coastguard Worker uint8_t* buf_data = chdr->buf;
288*cfb92d14SAndroid Build Coastguard Worker size_t free_space = cbuf_free_space(chdr);
289*cfb92d14SAndroid Build Coastguard Worker size_t start_index;
290*cfb92d14SAndroid Build Coastguard Worker size_t end_index;
291*cfb92d14SAndroid Build Coastguard Worker size_t bytes_to_end;
292*cfb92d14SAndroid Build Coastguard Worker if (offset > free_space) {
293*cfb92d14SAndroid Build Coastguard Worker return 0;
294*cfb92d14SAndroid Build Coastguard Worker } else if (offset + numbytes > free_space) {
295*cfb92d14SAndroid Build Coastguard Worker numbytes = free_space - offset;
296*cfb92d14SAndroid Build Coastguard Worker }
297*cfb92d14SAndroid Build Coastguard Worker start_index = (cbuf_get_w_index(chdr) + offset) % chdr->size;
298*cfb92d14SAndroid Build Coastguard Worker end_index = (start_index + numbytes) % chdr->size;
299*cfb92d14SAndroid Build Coastguard Worker if (end_index >= start_index) {
300*cfb92d14SAndroid Build Coastguard Worker copy_from(buf_data, start_index, data, data_offset, numbytes);
301*cfb92d14SAndroid Build Coastguard Worker if (bitmap) {
302*cfb92d14SAndroid Build Coastguard Worker bmp_setrange(bitmap, start_index, numbytes);
303*cfb92d14SAndroid Build Coastguard Worker }
304*cfb92d14SAndroid Build Coastguard Worker } else {
305*cfb92d14SAndroid Build Coastguard Worker bytes_to_end = chdr->size - start_index;
306*cfb92d14SAndroid Build Coastguard Worker copy_from(buf_data, start_index, data, data_offset, bytes_to_end);
307*cfb92d14SAndroid Build Coastguard Worker copy_from(buf_data, 0, data, data_offset + bytes_to_end, numbytes - bytes_to_end);
308*cfb92d14SAndroid Build Coastguard Worker if (bitmap) {
309*cfb92d14SAndroid Build Coastguard Worker bmp_setrange(bitmap, start_index, bytes_to_end);
310*cfb92d14SAndroid Build Coastguard Worker bmp_setrange(bitmap, 0, numbytes - bytes_to_end);
311*cfb92d14SAndroid Build Coastguard Worker }
312*cfb92d14SAndroid Build Coastguard Worker }
313*cfb92d14SAndroid Build Coastguard Worker if (firstindex) {
314*cfb92d14SAndroid Build Coastguard Worker *firstindex = start_index;
315*cfb92d14SAndroid Build Coastguard Worker }
316*cfb92d14SAndroid Build Coastguard Worker return numbytes;
317*cfb92d14SAndroid Build Coastguard Worker }
318*cfb92d14SAndroid Build Coastguard Worker
cbuf_reass_merge(struct cbufhead * chdr,size_t numbytes,uint8_t * bitmap)319*cfb92d14SAndroid Build Coastguard Worker size_t cbuf_reass_merge(struct cbufhead* chdr, size_t numbytes, uint8_t* bitmap) {
320*cfb92d14SAndroid Build Coastguard Worker size_t old_w = cbuf_get_w_index(chdr);
321*cfb92d14SAndroid Build Coastguard Worker size_t free_space = cbuf_free_space(chdr);
322*cfb92d14SAndroid Build Coastguard Worker size_t bytes_to_end;
323*cfb92d14SAndroid Build Coastguard Worker if (numbytes > free_space) {
324*cfb92d14SAndroid Build Coastguard Worker numbytes = free_space;
325*cfb92d14SAndroid Build Coastguard Worker }
326*cfb92d14SAndroid Build Coastguard Worker if (bitmap) {
327*cfb92d14SAndroid Build Coastguard Worker bytes_to_end = chdr->size - old_w;
328*cfb92d14SAndroid Build Coastguard Worker if (numbytes <= bytes_to_end) {
329*cfb92d14SAndroid Build Coastguard Worker bmp_clrrange(bitmap, old_w, numbytes);
330*cfb92d14SAndroid Build Coastguard Worker } else {
331*cfb92d14SAndroid Build Coastguard Worker bmp_clrrange(bitmap, old_w, bytes_to_end);
332*cfb92d14SAndroid Build Coastguard Worker bmp_clrrange(bitmap, 0, numbytes - bytes_to_end);
333*cfb92d14SAndroid Build Coastguard Worker }
334*cfb92d14SAndroid Build Coastguard Worker }
335*cfb92d14SAndroid Build Coastguard Worker chdr->used += numbytes;
336*cfb92d14SAndroid Build Coastguard Worker return numbytes;
337*cfb92d14SAndroid Build Coastguard Worker }
338*cfb92d14SAndroid Build Coastguard Worker
cbuf_reass_count_set(struct cbufhead * chdr,size_t offset,uint8_t * bitmap,size_t limit)339*cfb92d14SAndroid Build Coastguard Worker size_t cbuf_reass_count_set(struct cbufhead* chdr, size_t offset, uint8_t* bitmap, size_t limit) {
340*cfb92d14SAndroid Build Coastguard Worker size_t bitmap_size = BITS_TO_BYTES(chdr->size);
341*cfb92d14SAndroid Build Coastguard Worker size_t until_end;
342*cfb92d14SAndroid Build Coastguard Worker offset = (cbuf_get_w_index(chdr) + offset) % chdr->size;
343*cfb92d14SAndroid Build Coastguard Worker until_end = bmp_countset(bitmap, bitmap_size, offset, limit);
344*cfb92d14SAndroid Build Coastguard Worker if (until_end >= limit || until_end < (chdr->size - offset)) {
345*cfb92d14SAndroid Build Coastguard Worker // If we already hit the limit, or if the streak ended before wrapping, then stop here
346*cfb92d14SAndroid Build Coastguard Worker return until_end;
347*cfb92d14SAndroid Build Coastguard Worker }
348*cfb92d14SAndroid Build Coastguard Worker limit -= until_end; // effectively, this is our limit when continuing
349*cfb92d14SAndroid Build Coastguard Worker // Continue until either the new limit or until we have scanned OFFSET bits (if we scan more than OFFSET bits, we'll wrap and scan some parts twice)
350*cfb92d14SAndroid Build Coastguard Worker return until_end + bmp_countset(bitmap, bitmap_size, 0, limit < offset ? limit : offset);
351*cfb92d14SAndroid Build Coastguard Worker }
352*cfb92d14SAndroid Build Coastguard Worker
cbuf_reass_within_offset(struct cbufhead * chdr,size_t offset,size_t index)353*cfb92d14SAndroid Build Coastguard Worker int cbuf_reass_within_offset(struct cbufhead* chdr, size_t offset, size_t index) {
354*cfb92d14SAndroid Build Coastguard Worker size_t range_start = cbuf_get_w_index(chdr);
355*cfb92d14SAndroid Build Coastguard Worker size_t range_end = (range_start + offset) % chdr->size;
356*cfb92d14SAndroid Build Coastguard Worker if (range_end >= range_start) {
357*cfb92d14SAndroid Build Coastguard Worker return index >= range_start && index < range_end;
358*cfb92d14SAndroid Build Coastguard Worker } else {
359*cfb92d14SAndroid Build Coastguard Worker return index < range_end || (index >= range_start && index < chdr->size);
360*cfb92d14SAndroid Build Coastguard Worker }
361*cfb92d14SAndroid Build Coastguard Worker }
362