源码路径
src\butil\containers\flat_map.h
src\butil\containers\flat_map_inl.h
FlatMap 是brpc的一个容器类,在server管理添加的服务时用到
基本成员
size_t _size;
size_t _nbucket; // 桶数量
Bucket* _buckets; // 桶数组
uint64_t* _thumbnail; // 用bit存放,每个下标表示桶是否有效
u_int _load_factor; // 负载因子
hasher _hashfn; // 哈希方法
key_equal _eql; // 相等判断方法
SingleThreadedPool<sizeof(Bucket), 1024, 16> _pool; // 分配桶空间的内存池
初始化
template <typename _K, typename _T, typename _H, typename _E, bool _S>
int FlatMap<_K, _T, _H, _E, _S>::init(size_t nbucket, u_int load_factor) {
if (initialized()) { // 桶数组 _buckets 不为空则已经初始化
LOG(ERROR) << "Already initialized";
return -1;
}
if (load_factor < 10 || load_factor > 100) {
LOG(ERROR) << "Invalid load_factor=" << load_factor;
return -1;
}
_size = 0;
_nbucket = flatmap_round(nbucket); // 将入参桶数量变为最近的一个素数或2的幂
_load_factor = load_factor;
_buckets = (Bucket*)malloc(sizeof(Bucket) * (_nbucket + 1));
if (NULL == _buckets) {
LOG(ERROR) << "Fail to new _buckets";
return -1;
}
for (size_t i = 0; i < _nbucket; ++i) {
_buckets[i].set_invalid(); // 将每个桶元素的next指针置为-1
}
_buckets[_nbucket].next = NULL;
if (_S) {
_thumbnail = bit_array_malloc(_nbucket); // 以8字节为单位分配空间,详见bit_array.h
if (NULL == _thumbnail) {
LOG(ERROR) << "Fail to new _thumbnail";
return -1;
}
bit_array_clear(_thumbnail, _nbucket);
}
return 0;
}
插入元素
template <typename _K, typename _T, typename _H, typename _E, bool _S>
_T* FlatMap<_K, _T, _H, _E, _S>::insert(const key_type& key,
const mapped_type& value) {
mapped_type *p = &operator[](key);
*p = value;
return p;
}
删除元素
template <typename _K, typename _T, typename _H, typename _E, bool _S>
template <typename K2>
size_t FlatMap<_K, _T, _H, _E, _S>::erase(const K2& key, _T* old_value) {
if (!initialized()) {
return 0;
}
const size_t index = flatmap_mod(_hashfn(key), _nbucket); // 对key求哈希然后对桶数量取模
Bucket& first_node = _buckets[index];
if (!first_node.is_valid()) {
return 0;
}
if (_eql(first_node.element().first_ref(), key)) {
if (old_value) { // 返回删除节点的值
*old_value = first_node.element().second_ref();
}
if (first_node.next == NULL) { // 对该节点元素调用析构
first_node.element().~Element();
first_node.set_invalid();
if (_S) {
bit_array_unset(_thumbnail, index); // _thumbnail 数组第index个bit置零
}
} else {
Bucket* p = first_node.next; // 待删节点后还有元素next,把next删掉,然后将next的值拷贝到当前节点。
first_node.next = p->next;
const_cast<_K&>(first_node.element().first_ref()) =
p->element().first_ref();
first_node.element().second_ref() = p->element().second_ref();
p->element().~Element();
_pool.back(p); // 还给内存池?
}
--_size;
return 1UL;
}
// 这里说明待删节点不是桶第一个元素,找到后直接将节点前缀的next指向节点后缀即可
Bucket *p = first_node.next;
Bucket *last_p = &first_node;
while (p) {
if (_eql(p->element().first_ref(), key)) {
if (old_value) {
*old_value = p->element().second_ref();
}
last_p->next = p->next;
p->element().~Element();
_pool.back(p);
--_size;
return 1UL;
}
last_p = p;
p = p->next;
}
return 0;
}
过程基本是求哈希值,找到对应的桶,如果要删的是首元素且只有一个,直接删除;是首元素但不止一个,则将第二个元素删了,然后它的值拷贝到首元素中;不是首元素,则直接将待删节点的前缀节点next指向节点后缀。
清空元素
template <typename _K, typename _T, typename _H, typename _E, bool _S>
void FlatMap<_K, _T, _H, _E, _S>::clear() {
if (0 == _size) {
return;
}
_size = 0;
if (NULL != _buckets) {
for (size_t i = 0; i < _nbucket; ++i) {
Bucket& first_node = _buckets[i]; // 对每个桶每个元素调用析构
if (first_node.is_valid()) {
first_node.element().~Element();
Bucket* p = first_node.next;
while (p) {
Bucket* next_p = p->next;
p->element().~Element();
_pool.back(p);
p = next_p;
}
first_node.set_invalid();
}
}
}
if (NULL != _thumbnail) {
bit_array_clear(_thumbnail, _nbucket); // 对每个桶表示的bit置零
}
}
对每个桶每个元素调用析构,并对_thumbnail 每个桶代表的big置零
寻找元素
template <typename _K, typename _T, typename _H, typename _E, bool _S>
template <typename K2>
_T* FlatMap<_K, _T, _H, _E, _S>::seek(const K2& key) const {
if (!initialized()) {
return NULL;
}
Bucket& first_node = _buckets[flatmap_mod(_hashfn(key), _nbucket)];
if (!first_node.is_valid()) {
return NULL;
}
if (_eql(first_node.element().first_ref(), key)) {
return &first_node.element().second_ref();
}
Bucket *p = first_node.next;
while (p) {
if (_eql(p->element().first_ref(), key)) {
return &p->element().second_ref();
}
p = p->next;
}
return NULL;
}
寻找元素没有则添加
template <typename _K, typename _T, typename _H, typename _E, bool _S>
_T& FlatMap<_K, _T, _H, _E, _S>::operator[](const key_type& key) {
const size_t index = flatmap_mod(_hashfn(key), _nbucket);
Bucket& first_node = _buckets[index];
if (!first_node.is_valid()) { // 桶位置未占用
++_size;
if (_S) {
bit_array_set(_thumbnail, index); // 置位
}
new (&first_node) Bucket(key); // placement new,直接在元素上构建
return first_node.element().second_ref();
}
if (_eql(first_node.element().first_ref(), key)) { //是首元素则返回
return first_node.element().second_ref();
}
Bucket *p = first_node.next;
if (NULL == p) { // 只有首元素
if (is_too_crowded(_size)) {
if (resize(_nbucket + 1)) { // 扩容后添加元素
return operator[](key);
}
// fail to resize is OK
}
++_size;
Bucket* newp = new (_pool.get()) Bucket(key); // 从内存池分配并初始化
first_node.next = newp;
return newp->element().second_ref();
}
// 不止首元素
while (1) {
if (_eql(p->element().first_ref(), key)) {
return p->element().second_ref();
}
if (NULL == p->next) {
if (is_too_crowded(_size)) {
if (resize(_nbucket + 1)) {
return operator[](key);
}
// fail to resize is OK
}
++_size;
Bucket* newp = new (_pool.get()) Bucket(key);
p->next = newp;
return newp->element().second_ref();
}
p = p->next;
}
}
这里与seek的区别在于不存在则创建、扩容判断
扩容
template <typename _K, typename _T, typename _H, typename _E, bool _S>
bool FlatMap<_K, _T, _H, _E, _S>::resize(size_t nbucket2) {
nbucket2 = flatmap_round(nbucket2); // 找最近的素数或2的幂
if (_nbucket == nbucket2) {
return false;
}
FlatMap new_map;
if (new_map.init(nbucket2, _load_factor) != 0) {
LOG(ERROR) << "Fail to init new_map, nbucket=" << nbucket2;
return false;
}
for (iterator it = begin(); it != end(); ++it) {
new_map[Element::first_ref_from_value(*it)] =
Element::second_ref_from_value(*it); // first_ref_from_value 获取key,second_ref_from_value 获取value
}
new_map.swap(*this); // 替换成新的map
return true;
}