absl::flat_hash_map — Swiss Table 기반 hash map
#한 줄 요약
absl::flat_hash_map은 Swiss Table 구조를 채택한 open-addressing hash map이다. std::unordered_map이 강제하는 노드 단위 할당과 chain-list 순회를 연속 메모리에 SIMD-friendly한 metadata로 대체해 lookup이 평균 2~3배 빠르다. 대신 모든 mutation에서 iterator·pointer가 무효화된다.
#동기
std::unordered_map의 표준 규약은 노드 기반이다. 각 (key, value) 쌍이 별도 heap node에 있고, bucket은 노드 포인터 chain을 들고 있다. 결과:
- lookup마다 두 번 이상의 cache miss — bucket 배열 → chain head → 노드 → 노드.
- key 비교 전 해시 비교가 별도 메모리 접근.
- erase가 stable iterator를 요구해 노드 풀링이 강제.
flat_hash_map은 표준 규약을 일부 깨고 cache 친화 설계를 택한다.
- 슬롯이 연속 배열에 직접 저장 (open addressing).
- 슬롯 위 16바이트 control byte 그룹이 해시 partial + *상태(empty/deleted/full)*를 들고 있어 SIMD로 한 번에 16개 슬롯을 스캔한다.
- erase가 iterator를 무효화함을 허용하는 대신 packing이 단순해진다.
Swiss Table 자체의 내부 구조는 Part 5-07 — Swiss Table internals에서 본다. 여기서는 사용 측면.
구조를 한눈에 보면 다음과 같다.
#API와 사용법
#include "absl/container/flat_hash_map.h"
absl::flat_hash_map<std::string, int> counts;counts["a"] = 1;counts.emplace("b", 2);
if (auto it = counts.find("a"); it != counts.end()) { LOG(INFO) << it->second;}
for (const auto& [k, v] : counts) { // ...}인터페이스는 std::unordered_map과 거의 동일하다. 마이그레이션은 보통 헤더 교체와 typedef 변경으로 끝난다.
// beforestd::unordered_map<K, V> m;// afterabsl::flat_hash_map<K, V> m;#내부 구현 — open addressing
flat_hash_map은 open addressing hash table이다. node chain 대신 flat 배열에 직접 slot을 둔다.
hash 충돌 시 다음 slot으로 probe해 빈 자리를 찾는다. cache locality는 좋지만 load factor가 높을수록 probe 길이가 늘어 rehash가 필요해진다. Swiss Table은 여기에 SIMD로 16-slot 그룹을 1 cmp로 검사하는 트릭을 더해 probe 비용을 상쇄한다 (Part 5-07).
#내부 구현 — heterogeneous lookup
표준은 C++20부터 일부 heterogeneous lookup을 지원하지만, flat_hash_map은 처음부터 강력하다.
absl::flat_hash_map<std::string, int> m;m["hello"] = 1;
// std::unordered_map: 임시 std::string 생성 후 lookupauto it = m.find(absl::string_view("hello")); // OK — no allocauto it2 = m.find("hello"); // OK — no allocHash와 Eq가 transparent하면(is_transparent typedef) string_view로 직접 lookup이 가능하다. Abseil은 absl::Hash/std::equal_to<>를 기본으로 transparent 처리한다.
#std::unordered_map 비교
| 항목 | std::unordered_map | absl::flat_hash_map |
|---|---|---|
| storage | 노드 chain | open addressing flat array |
| lookup cache miss | 2~3회 | 0~1회 |
| iterator/pointer 안정성 | insert/erase에 stable | rehash·erase에서 무효화 |
node_type (split) | C++17 지원 | 미지원 (node_hash_map 별도) |
| heterogeneous lookup | C++20 부분 | 처음부터 강력 |
| value 이동 비용 | 없음 (노드 재사용) | rehash 시 모든 value 이동 |
| 평균 lookup | baseline | ~2-3x 빠름 |
| 메모리 사용 | 노드 헤더 overhead | ctrl byte + slot |
#코드 리뷰 포인트
1. value 크기 vs flat 선택
flat_hash_map은 (key, value)가 직접 배열에 저장된다. value가 크면(>32B 정도) rehash 비용이 커진다. 큰 value는 node_hash_map 또는 flat_hash_map<K, std::unique_ptr<V>>를 고려한다.
// 회피 — value 64B + rehash 비용absl::flat_hash_map<int, BigStruct> m;
// Goodabsl::flat_hash_map<int, std::unique_ptr<BigStruct>> m;// 또는absl::node_hash_map<int, BigStruct> m;node_hash_map은 Part 5-03에서 본다.
2. pointer/iterator 보관 금지
auto* p = &m["key"]; // 위험m.insert({"other", 0}); // rehash 가능 — p danglingstd::unordered_map은 노드 안정성을 보장하지만 flat_hash_map은 아니다. value 주소를 보관해야 하면 node_hash_map 또는 value를 unique_ptr로.
3. reserve로 rehash 비용 절감
absl::flat_hash_map<int, int> m;m.reserve(expected_size); // 한 번에 alloc, 이후 rehash 없음for (...) m.emplace(...);reserve(n)은 load factor를 고려해 충분한 슬롯을 잡는다.
4. heterogeneous lookup 활용
absl::flat_hash_map<std::string, int> m;absl::string_view key = LookupKeyFromInput();auto it = m.find(key); // no alloc, no string copystd::unordered_map은 같은 코드에 임시 string alloc이 발생한다 (C++20 transparent 미지원 시).
#안티패턴
큰 value 직접 저장
absl::flat_hash_map<int, std::array<char, 4096>> m;// rehash가 일어나면 모든 4KB value를 이동// — std::move 가능이라도 cache 영향 큼value 크기가 클 때는 unique_ptr<V> 또는 node_hash_map.
const_iterator로 mutate 회피 시도
flat_hash_map은 iterator/const_iterator가 모두 같은 안정성을 가진다(둘 다 무효화). const_iterator를 들고 있어도 rehash 위험은 동일.
std::map처럼 사용
hash map은 순서 보장 없음이다. ordered traversal이 필요하면 absl::btree_map (Part 5-04).
#정리
flat_hash_map은 Swiss Table 기반 open-addressing.- 연속 메모리 + 16-slot SIMD 스캔으로 lookup 2~3배 빠르다.
- iterator/pointer가 rehash·erase에서 무효화된다.
- value가 크면
unique_ptr또는node_hash_map. - heterogeneous lookup이 처음부터 강력 —
string_view로 lookup 가능.
#다음 편
Part 5-02 — flat_hash_set에서 set 대응을 짧게 본다.
#관련 항목
Abseil Code Review · 28 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::node_hash_map — stable pointer가 필요할 때
Part 5-03: absl::node_hash_map — flat_hash_map의 노드 기반 변형, value pointer 안정성 보장, std::unordered_map 마이그레이션 경로.
같은 시리즈에서 이어 읽기
absl::flat_hash_set — set 버전 Swiss Table
Part 5-02: absl::flat_hash_set — flat_hash_map의 set 대응, value-as-key 구조, dedup/membership 워크로드 패턴.
같은 시리즈에서 이어 읽기
Abseil algorithm container 확장 — c_sort·c_find_if·c_count_if
absl::c_* algorithm wrapper — container 전체를 받아 begin/end 자동 처리, STL algorithm의 한 줄 boilerplate를 제거.
같은 시리즈에서 이어 읽기
이 글을 참조하는 글 (10)
- Abseil algorithm container 확장 — c_sort·c_find_if·c_count_if — Abseil Code Review
- Abseil 자주 보는 anti-pattern — Abseil Code Review
- Abseil Custom hashable 구현 — Abseil Code Review
- Abseil AbslHashValue 분석 — Abseil Code Review
- Abseil Swiss Table internals — control byte·SIMD probing — Abseil Code Review
- absl::FixedArray — 런타임 크기 stack 배열 — Abseil Code Review
- absl::btree_map — sorted·cache-friendly B-tree — Abseil Code Review
- absl::node_hash_map — stable pointer가 필요할 때 — Abseil Code Review
- absl::flat_hash_set — set 버전 Swiss Table — Abseil Code Review
- Abseil Escape — CEscape·HexEscape·Base64 — Abseil Code Review