/src/h2o/deps/quicly/lib/ranges.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2017 Fastly, Kazuho Oku |
3 | | * |
4 | | * Permission is hereby granted, free of charge, to any person obtaining a copy |
5 | | * of this software and associated documentation files (the "Software"), to |
6 | | * deal in the Software without restriction, including without limitation the |
7 | | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
8 | | * sell copies of the Software, and to permit persons to whom the Software is |
9 | | * furnished to do so, subject to the following conditions: |
10 | | * |
11 | | * The above copyright notice and this permission notice shall be included in |
12 | | * all copies or substantial portions of the Software. |
13 | | * |
14 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
15 | | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
16 | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
17 | | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
18 | | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
19 | | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
20 | | * IN THE SOFTWARE. |
21 | | */ |
22 | | #include <assert.h> |
23 | | #include <stdlib.h> |
24 | | #include <string.h> |
25 | | #include "picotls.h" |
26 | | #include "quicly/constants.h" |
27 | | #include "quicly/ranges.h" |
28 | | |
29 | | #define COPY(dst, src, n) \ |
30 | 970 | do { \ |
31 | 970 | size_t _n = (n); \ |
32 | 970 | if (_n != 0) \ |
33 | 970 | memcpy((dst), (src), sizeof(quicly_range_t) * _n); \ |
34 | 970 | } while (0) |
35 | | #define MOVE(dst, src, n) \ |
36 | 79.6k | do { \ |
37 | 79.6k | size_t _n = (n); \ |
38 | 79.6k | if (_n != 0) \ |
39 | 79.6k | memmove((dst), (src), sizeof(quicly_range_t) * _n); \ |
40 | 79.6k | } while (0) |
41 | | |
42 | | static int insert_at(quicly_ranges_t *ranges, uint64_t start, uint64_t end, size_t slot) |
43 | 57.6k | { |
44 | 57.6k | if (ranges->num_ranges == ranges->capacity) { |
45 | 485 | size_t new_capacity = ranges->capacity < 4 ? 4 : ranges->capacity * 2; |
46 | 485 | quicly_range_t *new_ranges = malloc(new_capacity * sizeof(*new_ranges)); |
47 | 485 | if (new_ranges == NULL) |
48 | 0 | return PTLS_ERROR_NO_MEMORY; |
49 | 485 | COPY(new_ranges, ranges->ranges, slot); |
50 | 485 | COPY(new_ranges + slot + 1, ranges->ranges + slot, ranges->num_ranges - slot); |
51 | 485 | if (ranges->ranges != &ranges->_initial) |
52 | 0 | free(ranges->ranges); |
53 | 485 | ranges->ranges = new_ranges; |
54 | 485 | ranges->capacity = new_capacity; |
55 | 57.1k | } else { |
56 | 57.1k | MOVE(ranges->ranges + slot + 1, ranges->ranges + slot, ranges->num_ranges - slot); |
57 | 57.1k | } |
58 | 57.6k | ranges->ranges[slot] = (quicly_range_t){start, end}; |
59 | 57.6k | ++ranges->num_ranges; |
60 | 57.6k | return 0; |
61 | 57.6k | } |
62 | | |
63 | | void quicly_ranges_drop_by_range_indices(quicly_ranges_t *ranges, size_t begin_range_index, size_t end_range_index) |
64 | 22.5k | { |
65 | 22.5k | assert(begin_range_index < end_range_index); |
66 | | |
67 | 22.5k | MOVE(ranges->ranges + begin_range_index, ranges->ranges + end_range_index, ranges->num_ranges - end_range_index); |
68 | 22.5k | ranges->num_ranges -= end_range_index - begin_range_index; |
69 | 22.5k | if (ranges->capacity > 4 && ranges->num_ranges * 3 <= ranges->capacity) { |
70 | 0 | size_t new_capacity = ranges->capacity / 2; |
71 | 0 | quicly_range_t *new_ranges = realloc(ranges->ranges, new_capacity * sizeof(*new_ranges)); |
72 | 0 | if (new_ranges != NULL) { |
73 | 0 | ranges->ranges = new_ranges; |
74 | 0 | ranges->capacity = new_capacity; |
75 | 0 | } |
76 | 0 | } |
77 | 22.5k | } |
78 | | |
79 | | static inline int merge_update(quicly_ranges_t *ranges, uint64_t start, uint64_t end, size_t slot, size_t end_slot) |
80 | 8.95k | { |
81 | 8.95k | if (start < ranges->ranges[slot].start) |
82 | 0 | ranges->ranges[slot].start = start; |
83 | 8.95k | ranges->ranges[slot].end = end < ranges->ranges[end_slot].end ? ranges->ranges[end_slot].end : end; |
84 | | |
85 | 8.95k | if (slot != end_slot) |
86 | 0 | quicly_ranges_drop_by_range_indices(ranges, slot + 1, end_slot + 1); |
87 | | |
88 | 8.95k | return 0; |
89 | 8.95k | } |
90 | | |
91 | | int quicly_ranges_init_with_range(quicly_ranges_t *ranges, uint64_t start, uint64_t end) |
92 | 34.2k | { |
93 | 34.2k | quicly_ranges_init(ranges); |
94 | 34.2k | return insert_at(ranges, start, end, 0); |
95 | 34.2k | } |
96 | | |
97 | | int quicly_ranges_add(quicly_ranges_t *ranges, uint64_t start, uint64_t end) |
98 | 32.2k | { |
99 | 32.2k | size_t slot, end_slot; |
100 | | |
101 | 32.2k | assert(start <= end); |
102 | | |
103 | 32.2k | if (start == end) |
104 | 0 | return 0; |
105 | | |
106 | 32.2k | if (ranges->num_ranges == 0) { |
107 | 22.8k | return insert_at(ranges, start, end, 0); |
108 | 22.8k | } else if (ranges->ranges[ranges->num_ranges - 1].end < start) { |
109 | 485 | return insert_at(ranges, start, end, ranges->num_ranges); |
110 | 485 | } |
111 | | |
112 | | /* find the slot that should contain `end` */ |
113 | 8.95k | for (slot = ranges->num_ranges - 1;; --slot) { |
114 | 8.95k | if (ranges->ranges[slot].start <= end) |
115 | 8.95k | break; |
116 | 0 | if (slot == 0) |
117 | 0 | return insert_at(ranges, start, end, 0); |
118 | 0 | } |
119 | 8.95k | end_slot = slot; |
120 | | |
121 | | /* find the slot that should contain `start` */ |
122 | 8.95k | do { |
123 | 8.95k | if (ranges->ranges[slot].end == start) { |
124 | 8.95k | return merge_update(ranges, start, end, slot, end_slot); |
125 | 8.95k | } else if (ranges->ranges[slot].end < start) { |
126 | 0 | if (slot++ == end_slot) { |
127 | 0 | return insert_at(ranges, start, end, slot); |
128 | 0 | } else { |
129 | 0 | return merge_update(ranges, start, end, slot, end_slot); |
130 | 0 | } |
131 | 0 | } |
132 | 8.95k | } while (slot-- != 0); |
133 | | |
134 | 0 | return merge_update(ranges, start, end, 0, end_slot); |
135 | 8.95k | } |
136 | | |
137 | | int quicly_ranges_subtract(quicly_ranges_t *ranges, uint64_t start, uint64_t end) |
138 | 46.4k | { |
139 | 46.4k | size_t shrink_from, slot; |
140 | | |
141 | 46.4k | assert(start <= end); |
142 | | |
143 | 46.4k | if (start == end) |
144 | 0 | return 0; |
145 | | |
146 | 46.4k | if (ranges->num_ranges == 0) { |
147 | 2.90k | return 0; |
148 | 43.5k | } else if (end <= ranges->ranges[0].start) { |
149 | 0 | return 0; |
150 | 43.5k | } else if (ranges->ranges[ranges->num_ranges - 1].end <= start) { |
151 | 0 | return 0; |
152 | 0 | } |
153 | | |
154 | | /* find the first overlapping slot */ |
155 | 43.5k | for (slot = 0; ranges->ranges[slot].end < start; ++slot) |
156 | 0 | ; |
157 | | |
158 | 43.5k | if (end <= ranges->ranges[slot].end) { |
159 | | /* first overlapping slot is the only slot that we will ever modify */ |
160 | 43.5k | if (end <= ranges->ranges[slot].start) |
161 | 0 | return 0; |
162 | 43.5k | if (start <= ranges->ranges[slot].start) { |
163 | 43.5k | ranges->ranges[slot].start = end; |
164 | 43.5k | } else if (end == ranges->ranges[slot].end) { |
165 | 0 | ranges->ranges[slot].end = start; |
166 | 0 | } else { |
167 | | /* split */ |
168 | 0 | int ret; |
169 | 0 | if ((ret = insert_at(ranges, end, ranges->ranges[slot].end, slot + 1)) != 0) |
170 | 0 | return ret; |
171 | 0 | ranges->ranges[slot].end = start; |
172 | 0 | return 0; |
173 | 0 | } |
174 | | /* remove the slot if the range has become empty */ |
175 | 43.5k | if (ranges->ranges[slot].start == ranges->ranges[slot].end) |
176 | 22.5k | quicly_ranges_drop_by_range_indices(ranges, slot, slot + 1); |
177 | 43.5k | return 0; |
178 | 43.5k | } |
179 | | |
180 | | /* specified region covers multiple slots */ |
181 | 0 | if (start <= ranges->ranges[slot].start) { |
182 | 0 | shrink_from = slot; |
183 | 0 | } else { |
184 | 0 | ranges->ranges[slot].end = start; |
185 | 0 | shrink_from = slot + 1; |
186 | 0 | } |
187 | | |
188 | | /* find the last overlapping slot */ |
189 | 0 | for (++slot; slot != ranges->num_ranges; ++slot) { |
190 | 0 | if (end <= ranges->ranges[slot].start) |
191 | 0 | break; |
192 | 0 | if (end < ranges->ranges[slot].end) { |
193 | 0 | ranges->ranges[slot].start = end; |
194 | 0 | break; |
195 | 0 | } |
196 | 0 | } |
197 | | |
198 | | /* remove shrink_from..slot */ |
199 | 0 | if (shrink_from != slot) |
200 | 0 | quicly_ranges_drop_by_range_indices(ranges, shrink_from, slot); |
201 | |
|
202 | 0 | return 0; |
203 | 43.5k | } |