folly::F14FastMap — auto-select 동작
#한 줄 요약
F14FastMap은 sizeof(pair<K,V>)를 보고 컴파일 타임에 F14ValueMap(작은 value) 또는 F14VectorMap(큰 value)으로 alias 된다. 사용자가 trade-off를 고민하지 않아도 적절한 변형을 얻는다.
#동기
세 가지 변형(Value/Node/Vector)이 있으면 매번 무엇을 쓸지 결정해야 한다. 대부분의 코드는 굳이 차이를 고민할 필요가 없다 — 대충 빠르면 된다.
- value가 작으면 chunk inline이 cache-friendly → ValueMap.
- value가 크면 chunk slot에 큰 객체가 들어가면 메모리 낭비 → VectorMap.
이 결정을 컴파일러가 한다. sizeof(Item)이 임계치(48 byte) 이하면 ValueMap, 초과면 VectorMap.
folly::F14FastMap<int, int> // → ValueMap (sizeof(pair) = 8)folly::F14FastMap<std::string, BigObj> // → VectorMap (sizeof(pair) > 48)#API & 사용법
API는 ValueMap과 동일하다. 단, 어느 variant로 alias 되었느냐에 따라 세부 동작이 다르다.
#include <folly/container/F14Map.h>
folly::F14FastMap<int, std::string> small;// VectorMap으로 dispatch (pair<int, string> = 40 bytes... 임계치 부근)
folly::F14FastMap<int, int> tiny;// ValueMap (8 bytes)
folly::F14FastMap<std::string, std::array<char, 256>> big;// VectorMap
// 모두 같은 인터페이스small.emplace(1, "a");small.find(1);for (auto& [k, v] : small) { ... }VectorMap이 선택된 경우 insertion order가 유지된다. ValueMap이면 순서 없다. 코드가 양쪽을 모두 동작해야 하면 순서를 가정하면 안 된다.
#내부 구현
#간단한 type dispatch
// 약식 — folly/container/F14Map.hnamespace detail { constexpr size_t kF14VectorMapThreshold = 24;
template <typename K, typename V> using FastSelect = std::conditional_t< (sizeof(std::pair<K, V>) <= kF14VectorMapThreshold) && folly::IsRelocatable<std::pair<K, V>>::value, F14ValueMap<K, V>, F14VectorMap<K, V>>;}
template <typename K, typename V>using F14FastMap = detail::FastSelect<K, V>;(정확한 임계치와 trait는 folly 버전마다 다르다. core idea는 단순 if constexpr.)
조건:
sizeof(pair)≤ 임계치 (작은 value).is_trivially_relocatable(rehash move 안전).
둘 다 만족하면 ValueMap, 아니면 VectorMap.
#Trivially relocatable
folly는 자체 trait IsRelocatable을 가진다. std::pair, primitive, POD는 자동으로 relocatable. 사용자 타입은 다음과 같이 표시.
struct Big { std::array<char, 64> buf;};namespace folly { template <> struct IsRelocatable<Big> : std::true_type {}; }relocatable이면 rehash 시 byte-wise memmove로 옮길 수 있어 ValueMap이 안전하다. 아니면 VectorMap이 선택돼 옮길 일이 적다.
#사용 결정 — 언제 FastMap
F14FastMap을 쓰는 경우:
- 정책을 정하기 번거롭고 그냥 빠른 것이면 된다.
- workload가 lookup-heavy도, iteration-heavy도 명확하지 않다.
- team 코드 베이스에서 일관성을 원한다.
명시적 선택을 쓰는 경우:
- lookup만 한다면
F14ValueMap. - 순회/snapshot이 잦다면
F14VectorMap. - pointer 안정성이 필요하면
F14NodeMap. - 큰 value이고 erase가 잦다면
F14NodeMap(VectorMap의 swap-pop 회피).
대부분 새 코드는 F14FastMap이 default.
#std/abseil 비교
abseil에는 자동 선택이 없다. flat_hash_map 또는 node_hash_map을 사용자가 명시.
| 항목 | abseil | folly |
|---|---|---|
| 자동 선택 | X | F14FastMap |
| 명시 variants | flat, node | Value, Node, Vector |
| Insertion order | X | VectorMap만 |
| Trait based | X | is_trivially_relocatable |
folly의 FastMap은 abseil 식 명시적 선택에 대한 한 가지 답. 코드 작성 부담을 낮춘다.
#코드 리뷰 포인트
// Good — 일반적 경우 FastMapfolly::F14FastMap<int, int> counters;
// Bad — pointer 안정성 필요한데 FastMapfolly::F14FastMap<int, std::string> m;auto* p = &m[1];m[2] = "..."; // rehash 가능, ValueMap으로 alias 되면 UBFastMap이 어느 variant인지 모르므로 reference 안정성을 요구하는 코드는 명시적으로 NodeMap. FastMap은 “포인터 유지 안 한다”는 약속.
// 주의 — order에 의존하면 FastMap 안 됨folly::F14FastMap<int, int> m;m.insert({1, 1}); m.insert({2, 2});for (auto& [k, v] : m) { // 순서가 1, 2일 수도, 2, 1일 수도}FastMap의 순서는 컴파일 결과에 따라 다르다. 순서가 의미 있으면 F14VectorMap을 명시.
// Good — value 크기 명시적struct Stat { uint64_t count; uint64_t total; }; // 16 bytefolly::F14FastMap<int, Stat> stats; // ValueMap으로 dispatch작은 POD value면 FastMap이 ValueMap을 선택해 최적.
#안티패턴
F14FastMap을 NodeMap 대체로 사용: FastMap은 절대로 NodeMap을 선택하지 않는다. pointer 안정성 필요하면 NodeMap 명시.- value type을 incomplete type으로 FastMap에:
sizeof(pair)를 계산해야 하므로 complete type 필요. forward declared type은 못 씀. - 순서가 깨지는 곳에서 VectorMap default 가정: FastMap이
int → int같은 작은 type을 받으면 ValueMap 선택. 순서 없다.
#정리
F14FastMap은sizeof(pair)기반 컴파일 타임 dispatch.- 작은 value →
F14ValueMap, 큰 value →F14VectorMap. F14NodeMap은 자동 선택 안 함 — 필요하면 명시.- order/pointer 안정성에 의존하지 않는 일반 코드의 default.
- variant가 무엇인지 모르므로 변형별 특수 동작 가정 금지.
#다음 편
마지막으로 F14의 SIMD probing 내부를 본다. control byte 구조, H1/H2 hash split, NEON/SSE2 dispatch.
#관련 항목
Folly Code Review · 34 of 89
- 1 Folly Code Review — Meta의 production-grade C++ 라이브러리 코드 분석
- 2 Folly 개요 — Meta가 production에서 검증한 utility 모음 분석
- 3 Folly vs Abseil 철학 비교 — performance-first vs std-compatible
- 4 Folly 빌드와 fbcode 환경 — monorepo의 그림자
- 5 Folly API stability 정책 — 어떤 보장도 없다는 솔직함
- 6 Folly production validation 문화 — peta-scale에서 단련된 코드
- 7 folly::Future 분석 — std::future의 한계를 넘는 composable async
- 8 folly::Promise·makeFuture — Future를 만드는 두 길
- 9 folly::SemiFuture vs Future — executor binding의 명시화
- 10 folly::Future thenValue·thenError·thenTry — continuation 체인 분석
- 11 folly::collect·collectAll·collectAny — fan-in 패턴 분석
- 12 folly::Future retry·window·via — 제어 흐름 조합자
- 13 folly::fibers 분석 — M:N stackful coroutine
- 14 folly::InlineExecutor — 호출자 thread에서 즉시 실행
- 15 folly::CPUThreadPoolExecutor — CPU-bound 작업의 표준 thread pool
- 16 folly::IOThreadPoolExecutor — libevent 기반 I/O pool
- 17 folly::ManualExecutor — 결정적 테스트를 위한 수동 진행
- 18 folly::EventBase 분석 — libevent 이벤트 루프의 핵심
- 19 folly::IOBuf 분석 — zero-copy buffer chain의 기본 단위
- 20 folly::IOBufQueue — chain의 push/pull 추상화
- 21 folly::io::Cursor·RWCursor — chain 위의 stream
- 22 folly Zero-copy 패턴 — IOBuf로 ScatterGather I/O 표현
- 23 folly::IOBuf shared semantics — clone·unshare·takeOwnership
- 24 folly::FBString 분석 — SSO + COW 구현
- 25 folly의 fmt::format 통합 — 모던 포맷팅 채택
- 26 folly::StringPiece — string_view 호환 분석
- 27 folly Join·Split utilities — 문자열 분해와 결합
- 28 folly::to·tryTo — text↔num 변환 분석
- 29 folly Conv Customization — 사용자 타입 지원
- 30 folly Conv 성능 비교 — sprintf·stringstream 대비
- 31 folly::F14ValueMap vs std::unordered_map
- 32 folly::F14NodeMap — stable pointer가 필요할 때
- 33 folly::F14VectorMap — cache-friendly iteration
- 34 folly::F14FastMap — auto-select 동작
- 35 folly F14 internals — SIMD probing 메커니즘
- 36 folly::small_vector — inline storage 분석
- 37 folly::FixedString — compile-time string
- 38 folly::AtomicHashMap — lock-free read 분석
- 39 folly::ConcurrentHashMap — sharded 동시 해시 맵
- 40 folly::EvictingCacheMap — LRU 구현 분석
- 41 folly::Synchronized — lock wrapper 패턴
- 42 folly::SharedMutex 분석
- 43 folly::Baton — one-shot wait 동기화
- 44 folly::RWSpinLock 분석
- 45 folly::PicoSpinLock — 1-byte spinlock
- 46 folly::ProducerConsumerQueue — SPSC 큐 분석
- 47 folly::MPMCQueue — multi-producer multi-consumer
- 48 folly::UnboundedQueue — 동적 크기 lock-free
- 49 folly::fibers::Channel — Go-like channel
- 50 folly::dynamic — JSON-like dynamic type 분석
- 51 folly JSON conversion — toJson·parseJson
- 52 folly dynamic ↔ struct — manual marshaling
- 53 folly dynamic Visitor pattern — type별 분기
- 54 folly::Singleton vs Meyers/static — 왜 Folly의 Singleton인가
- 55 folly::SingletonVault 분석 — 등록·소멸·의존성
- 56 folly::Singleton try_get·try_get_fast — TLS-cached 접근
- 57 folly::ExceptionWrapper — type-erased exception holder
- 58 folly::ScopeGuard·SCOPE_EXIT — RAII cleanup
- 59 folly::Optional vs std::optional
- 60 folly::Function vs std::function
- 61 folly::Lazy — 지연 초기화 wrapper
- 62 folly Meta 스타일 code review 패턴
- 63 folly anti-patterns — 잘못 쓰면 std보다 느림
- 64 folly vs std 선택 기준 분석
- 65 folly::coro 개요 — production C++20 코루틴 어댑터
- 66 folly::coro::Task — lazy single-shot 코루틴
- 67 folly::coro::AsyncGenerator — 비동기 스트림
- 68 folly coro blockingWait·collectAll — 동기 경계와 fan-in
- 69 folly::coro::Baton·Mutex — 코루틴-aware 동기화
- 70 folly::Expected — 결과 또는 오류
- 71 folly::Try — Future 결과 wrapper
- 72 folly::Try vs Expected 선택 기준
- 73 folly::Range — 일반 iterator pair
- 74 folly::Uri — URL 파서
- 75 folly Fingerprint64·128 — 분산 hash
- 76 folly SpookyHashV2 — fast non-crypto hash
- 77 folly::Init — main() 부트스트랩
- 78 folly::Indestructible — global lifetime 패턴
- 79 folly::MicroLock — 1-byte 락
- 80 folly::MicroSpinLock — 가장 좁은 spin lock
- 81 folly::format — legacy formatter 분석
- 82 folly::demangle — typeid 디망글링
- 83 folly::DynamicConverter — dynamic ↔ struct
- 84 folly::RecordIO — append-only 로그 파일 포맷
- 85 folly::io::Compression — zstd·lz4·snappy wrapper
- 86 folly::AsyncIO — io_uring·Linux AIO
- 87 folly::CancellationToken — 코루틴·Future 취소 전파
- 88 folly::observer — hot config의 atomic refresh
- 89 fbcode 패턴 모음 — folly 사용의 실전
관련 글
folly F14 internals — SIMD probing 메커니즘
F14 chunk 구조와 SIMD probing — SSE2/AVX/NEON dispatch, H1/H2 hash split, 14-slot 선택 이유.
같은 시리즈에서 이어 읽기
folly::F14VectorMap — cache-friendly iteration
F14VectorMap — value를 contiguous vector에 두고 chunk에는 index만, 순회 cache-friendly.
같은 시리즈에서 이어 읽기
folly::F14NodeMap — stable pointer가 필요할 때
F14NodeMap — value를 별도 heap node에 두어 pointer/reference 안정성을 보장하는 F14 변형.
같은 시리즈에서 이어 읽기
이 글을 참조하는 글 (7)
- folly::SingletonVault 분석 — 등록·소멸·의존성 — Folly Code Review
- folly::EvictingCacheMap — LRU 구현 분석 — Folly Code Review
- folly::small_vector — inline storage 분석 — Folly Code Review
- folly F14 internals — SIMD probing 메커니즘 — Folly Code Review
- folly::F14VectorMap — cache-friendly iteration — Folly Code Review
- folly::F14NodeMap — stable pointer가 필요할 때 — Folly Code Review
- folly::F14ValueMap vs std::unordered_map — Folly Code Review