Skip to main content

oxgraph_hyper_bcsr/internal/
traits.rs

1//! Topology and hypergraph trait implementations for [`BcsrHypergraph`].
2//!
3//! [`BcsrHypergraph`]: crate::BcsrHypergraph
4
5use oxgraph_hyper::{
6    ContainsElement, ContainsIncidence, ContainsRelation, DirectedHyperedgeIncidences,
7    DirectedHyperedgeParticipants, DirectedVertexHyperedges, ElementIncidenceCount,
8    ElementIncidences, ElementIndex, ElementPredecessors, ElementSuccessors,
9    HyperedgeParticipantCount, HyperedgeParticipants, HypergraphCounts, IncidenceBase,
10    IncidenceCounts, IncidenceElement, IncidenceIndex, IncidenceRelation, IncidenceRole,
11    IncidentHyperedgeCount, IncidentHyperedges, RelationIncidenceCount, RelationIncidences,
12    RelationIndex, TopologyBase, TopologyCounts,
13};
14
15use crate::{
16    id::{BcsrHyperedgeId, BcsrParticipantId, BcsrRole, BcsrVertexId},
17    internal::{
18        iter::{
19            BcsrChainedHyperedges, BcsrChainedParticipants, BcsrChainedRelationIncidences,
20            BcsrElementIncidences, BcsrHyperedgeSlice, BcsrParticipantSlice,
21            BcsrPredecessorVertices, BcsrSuccessorVertices, BcsrVertexSlice,
22        },
23        validation::{index_to_usize_validated, usize_to_index_validated},
24        view::BcsrHypergraph,
25    },
26    word::{BcsrIndex, BcsrWord},
27};
28
29/// Private shorthand for the generic BCSR view.
30type View<'a, V, R, I, O, VW, RW> = BcsrHypergraph<'a, V, R, I, O, VW, RW>;
31
32impl<V, R, I, O, VW, RW> TopologyBase for View<'_, V, R, I, O, VW, RW>
33where
34    V: BcsrIndex,
35    R: BcsrIndex,
36    I: BcsrIndex,
37    O: BcsrWord<Index = I>,
38    VW: BcsrWord<Index = V>,
39    RW: BcsrWord<Index = R>,
40{
41    type ElementId = BcsrVertexId<V>;
42    type RelationId = BcsrHyperedgeId<R>;
43}
44
45impl<V, R, I, O, VW, RW> IncidenceBase for View<'_, V, R, I, O, VW, RW>
46where
47    V: BcsrIndex,
48    R: BcsrIndex,
49    I: BcsrIndex,
50    O: BcsrWord<Index = I>,
51    VW: BcsrWord<Index = V>,
52    RW: BcsrWord<Index = R>,
53{
54    type IncidenceId = BcsrParticipantId<I>;
55    type Role = BcsrRole;
56}
57
58impl<V, R, I, O, VW, RW> TopologyCounts for View<'_, V, R, I, O, VW, RW>
59where
60    V: BcsrIndex,
61    R: BcsrIndex,
62    I: BcsrIndex,
63    O: BcsrWord<Index = I>,
64    VW: BcsrWord<Index = V>,
65    RW: BcsrWord<Index = R>,
66{
67    fn element_count(&self) -> usize {
68        self.vertex_count()
69    }
70
71    fn relation_count(&self) -> usize {
72        self.hyperedge_count()
73    }
74}
75
76impl<V, R, I, O, VW, RW> IncidenceCounts for View<'_, V, R, I, O, VW, RW>
77where
78    V: BcsrIndex,
79    R: BcsrIndex,
80    I: BcsrIndex,
81    O: BcsrWord<Index = I>,
82    VW: BcsrWord<Index = V>,
83    RW: BcsrWord<Index = R>,
84{
85    fn incidence_count(&self) -> usize {
86        self.counts().total_incidences
87    }
88}
89
90impl<V, R, I, O, VW, RW> HypergraphCounts for View<'_, V, R, I, O, VW, RW>
91where
92    V: BcsrIndex,
93    R: BcsrIndex,
94    I: BcsrIndex,
95    O: BcsrWord<Index = I>,
96    VW: BcsrWord<Index = V>,
97    RW: BcsrWord<Index = R>,
98{
99}
100
101impl<V, R, I, O, VW, RW> ElementIndex for View<'_, V, R, I, O, VW, RW>
102where
103    V: BcsrIndex,
104    R: BcsrIndex,
105    I: BcsrIndex,
106    O: BcsrWord<Index = I>,
107    VW: BcsrWord<Index = V>,
108    RW: BcsrWord<Index = R>,
109{
110    fn element_bound(&self) -> usize {
111        self.vertex_count()
112    }
113
114    fn element_index(&self, element: BcsrVertexId<V>) -> usize {
115        index_to_usize_validated(element.0)
116    }
117}
118
119impl<V, R, I, O, VW, RW> RelationIndex for View<'_, V, R, I, O, VW, RW>
120where
121    V: BcsrIndex,
122    R: BcsrIndex,
123    I: BcsrIndex,
124    O: BcsrWord<Index = I>,
125    VW: BcsrWord<Index = V>,
126    RW: BcsrWord<Index = R>,
127{
128    fn relation_bound(&self) -> usize {
129        self.hyperedge_count()
130    }
131
132    fn relation_index(&self, relation: BcsrHyperedgeId<R>) -> usize {
133        index_to_usize_validated(relation.0)
134    }
135}
136
137impl<V, R, I, O, VW, RW> IncidenceIndex for View<'_, V, R, I, O, VW, RW>
138where
139    V: BcsrIndex,
140    R: BcsrIndex,
141    I: BcsrIndex,
142    O: BcsrWord<Index = I>,
143    VW: BcsrWord<Index = V>,
144    RW: BcsrWord<Index = R>,
145{
146    fn incidence_bound(&self) -> usize {
147        self.counts().total_incidences
148    }
149
150    fn incidence_index(&self, incidence: BcsrParticipantId<I>) -> usize {
151        index_to_usize_validated(incidence.0)
152    }
153}
154
155impl<V, R, I, O, VW, RW> ContainsElement for View<'_, V, R, I, O, VW, RW>
156where
157    V: BcsrIndex,
158    R: BcsrIndex,
159    I: BcsrIndex,
160    O: BcsrWord<Index = I>,
161    VW: BcsrWord<Index = V>,
162    RW: BcsrWord<Index = R>,
163{
164    fn contains_element(&self, element: BcsrVertexId<V>) -> bool {
165        index_to_usize_validated(element.0) < self.counts().vertex_count
166    }
167}
168
169impl<V, R, I, O, VW, RW> ContainsRelation for View<'_, V, R, I, O, VW, RW>
170where
171    V: BcsrIndex,
172    R: BcsrIndex,
173    I: BcsrIndex,
174    O: BcsrWord<Index = I>,
175    VW: BcsrWord<Index = V>,
176    RW: BcsrWord<Index = R>,
177{
178    fn contains_relation(&self, relation: BcsrHyperedgeId<R>) -> bool {
179        index_to_usize_validated(relation.0) < self.counts().hyperedge_count
180    }
181}
182
183impl<V, R, I, O, VW, RW> ContainsIncidence for View<'_, V, R, I, O, VW, RW>
184where
185    V: BcsrIndex,
186    R: BcsrIndex,
187    I: BcsrIndex,
188    O: BcsrWord<Index = I>,
189    VW: BcsrWord<Index = V>,
190    RW: BcsrWord<Index = R>,
191{
192    fn contains_incidence(&self, incidence: BcsrParticipantId<I>) -> bool {
193        index_to_usize_validated(incidence.0) < self.counts().total_incidences
194    }
195}
196
197impl<V, R, I, O, VW, RW> IncidenceElement for View<'_, V, R, I, O, VW, RW>
198where
199    V: BcsrIndex,
200    R: BcsrIndex,
201    I: BcsrIndex,
202    O: BcsrWord<Index = I>,
203    VW: BcsrWord<Index = V>,
204    RW: BcsrWord<Index = R>,
205{
206    fn incidence_element(&self, incidence: BcsrParticipantId<I>) -> BcsrVertexId<V> {
207        let incidence_index = index_to_usize_validated(incidence.0);
208        let counts = self.counts();
209        let sections = self.sections();
210        if incidence_index < counts.p_outgoing {
211            BcsrVertexId(sections.head_participants[incidence_index].get())
212        } else {
213            let position = incidence_index - counts.p_outgoing;
214            BcsrVertexId(sections.tail_participants[position].get())
215        }
216    }
217}
218
219impl<V, R, I, O, VW, RW> IncidenceRelation for View<'_, V, R, I, O, VW, RW>
220where
221    V: BcsrIndex,
222    R: BcsrIndex,
223    I: BcsrIndex,
224    O: BcsrWord<Index = I>,
225    VW: BcsrWord<Index = V>,
226    RW: BcsrWord<Index = R>,
227{
228    fn incidence_relation(&self, incidence: BcsrParticipantId<I>) -> BcsrHyperedgeId<R> {
229        let incidence_index = index_to_usize_validated(incidence.0);
230        let counts = self.counts();
231        let sections = self.sections();
232        if incidence_index < counts.p_outgoing {
233            BcsrHyperedgeId(locate_owning_bucket(sections.head_offsets, incidence_index))
234        } else {
235            let position = incidence_index - counts.p_outgoing;
236            BcsrHyperedgeId(locate_owning_bucket(sections.tail_offsets, position))
237        }
238    }
239}
240
241impl<V, R, I, O, VW, RW> IncidenceRole for View<'_, V, R, I, O, VW, RW>
242where
243    V: BcsrIndex,
244    R: BcsrIndex,
245    I: BcsrIndex,
246    O: BcsrWord<Index = I>,
247    VW: BcsrWord<Index = V>,
248    RW: BcsrWord<Index = R>,
249{
250    fn incidence_role(&self, incidence: BcsrParticipantId<I>) -> BcsrRole {
251        if index_to_usize_validated(incidence.0) < self.counts().p_outgoing {
252            BcsrRole::Head
253        } else {
254            BcsrRole::Tail
255        }
256    }
257}
258
259impl<V, R, I, O, VW, RW> RelationIncidences for View<'_, V, R, I, O, VW, RW>
260where
261    V: BcsrIndex,
262    R: BcsrIndex,
263    I: BcsrIndex,
264    O: BcsrWord<Index = I>,
265    VW: BcsrWord<Index = V>,
266    RW: BcsrWord<Index = R>,
267{
268    type Incidences<'view>
269        = BcsrChainedRelationIncidences<I>
270    where
271        Self: 'view;
272
273    fn relation_incidences(&self, relation: BcsrHyperedgeId<R>) -> Self::Incidences<'_> {
274        let sections = self.sections();
275        let p_outgoing = self.counts().p_outgoing;
276        let h_index = index_to_usize_validated(relation.0);
277        let head_start = index_to_usize_validated(sections.head_offsets[h_index].get());
278        let head_end = index_to_usize_validated(sections.head_offsets[h_index + 1].get());
279        let tail_start = index_to_usize_validated(sections.tail_offsets[h_index].get());
280        let tail_end = index_to_usize_validated(sections.tail_offsets[h_index + 1].get());
281        BcsrParticipantSlice::new(head_start, head_end, 0)
282            .chain(BcsrParticipantSlice::new(tail_start, tail_end, p_outgoing))
283    }
284}
285
286impl<V, R, I, O, VW, RW> ElementIncidences for View<'_, V, R, I, O, VW, RW>
287where
288    V: BcsrIndex,
289    R: BcsrIndex,
290    I: BcsrIndex,
291    O: BcsrWord<Index = I>,
292    VW: BcsrWord<Index = V>,
293    RW: BcsrWord<Index = R>,
294{
295    type Incidences<'view>
296        = BcsrElementIncidences<'view, O, VW, RW>
297    where
298        Self: 'view;
299
300    fn element_incidences(&self, element: BcsrVertexId<V>) -> Self::Incidences<'_> {
301        let sections = self.sections();
302        let counts = self.counts();
303        let v_index = index_to_usize_validated(element.0);
304        let outgoing = vertex_bucket(
305            sections.vertex_outgoing_offsets,
306            sections.vertex_outgoing_hyperedges,
307            v_index,
308        );
309        let incoming = vertex_bucket(
310            sections.vertex_incoming_offsets,
311            sections.vertex_incoming_hyperedges,
312            v_index,
313        );
314        BcsrElementIncidences::new(v_index, counts.p_outgoing, outgoing, incoming, sections)
315    }
316}
317
318impl<V, R, I, O, VW, RW> RelationIncidenceCount for View<'_, V, R, I, O, VW, RW>
319where
320    V: BcsrIndex,
321    R: BcsrIndex,
322    I: BcsrIndex,
323    O: BcsrWord<Index = I>,
324    VW: BcsrWord<Index = V>,
325    RW: BcsrWord<Index = R>,
326{
327    fn relation_incidence_count(&self, relation: BcsrHyperedgeId<R>) -> usize {
328        let sections = self.sections();
329        let h_index = index_to_usize_validated(relation.0);
330        let head_size = index_to_usize_validated(sections.head_offsets[h_index + 1].get())
331            - index_to_usize_validated(sections.head_offsets[h_index].get());
332        let tail_size = index_to_usize_validated(sections.tail_offsets[h_index + 1].get())
333            - index_to_usize_validated(sections.tail_offsets[h_index].get());
334        head_size + tail_size
335    }
336}
337
338impl<V, R, I, O, VW, RW> ElementIncidenceCount for View<'_, V, R, I, O, VW, RW>
339where
340    V: BcsrIndex,
341    R: BcsrIndex,
342    I: BcsrIndex,
343    O: BcsrWord<Index = I>,
344    VW: BcsrWord<Index = V>,
345    RW: BcsrWord<Index = R>,
346{
347    fn element_incidence_count(&self, element: BcsrVertexId<V>) -> usize {
348        let sections = self.sections();
349        let v_index = index_to_usize_validated(element.0);
350        let out_size =
351            index_to_usize_validated(sections.vertex_outgoing_offsets[v_index + 1].get())
352                - index_to_usize_validated(sections.vertex_outgoing_offsets[v_index].get());
353        let in_size = index_to_usize_validated(sections.vertex_incoming_offsets[v_index + 1].get())
354            - index_to_usize_validated(sections.vertex_incoming_offsets[v_index].get());
355        out_size + in_size
356    }
357}
358
359impl<V, R, I, O, VW, RW> HyperedgeParticipantCount for View<'_, V, R, I, O, VW, RW>
360where
361    V: BcsrIndex,
362    R: BcsrIndex,
363    I: BcsrIndex,
364    O: BcsrWord<Index = I>,
365    VW: BcsrWord<Index = V>,
366    RW: BcsrWord<Index = R>,
367{
368    fn hyperedge_participant_count(&self, hyperedge: BcsrHyperedgeId<R>) -> usize {
369        self.relation_incidence_count(hyperedge)
370    }
371}
372
373impl<V, R, I, O, VW, RW> IncidentHyperedgeCount for View<'_, V, R, I, O, VW, RW>
374where
375    V: BcsrIndex,
376    R: BcsrIndex,
377    I: BcsrIndex,
378    O: BcsrWord<Index = I>,
379    VW: BcsrWord<Index = V>,
380    RW: BcsrWord<Index = R>,
381{
382    fn incident_hyperedge_count(&self, vertex: BcsrVertexId<V>) -> usize {
383        self.element_incidence_count(vertex)
384    }
385}
386
387impl<V, R, I, O, VW, RW> HyperedgeParticipants for View<'_, V, R, I, O, VW, RW>
388where
389    V: BcsrIndex,
390    R: BcsrIndex,
391    I: BcsrIndex,
392    O: BcsrWord<Index = I>,
393    VW: BcsrWord<Index = V>,
394    RW: BcsrWord<Index = R>,
395{
396    type Participants<'view>
397        = BcsrChainedParticipants<'view, VW>
398    where
399        Self: 'view;
400
401    fn hyperedge_participants(&self, hyperedge: BcsrHyperedgeId<R>) -> Self::Participants<'_> {
402        let sections = self.sections();
403        let h_index = index_to_usize_validated(hyperedge.0);
404        let head = vertex_bucket(sections.head_offsets, sections.head_participants, h_index);
405        let tail = vertex_bucket(sections.tail_offsets, sections.tail_participants, h_index);
406        BcsrVertexSlice::new(head).chain(BcsrVertexSlice::new(tail))
407    }
408}
409
410impl<V, R, I, O, VW, RW> IncidentHyperedges for View<'_, V, R, I, O, VW, RW>
411where
412    V: BcsrIndex,
413    R: BcsrIndex,
414    I: BcsrIndex,
415    O: BcsrWord<Index = I>,
416    VW: BcsrWord<Index = V>,
417    RW: BcsrWord<Index = R>,
418{
419    type IncidentHyperedges<'view>
420        = BcsrChainedHyperedges<'view, RW>
421    where
422        Self: 'view;
423
424    fn incident_hyperedges(&self, vertex: BcsrVertexId<V>) -> Self::IncidentHyperedges<'_> {
425        let sections = self.sections();
426        let v_index = index_to_usize_validated(vertex.0);
427        let outgoing = vertex_bucket(
428            sections.vertex_outgoing_offsets,
429            sections.vertex_outgoing_hyperedges,
430            v_index,
431        );
432        let incoming = vertex_bucket(
433            sections.vertex_incoming_offsets,
434            sections.vertex_incoming_hyperedges,
435            v_index,
436        );
437        BcsrHyperedgeSlice::new(outgoing).chain(BcsrHyperedgeSlice::new(incoming))
438    }
439}
440
441impl<V, R, I, O, VW, RW> DirectedHyperedgeParticipants for View<'_, V, R, I, O, VW, RW>
442where
443    V: BcsrIndex,
444    R: BcsrIndex,
445    I: BcsrIndex,
446    O: BcsrWord<Index = I>,
447    VW: BcsrWord<Index = V>,
448    RW: BcsrWord<Index = R>,
449{
450    type SourceParticipants<'view>
451        = BcsrVertexSlice<'view, VW>
452    where
453        Self: 'view;
454
455    type TargetParticipants<'view>
456        = BcsrVertexSlice<'view, VW>
457    where
458        Self: 'view;
459
460    fn source_participants(&self, hyperedge: BcsrHyperedgeId<R>) -> Self::SourceParticipants<'_> {
461        let sections = self.sections();
462        let h_index = index_to_usize_validated(hyperedge.0);
463        let head = vertex_bucket(sections.head_offsets, sections.head_participants, h_index);
464        BcsrVertexSlice::new(head)
465    }
466
467    fn target_participants(&self, hyperedge: BcsrHyperedgeId<R>) -> Self::TargetParticipants<'_> {
468        let sections = self.sections();
469        let h_index = index_to_usize_validated(hyperedge.0);
470        let tail = vertex_bucket(sections.tail_offsets, sections.tail_participants, h_index);
471        BcsrVertexSlice::new(tail)
472    }
473}
474
475impl<V, R, I, O, VW, RW> DirectedHyperedgeIncidences for View<'_, V, R, I, O, VW, RW>
476where
477    V: BcsrIndex,
478    R: BcsrIndex,
479    I: BcsrIndex,
480    O: BcsrWord<Index = I>,
481    VW: BcsrWord<Index = V>,
482    RW: BcsrWord<Index = R>,
483{
484    type SourceIncidences<'view>
485        = BcsrParticipantSlice<I>
486    where
487        Self: 'view;
488
489    type TargetIncidences<'view>
490        = BcsrParticipantSlice<I>
491    where
492        Self: 'view;
493
494    fn source_incidences(&self, hyperedge: BcsrHyperedgeId<R>) -> Self::SourceIncidences<'_> {
495        let sections = self.sections();
496        let h_index = index_to_usize_validated(hyperedge.0);
497        let head_start = index_to_usize_validated(sections.head_offsets[h_index].get());
498        let head_end = index_to_usize_validated(sections.head_offsets[h_index + 1].get());
499        BcsrParticipantSlice::new(head_start, head_end, 0)
500    }
501
502    fn target_incidences(&self, hyperedge: BcsrHyperedgeId<R>) -> Self::TargetIncidences<'_> {
503        let sections = self.sections();
504        let h_index = index_to_usize_validated(hyperedge.0);
505        let tail_start = index_to_usize_validated(sections.tail_offsets[h_index].get());
506        let tail_end = index_to_usize_validated(sections.tail_offsets[h_index + 1].get());
507        BcsrParticipantSlice::new(tail_start, tail_end, self.counts().p_outgoing)
508    }
509}
510
511impl<V, R, I, O, VW, RW> DirectedVertexHyperedges for View<'_, V, R, I, O, VW, RW>
512where
513    V: BcsrIndex,
514    R: BcsrIndex,
515    I: BcsrIndex,
516    O: BcsrWord<Index = I>,
517    VW: BcsrWord<Index = V>,
518    RW: BcsrWord<Index = R>,
519{
520    type OutgoingHyperedges<'view>
521        = BcsrHyperedgeSlice<'view, RW>
522    where
523        Self: 'view;
524
525    type IncomingHyperedges<'view>
526        = BcsrHyperedgeSlice<'view, RW>
527    where
528        Self: 'view;
529
530    fn outgoing_hyperedges(&self, vertex: BcsrVertexId<V>) -> Self::OutgoingHyperedges<'_> {
531        let sections = self.sections();
532        let v_index = index_to_usize_validated(vertex.0);
533        let outgoing = vertex_bucket(
534            sections.vertex_outgoing_offsets,
535            sections.vertex_outgoing_hyperedges,
536            v_index,
537        );
538        BcsrHyperedgeSlice::new(outgoing)
539    }
540
541    fn incoming_hyperedges(&self, vertex: BcsrVertexId<V>) -> Self::IncomingHyperedges<'_> {
542        let sections = self.sections();
543        let v_index = index_to_usize_validated(vertex.0);
544        let incoming = vertex_bucket(
545            sections.vertex_incoming_offsets,
546            sections.vertex_incoming_hyperedges,
547            v_index,
548        );
549        BcsrHyperedgeSlice::new(incoming)
550    }
551}
552
553impl<V, R, I, O, VW, RW> ElementSuccessors for View<'_, V, R, I, O, VW, RW>
554where
555    V: BcsrIndex,
556    R: BcsrIndex,
557    I: BcsrIndex,
558    O: BcsrWord<Index = I>,
559    VW: BcsrWord<Index = V>,
560    RW: BcsrWord<Index = R>,
561{
562    type Successors<'view>
563        = BcsrSuccessorVertices<'view, RW, O, VW>
564    where
565        Self: 'view;
566
567    fn element_successors(&self, vertex: BcsrVertexId<V>) -> Self::Successors<'_> {
568        let sections = self.sections();
569        let v_index = index_to_usize_validated(vertex.0);
570        let outgoing = vertex_bucket(
571            sections.vertex_outgoing_offsets,
572            sections.vertex_outgoing_hyperedges,
573            v_index,
574        );
575        BcsrSuccessorVertices::new(outgoing, sections.tail_offsets, sections.tail_participants)
576    }
577}
578
579impl<V, R, I, O, VW, RW> ElementPredecessors for View<'_, V, R, I, O, VW, RW>
580where
581    V: BcsrIndex,
582    R: BcsrIndex,
583    I: BcsrIndex,
584    O: BcsrWord<Index = I>,
585    VW: BcsrWord<Index = V>,
586    RW: BcsrWord<Index = R>,
587{
588    type Predecessors<'view>
589        = BcsrPredecessorVertices<'view, RW, O, VW>
590    where
591        Self: 'view;
592
593    fn element_predecessors(&self, vertex: BcsrVertexId<V>) -> Self::Predecessors<'_> {
594        let sections = self.sections();
595        let v_index = index_to_usize_validated(vertex.0);
596        let incoming = vertex_bucket(
597            sections.vertex_incoming_offsets,
598            sections.vertex_incoming_hyperedges,
599            v_index,
600        );
601        BcsrPredecessorVertices::new(incoming, sections.head_offsets, sections.head_participants)
602    }
603}
604
605/// Returns the slice `values[offsets[index].get()..offsets[index + 1].get()]`.
606fn vertex_bucket<'view, OffsetWord, ValueWord>(
607    offsets: &'view [OffsetWord],
608    values: &'view [ValueWord],
609    index: usize,
610) -> &'view [ValueWord]
611where
612    OffsetWord: BcsrWord,
613{
614    let start = index_to_usize_validated(offsets[index].get());
615    let end = index_to_usize_validated(offsets[index + 1].get());
616    &values[start..end]
617}
618
619/// Binary search over an offset array, returning the bucket index that owns
620/// absolute position `target`.
621fn locate_owning_bucket<OffsetWord, RelationIndex>(
622    offsets: &[OffsetWord],
623    target: usize,
624) -> RelationIndex
625where
626    OffsetWord: BcsrWord,
627    RelationIndex: BcsrIndex,
628{
629    let mut low = 0_usize;
630    let mut high = offsets.len() - 1;
631    while low + 1 < high {
632        let mid = low + (high - low) / 2;
633        if index_to_usize_validated(offsets[mid].get()) <= target {
634            low = mid;
635        } else {
636            high = mid;
637        }
638    }
639    usize_to_index_validated(low)
640}