1a74702c6SGeorge Wang/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc.  See LICENSE. */
2fbc6cc04SDmitri Tikhonov#include <assert.h>
3fbc6cc04SDmitri Tikhonov#include <limits.h>
4fbc6cc04SDmitri Tikhonov#include <stddef.h>
5fbc6cc04SDmitri Tikhonov#include <stdint.h>
6fbc6cc04SDmitri Tikhonov
7fbc6cc04SDmitri Tikhonov#include "lsquic_int_types.h"
8fbc6cc04SDmitri Tikhonov#include "lsquic_trechist.h"
9fbc6cc04SDmitri Tikhonov
10fbc6cc04SDmitri Tikhonov
11fbc6cc04SDmitri Tikhonovstatic unsigned
12fbc6cc04SDmitri Tikhonovfind_free_slot (uint32_t slots)
13fbc6cc04SDmitri Tikhonov{
14fbc6cc04SDmitri Tikhonov#if __GNUC__
15fbc6cc04SDmitri Tikhonov    return __builtin_ctz(~slots);
16fbc6cc04SDmitri Tikhonov#else
17fbc6cc04SDmitri Tikhonov    unsigned n;
18fbc6cc04SDmitri Tikhonov
19fbc6cc04SDmitri Tikhonov    slots =~ slots;
20fbc6cc04SDmitri Tikhonov    n = 0;
21fbc6cc04SDmitri Tikhonov
22fbc6cc04SDmitri Tikhonov    if (0 == (slots & ((1ULL << 16) - 1))) { n += 16; slots >>= 16; }
23fbc6cc04SDmitri Tikhonov    if (0 == (slots & ((1ULL <<  8) - 1))) { n +=  8; slots >>=  8; }
24fbc6cc04SDmitri Tikhonov    if (0 == (slots & ((1ULL <<  4) - 1))) { n +=  4; slots >>=  4; }
25fbc6cc04SDmitri Tikhonov    if (0 == (slots & ((1ULL <<  2) - 1))) { n +=  2; slots >>=  2; }
26fbc6cc04SDmitri Tikhonov    if (0 == (slots & ((1ULL <<  1) - 1))) { n +=  1; slots >>=  1; }
27fbc6cc04SDmitri Tikhonov    return n;
28fbc6cc04SDmitri Tikhonov#endif
29fbc6cc04SDmitri Tikhonov}
30fbc6cc04SDmitri Tikhonov
31fbc6cc04SDmitri Tikhonov
3226e8f082SDmitri Tikhonov/* When capacity is reached, smallest element is removed.  When the number
3326e8f082SDmitri Tikhonov * of elements in a single range cannot be represented by te_count, an
3426e8f082SDmitri Tikhonov * error is returned.  This is the only error this function returns.
3526e8f082SDmitri Tikhonov */
36fbc6cc04SDmitri Tikhonovint
37fbc6cc04SDmitri Tikhonovlsquic_trechist_insert (trechist_mask_t *mask, struct trechist_elem *elems,
38fbc6cc04SDmitri Tikhonov                                                            uint32_t packno)
39fbc6cc04SDmitri Tikhonov{
4026e8f082SDmitri Tikhonov    struct trechist_elem *el, *prev, *cur, *next;
41fbc6cc04SDmitri Tikhonov    unsigned idx;
42fbc6cc04SDmitri Tikhonov
43fbc6cc04SDmitri Tikhonov    if (*mask == 0)
44fbc6cc04SDmitri Tikhonov    {
45fbc6cc04SDmitri Tikhonov        elems[0].te_low   = packno;
46fbc6cc04SDmitri Tikhonov        elems[0].te_count = 1;
47fbc6cc04SDmitri Tikhonov        elems[0].te_next  = 0;
48fbc6cc04SDmitri Tikhonov        *mask |= 1;
49fbc6cc04SDmitri Tikhonov        return 0;
50fbc6cc04SDmitri Tikhonov    }
51fbc6cc04SDmitri Tikhonov
52fbc6cc04SDmitri Tikhonov    el = elems;
53fbc6cc04SDmitri Tikhonov    prev = NULL;
54fbc6cc04SDmitri Tikhonov    while (1)
55fbc6cc04SDmitri Tikhonov    {
56fbc6cc04SDmitri Tikhonov        if (packno > TE_HIGH(el) + 1)
57fbc6cc04SDmitri Tikhonov            goto insert_before;
58fbc6cc04SDmitri Tikhonov        if (packno == el->te_low - 1)
59fbc6cc04SDmitri Tikhonov        {
6026e8f082SDmitri Tikhonov            if (el->te_next && el->te_low == TE_HIGH(&elems[el->te_next]) + 2)
61fbc6cc04SDmitri Tikhonov            {
6226e8f082SDmitri Tikhonov                if (el->te_count + elems[el->te_next].te_count - 1 > UCHAR_MAX)
6326e8f082SDmitri Tikhonov                    return -1;
64fbc6cc04SDmitri Tikhonov                *mask &= ~(1u << el->te_next);
6526e8f082SDmitri Tikhonov                el->te_count += elems[el->te_next].te_count + 1;
66fbc6cc04SDmitri Tikhonov                el->te_low    = elems[el->te_next].te_low;
67fbc6cc04SDmitri Tikhonov                el->te_next   = elems[el->te_next].te_next;
68fbc6cc04SDmitri Tikhonov            }
6926e8f082SDmitri Tikhonov            else
7026e8f082SDmitri Tikhonov            {
7126e8f082SDmitri Tikhonov                if (el->te_count == UCHAR_MAX)
7226e8f082SDmitri Tikhonov                    return -1;
7326e8f082SDmitri Tikhonov                --el->te_low;
7426e8f082SDmitri Tikhonov                ++el->te_count;
7526e8f082SDmitri Tikhonov            }
76fbc6cc04SDmitri Tikhonov            return 0;
77fbc6cc04SDmitri Tikhonov        }
78fbc6cc04SDmitri Tikhonov        if (packno == TE_HIGH(el) + 1)
79fbc6cc04SDmitri Tikhonov        {
80fbc6cc04SDmitri Tikhonov            if (el->te_count == UCHAR_MAX)
81fbc6cc04SDmitri Tikhonov                return -1;
82fbc6cc04SDmitri Tikhonov            ++el->te_count;
83fbc6cc04SDmitri Tikhonov            return 0;
84fbc6cc04SDmitri Tikhonov        }
85fbc6cc04SDmitri Tikhonov        if (packno >= el->te_low && packno <= TE_HIGH(el))
8626e8f082SDmitri Tikhonov            return 0;   /* Dup */
87fbc6cc04SDmitri Tikhonov        if (!el->te_next)
88fbc6cc04SDmitri Tikhonov            break;  /* insert tail */
89fbc6cc04SDmitri Tikhonov        prev = el;
90fbc6cc04SDmitri Tikhonov        el = &elems[el->te_next];
91fbc6cc04SDmitri Tikhonov    }
92fbc6cc04SDmitri Tikhonov
9326e8f082SDmitri Tikhonov    if (*mask == TRECHIST_MAX_RANGES_MASK)
9426e8f082SDmitri Tikhonov        /* No need to insert element smaller than the smallest element
9526e8f082SDmitri Tikhonov         * already in our list.  The new element "overflows".
9626e8f082SDmitri Tikhonov         */
9726e8f082SDmitri Tikhonov        return 0;
98fbc6cc04SDmitri Tikhonov
99fbc6cc04SDmitri Tikhonov    idx = find_free_slot(*mask);
100fbc6cc04SDmitri Tikhonov    elems[idx].te_low   = packno;
101fbc6cc04SDmitri Tikhonov    elems[idx].te_count = 1;
102fbc6cc04SDmitri Tikhonov    elems[idx].te_next  = 0;
103fbc6cc04SDmitri Tikhonov    *mask |= 1u << idx;;
104fbc6cc04SDmitri Tikhonov    el->te_next = idx;
105fbc6cc04SDmitri Tikhonov    return 0;
106fbc6cc04SDmitri Tikhonov
107fbc6cc04SDmitri Tikhonov  insert_before:
108fbc6cc04SDmitri Tikhonov
10926e8f082SDmitri Tikhonov    if (*mask != TRECHIST_MAX_RANGES_MASK)
11026e8f082SDmitri Tikhonov        idx = find_free_slot(*mask);
11126e8f082SDmitri Tikhonov    else
11226e8f082SDmitri Tikhonov    {   /* Drop last element and reuse its slot */
11326e8f082SDmitri Tikhonov        for (next = &elems[el->te_next], cur = el; next->te_next;
11426e8f082SDmitri Tikhonov                                cur = next, next = &elems[cur->te_next])
11526e8f082SDmitri Tikhonov            ;
11626e8f082SDmitri Tikhonov        idx = cur->te_next;
11726e8f082SDmitri Tikhonov        cur->te_next = 0;
11826e8f082SDmitri Tikhonov    }
119fbc6cc04SDmitri Tikhonov
120fbc6cc04SDmitri Tikhonov    *mask |= 1u << idx;;
121fbc6cc04SDmitri Tikhonov    if (el == elems)
122fbc6cc04SDmitri Tikhonov    {
123fbc6cc04SDmitri Tikhonov        elems[idx] = *el;
124fbc6cc04SDmitri Tikhonov        elems[0].te_low   = packno;
125fbc6cc04SDmitri Tikhonov        elems[0].te_count = 1;
126fbc6cc04SDmitri Tikhonov        elems[0].te_next  = idx;
127fbc6cc04SDmitri Tikhonov    }
128fbc6cc04SDmitri Tikhonov    else
129fbc6cc04SDmitri Tikhonov    {
130fbc6cc04SDmitri Tikhonov        assert(prev);
131fbc6cc04SDmitri Tikhonov        elems[idx].te_low   = packno;
132fbc6cc04SDmitri Tikhonov        elems[idx].te_count = 1;
133fbc6cc04SDmitri Tikhonov        elems[idx].te_next  = prev->te_next;
134fbc6cc04SDmitri Tikhonov        prev->te_next = idx;
135fbc6cc04SDmitri Tikhonov    }
136fbc6cc04SDmitri Tikhonov
137fbc6cc04SDmitri Tikhonov    return 0;
138fbc6cc04SDmitri Tikhonov}
139fbc6cc04SDmitri Tikhonov
140fbc6cc04SDmitri Tikhonov
141fbc6cc04SDmitri Tikhonovvoid
142fbc6cc04SDmitri Tikhonovlsquic_trechist_iter (struct trechist_iter *iter, trechist_mask_t mask,
143fbc6cc04SDmitri Tikhonov                                            const struct trechist_elem *elems)
144fbc6cc04SDmitri Tikhonov{
145fbc6cc04SDmitri Tikhonov    iter->mask = mask;
146fbc6cc04SDmitri Tikhonov    iter->elems = elems;
147fbc6cc04SDmitri Tikhonov}
148fbc6cc04SDmitri Tikhonov
149fbc6cc04SDmitri Tikhonov
150fbc6cc04SDmitri Tikhonovconst struct lsquic_packno_range *
151fbc6cc04SDmitri Tikhonovlsquic_trechist_first (void *iter_p)
152fbc6cc04SDmitri Tikhonov{
153fbc6cc04SDmitri Tikhonov    struct trechist_iter *const iter = iter_p;
154fbc6cc04SDmitri Tikhonov
155fbc6cc04SDmitri Tikhonov    if (iter->mask == 0)
156fbc6cc04SDmitri Tikhonov        return NULL;
157fbc6cc04SDmitri Tikhonov
158fbc6cc04SDmitri Tikhonov    iter->next = iter->elems[0].te_next;
159fbc6cc04SDmitri Tikhonov    iter->range.low = iter->elems[0].te_low;
160fbc6cc04SDmitri Tikhonov    iter->range.high = TE_HIGH(&iter->elems[0]);
161fbc6cc04SDmitri Tikhonov    return &iter->range;
162fbc6cc04SDmitri Tikhonov}
163fbc6cc04SDmitri Tikhonov
164fbc6cc04SDmitri Tikhonov
165fbc6cc04SDmitri Tikhonovconst struct lsquic_packno_range *
166fbc6cc04SDmitri Tikhonovlsquic_trechist_next (void *iter_p)
167fbc6cc04SDmitri Tikhonov{
168fbc6cc04SDmitri Tikhonov    struct trechist_iter *const iter = iter_p;
169fbc6cc04SDmitri Tikhonov
170fbc6cc04SDmitri Tikhonov    if (iter->next == 0)
171fbc6cc04SDmitri Tikhonov        return NULL;
172fbc6cc04SDmitri Tikhonov
173fbc6cc04SDmitri Tikhonov    iter->range.low = iter->elems[iter->next].te_low;
174fbc6cc04SDmitri Tikhonov    iter->range.high = TE_HIGH(&iter->elems[iter->next]);
175fbc6cc04SDmitri Tikhonov    iter->next = iter->elems[iter->next].te_next;
176fbc6cc04SDmitri Tikhonov    return &iter->range;
177fbc6cc04SDmitri Tikhonov}
178fbc6cc04SDmitri Tikhonov
179fbc6cc04SDmitri Tikhonov
18026e8f082SDmitri Tikhonov/* First TRECHIST_MAX_RANGES ranges are copied */
18126e8f082SDmitri Tikhonovvoid
182fbc6cc04SDmitri Tikhonovlsquic_trechist_copy_ranges (trechist_mask_t *mask,
183fbc6cc04SDmitri Tikhonov                    struct trechist_elem *elems, void *src_rechist,
184fbc6cc04SDmitri Tikhonov                    const struct lsquic_packno_range * (*first) (void *),
185fbc6cc04SDmitri Tikhonov                    const struct lsquic_packno_range * (*next) (void *))
186fbc6cc04SDmitri Tikhonov{
187fbc6cc04SDmitri Tikhonov    const struct lsquic_packno_range *range;
188fbc6cc04SDmitri Tikhonov    struct trechist_elem *el;
189fbc6cc04SDmitri Tikhonov    unsigned i;
190fbc6cc04SDmitri Tikhonov
191fbc6cc04SDmitri Tikhonov    for (el = NULL, i = 0, range = first(src_rechist);
192fbc6cc04SDmitri Tikhonov            i < TRECHIST_MAX_RANGES && range;
193fbc6cc04SDmitri Tikhonov                range = next(src_rechist), ++i)
194fbc6cc04SDmitri Tikhonov    {
195fbc6cc04SDmitri Tikhonov        /* This should never happen: */
196fbc6cc04SDmitri Tikhonov        assert(range->high - range->low + 1 <= UINT_MAX);
197fbc6cc04SDmitri Tikhonov
198fbc6cc04SDmitri Tikhonov        el = &elems[i];
199fbc6cc04SDmitri Tikhonov        el->te_low = range->low;
200fbc6cc04SDmitri Tikhonov        el->te_count = range->high - range->low + 1;
201fbc6cc04SDmitri Tikhonov        el->te_next = i + 1;
202fbc6cc04SDmitri Tikhonov    }
203fbc6cc04SDmitri Tikhonov
20426e8f082SDmitri Tikhonov    if (el)
205fbc6cc04SDmitri Tikhonov        el->te_next = 0;
20626e8f082SDmitri Tikhonov
20726e8f082SDmitri Tikhonov    if (i < 32)
208fbc6cc04SDmitri Tikhonov        *mask = (1u << i) - 1;
209fbc6cc04SDmitri Tikhonov    else
21026e8f082SDmitri Tikhonov        *mask = UINT32_MAX;
211fbc6cc04SDmitri Tikhonov}
212fbc6cc04SDmitri Tikhonov
213fbc6cc04SDmitri Tikhonov
214fbc6cc04SDmitri Tikhonovint
215fbc6cc04SDmitri Tikhonovlsquic_trechist_contains (trechist_mask_t mask,
216fbc6cc04SDmitri Tikhonov                    const struct trechist_elem *elems, uint32_t packno)
217fbc6cc04SDmitri Tikhonov{
218fbc6cc04SDmitri Tikhonov    const struct trechist_elem *el;
219fbc6cc04SDmitri Tikhonov    if (mask == 0)
220fbc6cc04SDmitri Tikhonov        return 0;
221fbc6cc04SDmitri Tikhonov
222fbc6cc04SDmitri Tikhonov    el = &elems[0];
223fbc6cc04SDmitri Tikhonov    while (1)
224fbc6cc04SDmitri Tikhonov    {
225fbc6cc04SDmitri Tikhonov        if (packno > TE_HIGH(el))
226fbc6cc04SDmitri Tikhonov            return 0;
227fbc6cc04SDmitri Tikhonov        if (packno >= el->te_low)
228fbc6cc04SDmitri Tikhonov            return 1;
229fbc6cc04SDmitri Tikhonov        if (el->te_next)
230fbc6cc04SDmitri Tikhonov            el = &elems[el->te_next];
231fbc6cc04SDmitri Tikhonov        else
232fbc6cc04SDmitri Tikhonov            break;
233fbc6cc04SDmitri Tikhonov    }
234fbc6cc04SDmitri Tikhonov
235fbc6cc04SDmitri Tikhonov    return 0;
236fbc6cc04SDmitri Tikhonov}
237fbc6cc04SDmitri Tikhonov
238fbc6cc04SDmitri Tikhonov
239fbc6cc04SDmitri Tikhonovuint32_t
240fbc6cc04SDmitri Tikhonovlsquic_trechist_max (trechist_mask_t mask, const struct trechist_elem *elems)
241fbc6cc04SDmitri Tikhonov{
242fbc6cc04SDmitri Tikhonov    if (mask)
243fbc6cc04SDmitri Tikhonov    {
244fbc6cc04SDmitri Tikhonov        assert(mask & 1);
245fbc6cc04SDmitri Tikhonov        return TE_HIGH(&elems[0]);
246fbc6cc04SDmitri Tikhonov    }
247fbc6cc04SDmitri Tikhonov    else
248fbc6cc04SDmitri Tikhonov        return 0;
249fbc6cc04SDmitri Tikhonov}
250