167 lines
3.6 KiB
C++
167 lines
3.6 KiB
C++
//
|
|
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022
|
|
//
|
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
//
|
|
#pragma once
|
|
|
|
#include "td/utils/common.h"
|
|
#include "td/utils/HashTableUtils.h"
|
|
|
|
#include <new>
|
|
#include <type_traits>
|
|
#include <utility>
|
|
|
|
namespace td {
|
|
|
|
template <class KeyT, class ValueT, class Enable = void>
|
|
struct MapNode {
|
|
using first_type = KeyT;
|
|
using second_type = ValueT;
|
|
using public_key_type = KeyT;
|
|
using public_type = MapNode;
|
|
|
|
KeyT first{};
|
|
union {
|
|
ValueT second;
|
|
};
|
|
|
|
const KeyT &key() const {
|
|
return first;
|
|
}
|
|
|
|
MapNode &get_public() {
|
|
return *this;
|
|
}
|
|
|
|
const MapNode &get_public() const {
|
|
return *this;
|
|
}
|
|
|
|
MapNode() {
|
|
}
|
|
MapNode(KeyT key, ValueT value) : first(std::move(key)) {
|
|
new (&second) ValueT(std::move(value));
|
|
DCHECK(!empty());
|
|
}
|
|
MapNode(const MapNode &other) = delete;
|
|
MapNode &operator=(const MapNode &other) = delete;
|
|
MapNode(MapNode &&other) noexcept {
|
|
*this = std::move(other);
|
|
}
|
|
void operator=(MapNode &&other) noexcept {
|
|
DCHECK(empty());
|
|
DCHECK(!other.empty());
|
|
first = std::move(other.first);
|
|
other.first = KeyT{};
|
|
new (&second) ValueT(std::move(other.second));
|
|
other.second.~ValueT();
|
|
}
|
|
~MapNode() {
|
|
if (!empty()) {
|
|
second.~ValueT();
|
|
}
|
|
}
|
|
|
|
void copy_from(const MapNode &other) {
|
|
DCHECK(empty());
|
|
DCHECK(!other.empty());
|
|
first = other.first;
|
|
new (&second) ValueT(other.second);
|
|
}
|
|
|
|
bool empty() const {
|
|
return is_hash_table_key_empty(first);
|
|
}
|
|
|
|
void clear() {
|
|
DCHECK(!empty());
|
|
first = KeyT();
|
|
second.~ValueT();
|
|
DCHECK(empty());
|
|
}
|
|
|
|
template <class... ArgsT>
|
|
void emplace(KeyT key, ArgsT &&...args) {
|
|
DCHECK(empty());
|
|
first = std::move(key);
|
|
new (&second) ValueT(std::forward<ArgsT>(args)...);
|
|
DCHECK(!empty());
|
|
}
|
|
};
|
|
|
|
template <class KeyT, class ValueT>
|
|
struct MapNode<KeyT, ValueT, typename std::enable_if_t<(sizeof(KeyT) + sizeof(ValueT) > 6 * sizeof(void *))>> {
|
|
struct Impl {
|
|
using first_type = KeyT;
|
|
using second_type = ValueT;
|
|
|
|
KeyT first{};
|
|
union {
|
|
ValueT second;
|
|
};
|
|
|
|
template <class InputKeyT, class... ArgsT>
|
|
Impl(InputKeyT &&key, ArgsT &&...args) : first(std::forward<InputKeyT>(key)) {
|
|
new (&second) ValueT(std::forward<ArgsT>(args)...);
|
|
DCHECK(!is_hash_table_key_empty(first));
|
|
}
|
|
Impl(const Impl &other) = delete;
|
|
Impl &operator=(const Impl &other) = delete;
|
|
Impl(Impl &&other) = delete;
|
|
void operator=(Impl &&other) = delete;
|
|
~Impl() {
|
|
second.~ValueT();
|
|
}
|
|
};
|
|
|
|
using first_type = KeyT;
|
|
using second_type = ValueT;
|
|
using public_key_type = KeyT;
|
|
using public_type = Impl;
|
|
|
|
unique_ptr<Impl> impl_;
|
|
|
|
const KeyT &key() const {
|
|
DCHECK(!empty());
|
|
return impl_->first;
|
|
}
|
|
|
|
Impl &get_public() {
|
|
return *impl_;
|
|
}
|
|
|
|
const Impl &get_public() const {
|
|
return *impl_;
|
|
}
|
|
|
|
MapNode() {
|
|
}
|
|
MapNode(KeyT key, ValueT value) : impl_(td::make_unique<Impl>(std::move(key), std::move(value))) {
|
|
}
|
|
|
|
void copy_from(const MapNode &other) {
|
|
DCHECK(empty());
|
|
DCHECK(!other.empty());
|
|
impl_ = td::make_unique<Impl>(other.impl_->first, other.impl_->second);
|
|
}
|
|
|
|
bool empty() const {
|
|
return impl_ == nullptr;
|
|
}
|
|
|
|
void clear() {
|
|
DCHECK(!empty());
|
|
impl_ = nullptr;
|
|
}
|
|
|
|
template <class... ArgsT>
|
|
void emplace(KeyT key, ArgsT &&...args) {
|
|
DCHECK(empty());
|
|
impl_ = td::make_unique<Impl>(std::move(key), std::forward<ArgsT>(args)...);
|
|
}
|
|
};
|
|
|
|
} // namespace td
|