天天看点

vpp之clib.h分析

vpp代码中有一个clib.h,其中封装了很一些很经典的位运算:

1 //计算以2为底的对数,log2(x)
  2 //也就是计算2的N次方为x。x为uint32类型
  3 #if defined (count_leading_zeros)
  4 always_inline uword
  5 min_log2 (uword x)
  6 {
  7     uword n;
  8     n = count_leading_zeros (x);
  9     return BITS (uword) - n - 1;
 10 }
 11 #else
 12 always_inline uword
 13 min_log2 (uword x)
 14 {
 15     uword a = x, b = BITS (uword) / 2, c = 0, r = 0;
 16 
 17     /* Reduce x to 4 bit result. */
 18 #define _                   \
 19     {                       \
 20       c = a >> b;                   \
 21       if (c) a = c;                 \
 22       if (c) r += b;                \
 23       b /= 2;                   \
 24     }
 25 
 26     if (BITS (uword) > 32)
 27         _;
 28     _;
 29     _;
 30     _;
 31 #undef _
 32 
 33     /* Do table lookup on 4 bit partial. */
 34     if (BITS (uword) > 32)
 35     {
 36         const u64 table = 0x3333333322221104LL;
 37         uword t = (table >> (4 * a)) & 0xf;
 38         r = t < 4 ? r + t : ~0;
 39     }
 40     else
 41     {
 42         const u32 table = 0x22221104;
 43         uword t = (a & 8) ? 3 : ((table >> (4 * a)) & 0xf);
 44         r = t < 4 ? r + t : ~0;
 45     }
 46 
 47     return r;
 48 }
 49 #endif
 50 
 51 //计算以2为底的对数(有余数的话+1),log2(x)
 52 //也就是计算2的N次方为x。2的N次方大于x
 53 always_inline uword
 54 max_log2 (uword x)
 55 {
 56     uword l = min_log2 (x);
 57     if (x > ((uword) 1 << l))
 58         l++;
 59     return l;
 60 }
 61 
 62 //计算以2为底的对数,log2(x)
 63 //也就是计算2的N次方为x。x为u64类型
 64 always_inline u64
 65 min_log2_u64 (u64 x)
 66 {
 67     if (BITS (uword) == 64)
 68         return min_log2 (x);
 69     else
 70     {
 71         uword l, y;
 72         y = x;
 73         l = 0;
 74         if (y == 0)
 75         {
 76             l += 32;
 77             x >>= 32;
 78         }
 79         l += min_log2 (x);
 80         return l;
 81     }
 82 }
 83 
 84 //计算基数2的x次幂的值对应的掩码
 85 //比如2的4次幂为16,对应的掩码为15
 86 always_inline uword
 87 pow2_mask (uword x)
 88 {
 89     return ((uword) 1 << x) - (uword) 1;
 90 }
 91 
 92 //计算数字x对应的,以基数2的n次幂的值。x小于等于n
 93 //比如x=15,则得出的数字为16.2的3次幂小于x,2的4次幂大于x。
 94 always_inline uword
 95 max_pow2 (uword x)
 96 {
 97     word y = (word) 1 << min_log2 (x);
 98     if (x > y)
 99         y *= 2;
100     return y;
101 }
102 
103 //计算x是否可等于基数2的n次幂
104 //比如x=16,返回1.x=15,返回0
105 always_inline uword
106 is_pow2 (uword x)
107 {
108     return 0 == (x & (x - 1));
109 }
110 
111 //计算x以pow2对齐的长度。pow2应该为2的n次方。
112 //如x=15,pow2=4,则返回16。
113 always_inline uword
114 round_pow2 (uword x, uword pow2)
115 {
116     return (x + pow2 - 1) & ~(pow2 - 1);
117 }
118 
119 //计算x以pow2对齐的长度。pow2应该为2的n次方。
120 //如x=15,pow2=4,则返回16。
121 always_inline u64
122 round_pow2_u64 (u64 x, u64 pow2)
123 {
124     return (x + pow2 - 1) & ~(pow2 - 1);
125 }
126 
127 //保留二进制下最后出现的1的位置,其余位置置0(即一个数中最大的2的n次幂的因数
128 //当一个偶数与它的负值向与时,结果是能被这个偶数整除的最大的2的n次幂
129 //当一个奇数与它的负值向与时结果一定是1
130 always_inline uword
131 first_set (uword x)
132 {
133     return x & -x;
134 }
135 
136 //先将x用first_set计算结果,
137 //然后以2为底做对数运算
138 always_inline uword
139 log2_first_set (uword x)
140 {
141     uword result;
142 #ifdef count_trailing_zeros
143     result = count_trailing_zeros (x);
144 #else
145     result = min_log2 (first_set (x));
146 #endif
147     return result;
148 }
149 
150 //将浮点数强转为整型(小数部分舍去)
151 always_inline f64
152 flt_round_down (f64 x)
153 {
154     return (int) x;
155 }
156 
157 //将浮点数强转为整型(小数部分四舍五入)
158 always_inline word
159 flt_round_nearest (f64 x)
160 {
161     return (word) (x + .5);
162 }
163 
164 //若x大于f的一半,则返回f,否则返回0
165 always_inline f64
166 flt_round_to_multiple (f64 x, f64 f)
167 {
168     return f * flt_round_nearest (x / f);
169 }
170 
171 //计算x右移start位后,再截取count位有效数字是多少
172 always_inline uword
173 extract_bits (uword x, int start, int count)
174 {
175 #ifdef __BMI__
176     return _bextr_u64 (x, start, count);
177 #endif
178     return (x >> start) & pow2_mask (count);
179 }
180 
181 //取x和y两个数中大的数
182 #define clib_max(x,y)               \
183 ({                      \
184   __typeof__ (x) _x = (x);          \
185   __typeof__ (y) _y = (y);          \
186   _x > _y ? _x : _y;                \
187 })
188 
189 //取x和y两个数中较小的数
190 #define clib_min(x,y)               \
191 ({                      \
192   __typeof__ (x) _x = (x);          \
193   __typeof__ (y) _y = (y);          \
194   _x < _y ? _x : _y;                \
195 })
196 
197 //取x和y两个数中较大的数
198 #define clib_max(x,y)               \
199 ({                      \
200   __typeof__ (x) _x = (x);          \
201   __typeof__ (y) _y = (y);          \
202   _x > _y ? _x : _y;                \
203 })
204 
205 
206 //取x的绝对值
207 //定义类型与x相同的临时变量_x,并将x的值赋予_x
208 //取绝对值 
209 #define clib_abs(x)             \
210 ({                      \
211   __typeof__ (x) _x = (x);         \
212   _x < 0 ? -_x : _x;                \
213 })