LCOV - code coverage report
Current view: top level - vppinfra - sparse_vec.h (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 69 74 93.2 %
Date: 2023-07-05 22:20:52 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2015 Cisco and/or its affiliates.
       3             :  * Licensed under the Apache License, Version 2.0 (the "License");
       4             :  * you may not use this file except in compliance with the License.
       5             :  * You may obtain a copy of the License at:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       9             :  * Unless required by applicable law or agreed to in writing, software
      10             :  * distributed under the License is distributed on an "AS IS" BASIS,
      11             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             :  * See the License for the specific language governing permissions and
      13             :  * limitations under the License.
      14             :  */
      15             : /*
      16             :   Copyright (c) 2005 Eliot Dresselhaus
      17             : 
      18             :   Permission is hereby granted, free of charge, to any person obtaining
      19             :   a copy of this software and associated documentation files (the
      20             :   "Software"), to deal in the Software without restriction, including
      21             :   without limitation the rights to use, copy, modify, merge, publish,
      22             :   distribute, sublicense, and/or sell copies of the Software, and to
      23             :   permit persons to whom the Software is furnished to do so, subject to
      24             :   the following conditions:
      25             : 
      26             :   The above copyright notice and this permission notice shall be
      27             :   included in all copies or substantial portions of the Software.
      28             : 
      29             :   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
      30             :   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
      31             :   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
      32             :   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
      33             :   LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
      34             :   OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
      35             :   WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
      36             : */
      37             : 
      38             : #ifndef included_sparse_vec_h
      39             : #define included_sparse_vec_h
      40             : 
      41             : #include <vppinfra/clib.h>
      42             : #include <vppinfra/vec.h>
      43             : 
      44             : /* Sparsely indexed vectors.  Basic idea taken from Hacker's delight.
      45             :    Eliot added ranges. */
      46             : typedef struct
      47             : {
      48             :   /* Bitmap one for each sparse index. */
      49             :   uword *is_member_bitmap;
      50             : 
      51             :   /* member_counts[i] = total number of members with j < i. */
      52             :   u16 *member_counts;
      53             : 
      54             : #define SPARSE_VEC_IS_RANGE (1 << 0)
      55             : #define SPARSE_VEC_IS_VALID_RANGE (1 << 1)
      56             :   u8 *range_flags;
      57             : } sparse_vec_header_t;
      58             : 
      59             : always_inline sparse_vec_header_t *
      60     7679204 : sparse_vec_header (void *v)
      61             : {
      62     7679204 :   return vec_header (v);
      63             : }
      64             : 
      65             : /* Index 0 is always used to mark indices that are not valid in
      66             :    sparse vector.  For example, you look up V[0x1234] and 0x1234 is not
      67             :    known you'll get 0 back as an index. */
      68             : #define SPARSE_VEC_INVALID_INDEX (0)
      69             : 
      70             : always_inline void *
      71        4695 : sparse_vec_new (uword elt_bytes, uword sparse_index_bits)
      72             : {
      73             :   void *v;
      74             :   sparse_vec_header_t *h;
      75             :   word n;
      76        4695 :   vec_attr_t va = { .elt_sz = elt_bytes, .hdr_sz = sizeof (h[0]) };
      77             : 
      78        4695 :   ASSERT (sparse_index_bits <= 16);
      79             : 
      80        4695 :   v = _vec_alloc_internal (/* data bytes */ 8, &va);
      81             : 
      82             :   /* Make space for invalid entry (entry 0). */
      83        4692 :   _vec_set_len (v, 1, elt_bytes);
      84             : 
      85        4694 :   h = sparse_vec_header (v);
      86             : 
      87        4694 :   n = sparse_index_bits - min_log2 (BITS (uword));
      88        4695 :   if (n < 0)
      89           0 :     n = 0;
      90        4695 :   n = 1ULL << n;
      91        4695 :   vec_resize (h->is_member_bitmap, n);
      92        4695 :   vec_resize (h->member_counts, n);
      93             : 
      94        4695 :   return v;
      95             : }
      96             : 
      97             : always_inline uword
      98     7578357 : sparse_vec_index_internal (void *v,
      99             :                            uword sparse_index,
     100             :                            uword maybe_range, u32 * insert)
     101             : {
     102             :   sparse_vec_header_t *h;
     103             :   uword i, b, d, w;
     104             :   u8 is_member;
     105             : 
     106     7578357 :   h = sparse_vec_header (v);
     107     7578357 :   i = sparse_index / BITS (h->is_member_bitmap[0]);
     108     7578357 :   b = sparse_index % BITS (h->is_member_bitmap[0]);
     109             : 
     110     7578357 :   ASSERT (i < vec_len (h->is_member_bitmap));
     111     7578357 :   ASSERT (i < vec_len (h->member_counts));
     112             : 
     113     7578357 :   w = h->is_member_bitmap[i];
     114             : 
     115             :   /* count_trailing_zeros(0) == 0, take care of that case */
     116     7578357 :   if (PREDICT_FALSE (maybe_range == 0 && insert == 0 && w == 0))
     117     6487784 :     return 0;
     118             : 
     119     1090573 :   if (PREDICT_TRUE (maybe_range == 0 && insert == 0 &&
     120             :                     count_trailing_zeros (w) == b))
     121       20766 :     return h->member_counts[i] + 1;
     122             : 
     123     1069806 :   d = h->member_counts[i] + count_set_bits (w & ((1ULL << b) - 1));
     124     1069806 :   is_member = (w & (1ULL << b)) != 0;
     125             : 
     126     1069806 :   if (maybe_range)
     127             :     {
     128           0 :       u8 r = h->range_flags[d];
     129             :       u8 is_range, is_valid_range;
     130             : 
     131           0 :       is_range = maybe_range & (r & SPARSE_VEC_IS_RANGE);
     132           0 :       is_valid_range = (r & SPARSE_VEC_IS_VALID_RANGE) != 0;
     133             : 
     134           0 :       is_member = is_range ? is_valid_range : is_member;
     135             :     }
     136             : 
     137     1069806 :   if (insert)
     138             :     {
     139       18800 :       *insert = !is_member;
     140       18800 :       if (!is_member)
     141             :         {
     142             :           uword j;
     143       17613 :           w |= 1ULL << b;
     144       17613 :           h->is_member_bitmap[i] = w;
     145    10938737 :           for (j = i + 1; j < vec_len (h->member_counts); j++)
     146    10921118 :             h->member_counts[j] += 1;
     147             :         }
     148             : 
     149       18800 :       return 1 + d;
     150             :     }
     151             : 
     152     1051006 :   d = is_member ? d : 0;
     153             : 
     154     1051006 :   return is_member + d;
     155             : }
     156             : 
     157             : always_inline uword
     158     7559557 : sparse_vec_index (void *v, uword sparse_index)
     159             : {
     160     7559557 :   return sparse_vec_index_internal (v, sparse_index,
     161             :                                     /* maybe range */ 0,
     162             :                                     /* insert? */ 0);
     163             : }
     164             : 
     165             : always_inline void
     166       95927 : sparse_vec_index2 (void *v,
     167             :                    u32 si0, u32 si1, u32 * i0_return, u32 * i1_return)
     168             : {
     169             :   sparse_vec_header_t *h;
     170             :   uword b0, b1, w0, w1, v0, v1;
     171             :   u32 i0, i1, d0, d1;
     172             :   u8 is_member0, is_member1;
     173             : 
     174       95927 :   h = sparse_vec_header (v);
     175             : 
     176       95927 :   i0 = si0 / BITS (h->is_member_bitmap[0]);
     177       95927 :   i1 = si1 / BITS (h->is_member_bitmap[0]);
     178             : 
     179       95927 :   b0 = si0 % BITS (h->is_member_bitmap[0]);
     180       95927 :   b1 = si1 % BITS (h->is_member_bitmap[0]);
     181             : 
     182       95927 :   ASSERT (i0 < vec_len (h->is_member_bitmap));
     183       95927 :   ASSERT (i1 < vec_len (h->is_member_bitmap));
     184             : 
     185       95927 :   ASSERT (i0 < vec_len (h->member_counts));
     186       95927 :   ASSERT (i1 < vec_len (h->member_counts));
     187             : 
     188       95927 :   w0 = h->is_member_bitmap[i0];
     189       95927 :   w1 = h->is_member_bitmap[i1];
     190             : 
     191       95927 :   if (PREDICT_TRUE ((count_trailing_zeros (w0) == b0) +
     192             :                     (count_trailing_zeros (w1) == b1) == 2))
     193             :     {
     194        8525 :       *i0_return = h->member_counts[i0] + 1;
     195        8525 :       *i1_return = h->member_counts[i1] + 1;
     196        8525 :       return;
     197             :     }
     198             : 
     199       87402 :   v0 = w0 & ((1ULL << b0) - 1);
     200       87402 :   v1 = w1 & ((1ULL << b1) - 1);
     201             : 
     202             :   /* Speculate that masks will have zero or one bits set. */
     203       87402 :   d0 = h->member_counts[i0] + (v0 != 0);
     204       87402 :   d1 = h->member_counts[i1] + (v1 != 0);
     205             : 
     206             :   /* Validate speculation. */
     207       87402 :   if (PREDICT_FALSE (!is_pow2 (v0) || !is_pow2 (v1)))
     208             :     {
     209       21817 :       d0 += count_set_bits (v0) - (v0 != 0);
     210       21817 :       d1 += count_set_bits (v1) - (v1 != 0);
     211             :     }
     212             : 
     213       87402 :   is_member0 = (w0 & (1ULL << b0)) != 0;
     214       87402 :   is_member1 = (w1 & (1ULL << b1)) != 0;
     215             : 
     216       87402 :   d0 = is_member0 ? d0 : 0;
     217       87402 :   d1 = is_member1 ? d1 : 0;
     218             : 
     219       87402 :   *i0_return = is_member0 + d0;
     220       87402 :   *i1_return = is_member1 + d1;
     221             : }
     222             : 
     223             : #define sparse_vec_free(V)                                                    \
     224             :   do                                                                          \
     225             :     {                                                                         \
     226             :       if (V)                                                                  \
     227             :         {                                                                     \
     228             :           sparse_vec_header_t *_h = sparse_vec_header (V);                    \
     229             :           vec_free (_h->is_member_bitmap);                                    \
     230             :           vec_free (_h->member_counts);                                       \
     231             :           clib_mem_free (_h);                                                 \
     232             :           V = 0;                                                              \
     233             :         }                                                                     \
     234             :     }                                                                         \
     235             :   while (0)
     236             : 
     237             : #define sparse_vec_elt_at_index(v,i) \
     238             :   vec_elt_at_index ((v), sparse_vec_index ((v), (i)))
     239             : 
     240             : #define sparse_vec_validate(v,i)                                        \
     241             : ({                                                                      \
     242             :   uword _i;                                                             \
     243             :   u32 _insert;                                                          \
     244             :                                                                         \
     245             :   if (! (v))                                                            \
     246             :     (v) = sparse_vec_new (sizeof ((v)[0]), BITS (u16));                 \
     247             :                                                                         \
     248             :   _i = sparse_vec_index_internal ((v), (i),                             \
     249             :                                   /* maybe range */ 0,                  \
     250             :                                   /* insert? */ &_insert);          \
     251             :   if (_insert)                                                          \
     252             :     vec_insert_ha ((v), 1, _i,                                          \
     253             :                    /* header size */ sizeof (sparse_vec_header_t),      \
     254             :                    /* align */ 0);                                      \
     255             :                                                                         \
     256             :   /* Invalid index is 0. */                                             \
     257             :   ASSERT (_i > 0);                                                   \
     258             :                                                                         \
     259             :   (v) + _i;                                                             \
     260             : })
     261             : 
     262             : #endif /* included_sparse_vec_h */
     263             : 
     264             : /*
     265             :  * fd.io coding-style-patch-verification: ON
     266             :  *
     267             :  * Local Variables:
     268             :  * eval: (c-set-style "gnu")
     269             :  * End:
     270             :  */

Generated by: LCOV version 1.14