lsquic_trechist.c revision fbc6cc04
1/* Copyright (c) 2017 - 2020 LiteSpeed Technologies Inc.  See LICENSE. */
2#include <assert.h>
3#include <limits.h>
4#include <stddef.h>
5#include <stdint.h>
6
7#include "lsquic_int_types.h"
8#include "lsquic_trechist.h"
9
10
11static unsigned
12find_free_slot (uint32_t slots)
13{
14#if __GNUC__
15    return __builtin_ctz(~slots);
16#else
17    unsigned n;
18
19    slots =~ slots;
20    n = 0;
21
22    if (0 == (slots & ((1ULL << 16) - 1))) { n += 16; slots >>= 16; }
23    if (0 == (slots & ((1ULL <<  8) - 1))) { n +=  8; slots >>=  8; }
24    if (0 == (slots & ((1ULL <<  4) - 1))) { n +=  4; slots >>=  4; }
25    if (0 == (slots & ((1ULL <<  2) - 1))) { n +=  2; slots >>=  2; }
26    if (0 == (slots & ((1ULL <<  1) - 1))) { n +=  1; slots >>=  1; }
27    return n;
28#endif
29}
30
31
32/* Returns 0 on success, 1 if dup, -1 if out of elements */
33int
34lsquic_trechist_insert (trechist_mask_t *mask, struct trechist_elem *elems,
35                                                            uint32_t packno)
36{
37    struct trechist_elem *el, *prev;
38    unsigned idx;
39
40    if (*mask == 0)
41    {
42        elems[0].te_low   = packno;
43        elems[0].te_count = 1;
44        elems[0].te_next  = 0;
45        *mask |= 1;
46        return 0;
47    }
48
49    el = elems;
50    prev = NULL;
51    while (1)
52    {
53        if (packno > TE_HIGH(el) + 1)
54            goto insert_before;
55        if (packno == el->te_low - 1)
56        {
57            if (el->te_count == UCHAR_MAX)
58                return -1;
59            --el->te_low;
60            ++el->te_count;
61            if (el->te_next && el->te_low == TE_HIGH(&elems[el->te_next]) + 1)
62            {
63                *mask &= ~(1u << el->te_next);
64                el->te_count += elems[el->te_next].te_count;
65                el->te_low    = elems[el->te_next].te_low;
66                el->te_next   = elems[el->te_next].te_next;
67            }
68            return 0;
69        }
70        if (packno == TE_HIGH(el) + 1)
71        {
72            if (el->te_count == UCHAR_MAX)
73                return -1;
74            ++el->te_count;
75            return 0;
76        }
77        if (packno >= el->te_low && packno <= TE_HIGH(el))
78            return 1;   /* Dup */
79        if (!el->te_next)
80            break;  /* insert tail */
81        prev = el;
82        el = &elems[el->te_next];
83    }
84
85    if (*mask == ((1u << TRECHIST_MAX_RANGES) - 1))
86        return -1;
87
88    idx = find_free_slot(*mask);
89    elems[idx].te_low   = packno;
90    elems[idx].te_count = 1;
91    elems[idx].te_next  = 0;
92    *mask |= 1u << idx;;
93    el->te_next = idx;
94    return 0;
95
96  insert_before:
97
98    if (*mask == ((1u << TRECHIST_MAX_RANGES) - 1))
99        return -1;
100
101    idx = find_free_slot(*mask);
102    *mask |= 1u << idx;;
103    if (el == elems)
104    {
105        elems[idx] = *el;
106        elems[0].te_low   = packno;
107        elems[0].te_count = 1;
108        elems[0].te_next  = idx;
109    }
110    else
111    {
112        assert(prev);
113        elems[idx].te_low   = packno;
114        elems[idx].te_count = 1;
115        elems[idx].te_next  = prev->te_next;
116        prev->te_next = idx;
117    }
118
119    return 0;
120}
121
122
123void
124lsquic_trechist_iter (struct trechist_iter *iter, trechist_mask_t mask,
125                                            const struct trechist_elem *elems)
126{
127    iter->mask = mask;
128    iter->elems = elems;
129}
130
131
132const struct lsquic_packno_range *
133lsquic_trechist_first (void *iter_p)
134{
135    struct trechist_iter *const iter = iter_p;
136
137    if (iter->mask == 0)
138        return NULL;
139
140    iter->next = iter->elems[0].te_next;
141    iter->range.low = iter->elems[0].te_low;
142    iter->range.high = TE_HIGH(&iter->elems[0]);
143    return &iter->range;
144}
145
146
147const struct lsquic_packno_range *
148lsquic_trechist_next (void *iter_p)
149{
150    struct trechist_iter *const iter = iter_p;
151
152    if (iter->next == 0)
153        return NULL;
154
155    iter->range.low = iter->elems[iter->next].te_low;
156    iter->range.high = TE_HIGH(&iter->elems[iter->next]);
157    iter->next = iter->elems[iter->next].te_next;
158    return &iter->range;
159}
160
161
162int
163lsquic_trechist_copy_ranges (trechist_mask_t *mask,
164                    struct trechist_elem *elems, void *src_rechist,
165                    const struct lsquic_packno_range * (*first) (void *),
166                    const struct lsquic_packno_range * (*next) (void *))
167{
168    const struct lsquic_packno_range *range;
169    struct trechist_elem *el;
170    unsigned i;
171
172    for (el = NULL, i = 0, range = first(src_rechist);
173            i < TRECHIST_MAX_RANGES && range;
174                range = next(src_rechist), ++i)
175    {
176        /* This should never happen: */
177        assert(range->high - range->low + 1 <= UINT_MAX);
178
179        el = &elems[i];
180        el->te_low = range->low;
181        el->te_count = range->high - range->low + 1;
182        el->te_next = i + 1;
183    }
184
185    if (!range && el)
186    {
187        el->te_next = 0;
188        *mask = (1u << i) - 1;
189        return 0;
190    }
191    else if (!el)
192    {
193        *mask = 0;
194        return 0;   /* Must have been an empty */
195    }
196    else
197        return -1;
198}
199
200
201int
202lsquic_trechist_contains (trechist_mask_t mask,
203                    const struct trechist_elem *elems, uint32_t packno)
204{
205    const struct trechist_elem *el;
206    if (mask == 0)
207        return 0;
208
209    el = &elems[0];
210    while (1)
211    {
212        if (packno > TE_HIGH(el))
213            return 0;
214        if (packno >= el->te_low)
215            return 1;
216        if (el->te_next)
217            el = &elems[el->te_next];
218        else
219            break;
220    }
221
222    return 0;
223}
224
225
226uint32_t
227lsquic_trechist_max (trechist_mask_t mask, const struct trechist_elem *elems)
228{
229    if (mask)
230    {
231        assert(mask & 1);
232        return TE_HIGH(&elems[0]);
233    }
234    else
235        return 0;
236}
237