absl::bits — popcount·countl_zero
#C++20 <bit>의 polyfill
C++20에서 <bit> 헤더가 들어왔다. std::popcount, std::countl_zero, std::countr_zero, std::bit_width 등. C++14/17 코드베이스에서는 쓸 수 없지만 Abseil이 동일 인터페이스를 미리 제공한다.
#include "absl/numeric/bits.h"
uint32_t x = 0b1011'0100;
int pop = absl::popcount(x); // 4 — 1 비트 개수int lz = absl::countl_zero(x); // 24int tz = absl::countr_zero(x); // 2int lo1 = absl::countl_one(x); // 0int tz1 = absl::countr_one(x); // 0int bw = absl::bit_width(x); // 8 — 표현에 필요한 비트 수bool p2 = absl::has_single_bit(x); // false (2의 거듭제곱이 아님)#표 — 함수 카탈로그
| 함수 | 의미 | 입력 0일 때 |
|---|---|---|
popcount(x) | 1 비트 개수 | 0 |
countl_zero(x) | 왼쪽(MSB) 0 개수 | N (모두 0) |
countr_zero(x) | 오른쪽(LSB) 0 개수 | N |
countl_one(x) | 왼쪽 1 개수 | 0 |
countr_one(x) | 오른쪽 1 개수 | 0 |
bit_width(x) | 비트 폭 (최상위 1의 위치 + 1) | 0 |
bit_ceil(x) | x 이상 최소 2의 거듭제곱 | 1 |
bit_floor(x) | x 이하 최대 2의 거듭제곱 | 0 |
has_single_bit(x) | x가 2의 거듭제곱? | false |
rotl(x, s) | 왼쪽 비트 회전 | 0 |
rotr(x, s) | 오른쪽 비트 회전 | 0 |
타입은 unsigned integer 한정(uint8_t/uint16_t/uint32_t/uint64_t). signed 입력은 컴파일 에러.
#실제 어디 쓰이나
#SwissTable의 SIMD 메타데이터
absl::flat_hash_map의 group 검색은 16바이트 메타에서 매칭 비트마스크를 만들고 countr_zero로 슬롯 인덱스를 뽑는다.
// 의사 코드 — 실제는 SIMD intrinsicuint16_t mask = MatchFingerprint(group, fingerprint);while (mask) { int idx = absl::countr_zero(mask); if (slots[idx].key == key) return slots[idx].value; mask &= mask - 1; // 가장 낮은 1 비트 끄기}#가변 길이 정수 인코딩
int BytesNeeded(uint64_t x) { if (x == 0) return 1; int bits = absl::bit_width(x); return (bits + 6) / 7; // 7비트씩 묶기 (varint)}#해시맵 capacity 계산
size_t NextPowerOfTwo(size_t n) { return absl::bit_ceil(n);}
size_t IndexMask(size_t capacity) { // capacity는 2의 거듭제곱 return capacity - 1;}#컴파일러 매핑
| 함수 | x86 BMI/POPCNT | ARM |
|---|---|---|
popcount | popcnt | cnt |
countl_zero | lzcnt | clz |
countr_zero | tzcnt / bsf | rbit + clz |
Abseil은 하드웨어 instruction이 있으면 그것을, 없으면 portable bit-twiddle로 fallback. 인라인 호출이 단일 instruction으로 컴파일되는 게 보통이다.
#회피 패턴
// 회피 — manual loopint Popcount(uint32_t x) { int c = 0; while (x) { c += x & 1; x >>= 1; } return c;}
// Good — hardware popcntint c = absl::popcount(x);// 회피 — branch로 가장 높은 비트 찾기int Log2(uint32_t x) { int r = 0; while (x >>= 1) ++r; return r;}
// Goodint r = absl::bit_width(x) - 1; // x == 0이면 -1, 호출 전 검사// 회피 — 2의 거듭제곱 검사bool IsPow2(uint32_t x) { return x && !(x & (x - 1)); }
// Goodbool p = absl::has_single_bit(x);#C++20 마이그레이션
Abseil 함수들은 std:: 짝과 1
// before#include "absl/numeric/bits.h"int c = absl::popcount(x);
// after#include <bit>int c = std::popcount(x);namespace absl = std; 같은 alias는 안 되지만 using std::popcount; 정도면 단일 함수 단위 마이그레이션이 가능하다.
#작은 예시 — Bit Set 순회
// uint64 비트마스크의 set 비트 인덱스를 모두 순회void ForEachSet(uint64_t mask, std::function<void(int)> f) { while (mask) { int idx = absl::countr_zero(mask); f(idx); mask &= mask - 1; // lowest set bit clear }}
ForEachSet(0b10101100, [](int i) { std::cout << i << "\n"; });// 2, 3, 5, 7이 패턴은 SwissTable group search, bitmap allocator, sparse vector 순회 등 어디서나 등장한다.
#정리
<bit>의 polyfill — C++14/17 코드베이스에서popcount·countl_zero등 사용 가능.- 입력은 unsigned 정수 한정. 0 입력 시 정의 명확(undefined behavior 없음).
- 하드웨어 popcnt/lzcnt가 있으면 그쪽으로 단일 instruction 컴파일.
bit_ceil/has_single_bit— capacity 계산, 2의 거듭제곱 체크.countr_zero+mask & (mask-1)패턴은 set bit 순회의 정석.
#다음 장 예고
Part 9-03: absl::optional — std::optional의 polyfill.
#관련 항목
Abseil Code Review · 50 of 79
- 1 Abseil Code Review — Google production-grade C++ 라이브러리 분석
- 2 Abseil 개요 — Google이 std를 보완한 이유
- 3 Abseil 설계 철학 — std 호환과 추가 기능의 균형
- 4 Abseil 빌드와 의존성 — Bazel vs CMake
- 5 Abseil LTS vs HEAD 릴리스 모델 분석
- 6 Abseil Versioning과 ABI 호환성 정책
- 7 Abseil 매크로 — ABSL_HAVE_*·ABSL_ATTRIBUTE_*
- 8 Abseil ABSL_PREDICT_TRUE/FALSE — branch hint
- 9 absl::LogSeverity — 로그 레벨 타입
- 10 Abseil type_traits — negation·conjunction·void_t
- 11 Abseil Conformance·Policy 분석
- 12 Abseil Memory utilities 분석
- 13 Abseil raw_logging — heap-free 로깅
- 14 Abseil thread_annotations — clang TSA 통합
- 15 absl::Status — exception-free error handling
- 16 absl::StatusOr<T> — 값 또는 에러
- 17 absl status_macros — ASSIGN_OR_RETURN·RETURN_IF_ERROR
- 18 absl::Status payload — 구조화된 에러 컨텍스트
- 19 absl::Status ↔ exception 변환 패턴
- 20 absl::string_view — non-owning 문자열 참조
- 21 absl::string_view 함정 — dangling·c_str·임시 객체
- 22 absl::StrCat — 가변 인자 문자열 연결과 AlphaNum
- 23 absl::StrSplit — Delimiter·Predicate·컨테이너 변환
- 24 absl::StrJoin — 컨테이너 결합과 Formatter
- 25 absl::StrFormat — type-safe printf·FormatSpec
- 26 Abseil ASCII 함수 — locale-free 분류·대소문자 변환
- 27 Abseil Escape — CEscape·HexEscape·Base64
- 28 absl::flat_hash_map — Swiss Table 기반 hash map
- 29 absl::flat_hash_set — set 버전 Swiss Table
- 30 absl::node_hash_map — stable pointer가 필요할 때
- 31 absl::btree_map — sorted·cache-friendly B-tree
- 32 absl::FixedArray — 런타임 크기 stack 배열
- 33 absl::InlinedVector — small buffer optimization
- 34 Abseil Swiss Table internals — control byte·SIMD probing
- 35 absl::Mutex — reader-writer·fairness·deadlock 검출
- 36 absl::Mutex Conditional Critical Section — Await로 cv 없애기
- 37 absl::Notification — once-only signal
- 38 absl::BlockingCounter·Barrier — 다중 thread 조율
- 39 absl::Mutex annotations — clang thread-safety로 race를 컴파일 타임에
- 40 absl::Time·Duration 분석 — 단단한 type
- 41 absl::Time Format·Parse
- 42 absl::CivilTime 분석
- 43 absl::time_zone 분석
- 44 absl::Time mocking — 테스트 친화 시간
- 45 absl::BitGen — 모던 난수 생성기
- 46 Abseil Random Distributions — Uniform·Exponential
- 47 Abseil Mocking Random — 테스트 결정성
- 48 Abseil Random Seeding·Entropy
- 49 absl::int128·uint128 분석
- 50 absl::bits — popcount·countl_zero
- 51 absl::optional vs std::optional
- 52 absl::variant 분석
- 53 absl::span 분석
- 54 absl::any 분석
- 55 absl::compare — three-way 비교
- 56 Abseil utility — apply·in_place
- 57 Abseil AbslHashValue 분석
- 58 Abseil HashState chaining
- 59 Abseil Custom hashable 구현
- 60 Abseil LOG·VLOG·CHECK 분석
- 61 Abseil LogSink 분석
- 62 Abseil LogEntry·structured logging
- 63 Abseil Stack trace·failure_signal_handler
- 64 ABSL_FLAG 정의 분석
- 65 Abseil ParseCommandLine 동작
- 66 Abseil Flag introspection·validation
- 67 Google 스타일의 Abseil 사용 패턴
- 68 Abseil 자주 보는 anti-pattern
- 69 std → absl 마이그레이션 전략
- 70 absl::Cleanup — 함수 종료 시 실행 보장
- 71 Abseil algorithm container 확장 — c_sort·c_find_if·c_count_if
- 72 absl::function_ref와 any_invocable — 함수 객체 전달의 두 축
- 73 absl::bind_front와 Overload — 함수 객체 보조 도구
- 74 absl::Cord — 분산 시스템용 대용량 문자열
- 75 absl::from_chars·SimpleAtoi — 빠른 숫자 변환
- 76 absl::Cord vs std::string — 선택 기준과 메모리 프로파일
- 77 absl::GetStackTrace와 Symbolize — crash 시 readable stack
- 78 absl::ComputeCrc32c — 하드웨어 가속 체크섬
- 79 absl::PeriodicSampler — 적응형 샘플링·jitter 회피
관련 글
absl::int128·uint128 분석
absl::int128, uint128 — 64비트로 부족한 곳을 메우는 128비트 정수. 컴파일러 builtin과 emulation 양쪽을 가린 ABI.
같은 시리즈에서 이어 읽기
absl::PeriodicSampler — 적응형 샘플링·jitter 회피
absl::profiling_internal::PeriodicSampler — sampling rate를 동적으로 조정, geometric distribution으로 jitter 회피. 메모리 할당 추적·profiling 인프라의 기반.
같은 시리즈에서 이어 읽기
absl::ComputeCrc32c — 하드웨어 가속 체크섬
absl::ComputeCrc32c — SSE4.2 CRC32, ARM CRC 명령어로 가속된 CRC32C 구현. iSCSI·Btrfs·protobuf에서 표준화된 무결성 검사.
같은 시리즈에서 이어 읽기