游雁
2024-02-19 94de39dde2e616a01683c518023d0fab72b4e103
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// See www.openfst.org for extensive documentation on this weighted
// finite-state transducer library.
 
#ifndef FST_EXTENSIONS_NGRAM_NTHBIT_H_
#define FST_EXTENSIONS_NGRAM_NTHBIT_H_
 
#include <fst/types.h>
#include <fst/compat.h>
 
#ifdef __BMI2__
// PDEP requires BMI2.
 
// Returns the position (0-63) of the r-th 1 bit in v.
// 1 <= r <= CountOnes(v) <= 64.  Therefore, v must not be 0.
inline uint32 nth_bit(uint64 v, uint32 r) {
  // PDEP example from https://stackoverflow.com/a/27453505
  return __builtin_ctzll(_pdep_u64(uint64{1} << (r - 1), v));
}
 
#else  // !defined(__BMI2__)
 
extern const uint32 nth_bit_bit_offset[];
 
// Returns the position (0-63) of the r-th 1 bit in v.
// 1 <= r <= CountOnes(v) <= 64.  Therefore, v must not be 0.
inline uint32 nth_bit(uint64 v, uint32 r) {
  uint32 shift = 0;
  uint32 c = __builtin_popcount(v & 0xffffffff);
  uint32 mask = -(r > c);
  r -= c & mask;
  shift += (32 & mask);
 
  c = __builtin_popcount((v >> shift) & 0xffff);
  mask = -(r > c);
  r -= c & mask;
  shift += (16 & mask);
 
  c = __builtin_popcount((v >> shift) & 0xff);
  mask = -(r > c);
  r -= c & mask;
  shift += (8 & mask);
 
  return shift +
         ((nth_bit_bit_offset[(v >> shift) & 0xff] >> ((r - 1) << 2)) & 0xf);
}
 
#endif  // !defined(__BMI2__)
 
#endif  // FST_EXTENSIONS_NGRAM_NTHBIT_H_