const char *key = luaL_checkstring(L, 2);
luaL_checkany(L, 3);
if (lua_isnil(L, 3)) {
- (void)m->_set(key, 0, 0);
+ m->_remove(key);
return 0;
}
lua_getiuservalue(L, 1, 1);
switch (lua_tointeger(L, -1)) {
case MAPTYPE_STRINGSET:
- (void)m->_set(key, key, 0);
+ m->_set(key);
break;
case MAPTYPE_CLIENT: {
void **p = (void **)luaL_checkudata(L, 3, "client");
- (void)m->_set(key, *p, 0);
+ m->_set(*p);
break;
}
case MAPTYPE_CHANNEL: {
void **p = (void **)luaL_checkudata(L, 3, "channel");
- (void)m->_set(key, *p, 0);
+ m->_set(*p);
break;
}
}
lua_getiuservalue(L, 1, 1);
switch (lua_tointeger(L, -1)) {
case MAPTYPE_STRINGSET:
- lua_pushstring(L, key);
- lua_pushstring(L, key);
+ lua_pushlstring(L, key.data(), key.size());
+ lua_pushlstring(L, key.data(), key.size());
return 2;
case MAPTYPE_CLIENT:
- lua_pushstring(L, key);
+ lua_pushlstring(L, key.data(), key.size());
*(Client **)lua_newuserdatauv(L, sizeof(Client *), 0) = (Client *)value;
luaL_setmetatable(L, "client");
return 2;
case MAPTYPE_CHANNEL:
- lua_pushstring(L, key);
+ lua_pushlstring(L, key.data(), key.size());
*(Channel **)lua_newuserdatauv(L, sizeof(Channel *), 0) = (Channel *)value;
luaL_setmetatable(L, "channel");
return 2;
KeyContainer m_vec;
[[no_unique_address]] Compare cmp;
public:
- using iterator = KeyContainer::iterator;
- auto begin() noexcept { return m_vec.begin(); }
- auto end() noexcept { return m_vec.end(); }
+ using iterator = KeyContainer::const_iterator;
+ iterator begin() noexcept { return m_vec.cbegin(); }
+ iterator end() noexcept { return m_vec.cend(); }
- auto lower_bound(const Key& key) {
+ KeyContainer extract() && {
+ return std::move(m_vec);
+ }
+ void replace(KeyContainer&& cont) {
+ m_vec = std::move(cont);
+ }
+
+ iterator lower_bound(const Key& key) {
return std::partition_point(begin(), end(), [&](const auto &e){ return cmp(e, key); });
}
template<typename K> requires is_transparent<Compare>
- auto lower_bound(const K& key) {
+ iterator lower_bound(const K& key) {
return std::partition_point(begin(), end(), [&](const auto &e){ return cmp(e, key); });
}
- auto find(const Key& key) {
+ iterator find(const Key& key) {
auto it = lower_bound(key);
if (it != end() && !cmp(key, *it))
return it;
return end();
}
template<typename K> requires is_transparent<Compare>
- auto find(const K& key) {
+ iterator find(const K& key) {
auto it = lower_bound(key);
if (it != end() && !cmp(key, *it))
return it;
return end();
}
- auto insert(const Key& key) {
+ std::pair<iterator, bool> insert(const Key& key) {
auto it = lower_bound(key);
if (it != end() && !cmp(key, *it)) {
return std::make_pair(it, false);
return std::make_pair(m_vec.insert(it, key), true);
}
}
- auto insert(Key&& key) {
+ std::pair<iterator, bool> insert(Key&& key) {
auto it = lower_bound(key);
if (it != end() && !cmp(key, *it)) {
return std::make_pair(it, false);
return std::make_pair(m_vec.insert(it, std::move(key)), true);
}
}
+ template<typename K> requires is_transparent<Compare>
+ std::pair<iterator, bool> insert(K&& key) {
+ auto it = lower_bound(key);
+ if (it != end() && !cmp(key, *it)) {
+ return std::make_pair(it, false);
+ } else {
+ return std::make_pair(m_vec.emplace(it, std::forward<K>(key)), true);
+ }
+ }
- auto erase(typename KeyContainer::iterator it) {
+ iterator erase(iterator it) {
return m_vec.erase(it);
}
size_t erase(const Key& key) {
void clear() noexcept {
m_vec.clear();
}
- auto size() noexcept {
+ size_t size() noexcept {
return m_vec.size();
}
* A map is created by allocating and zero-initializing an object of type
* map_t. All map functions take a pointer to map_t.
*/
+struct Client;
+struct Channel;
+constexpr std::string_view to_key(const std::string &v) noexcept {
+ return v;
+}
+constexpr std::string_view to_key(const Client *v) noexcept;
+constexpr std::string_view to_key(const Channel *v) noexcept;
+
template<typename T>
struct MapValueLess {
using is_transparent = void;
- constexpr std::string_view to_key(const T &v) {
- return v.key;
- }
constexpr bool operator()(const T& lhs, const T& rhs) noexcept {
return to_key(lhs) < to_key(rhs);
}
+ constexpr bool operator()(const T& lhs, const char *rhs) noexcept {
+ return to_key(lhs) < rhs;
+ }
+ constexpr bool operator()(const char *lhs, const T& rhs) noexcept {
+ return lhs < to_key(rhs);
+ }
constexpr bool operator()(const T& lhs, std::string_view rhs) noexcept {
return to_key(lhs) < rhs;
}
map_base& operator=(map_base&&) = delete;
virtual ~map_base() = default;
virtual void *_get(const char *key) =0;
- virtual void _set(const char *key, const void *value, void **oldvalue) =0;
- virtual std::pair<char *, void *>_next(size_t& index) =0;
+ virtual void _set(const void *value) =0;
+ virtual void _remove(const char *key) =0;
+ virtual std::pair<std::string_view, void *> _next(size_t& index) =0;
struct iter {
map_base *root;
size_t index;
};
};
-struct map_base1_5 : map_base {
- struct map_value {
- char *key;
- void *value;
- };
- FlatSet<map_value, MapValueLess<map_value>> m;
+template<typename T>
+struct map_base2 : map_base {
+ FlatSet<T, MapValueLess<T>> m;
- ~map_base1_5() {
+ ~map_base2() {
clear();
}
- void *_get(const char *key) final {
- auto it = m.find(std::string_view(key));
- return it != m.end() ? it->value : nullptr;
+private:
+ static constexpr T value_to_void(T v) noexcept requires (std::same_as<T, Client*> || std::same_as<T, Channel*>) {
+ return v;
}
- void *_iget(const char *key) {
- auto it = m.find(LowercasingView(key));
- return it != m.end() ? it->value : nullptr;
+ static constexpr char *value_to_void(const T& v) noexcept requires std::same_as<T, std::string> {
+ return const_cast<char *>(v.data());
}
- void _set(const char *key, const void *value, void **oldvalue) final {
+ using value_to_void_type = decltype(value_to_void(std::declval<T>()));
+
+ constexpr T void_to_value(void *p) noexcept requires (std::same_as<T, Client*> || std::same_as<T, Channel*>) {
+ return static_cast<T>(p);
+ }
+ constexpr std::string_view void_to_value(void *p) noexcept requires std::same_as<T, std::string> {
+ return static_cast<char *>(p);
+ }
+public:
+ void *_get(const char *key) final {
+ auto it = m.find(key);
+ return it != m.end() ? value_to_void(*it) : nullptr;
+ }
+ void _set(const void *value) final {
if (value) {
- map_value mv;
- mv.key = const_cast<char *>(key);
- mv.value = const_cast<void *>(value);
- auto [it, inserted] = m.insert(mv);
- if (inserted) {
- if (oldvalue)
- *oldvalue = nullptr;
- it->key = mystrdup(it->key);
- } else {
- if (oldvalue)
- *oldvalue = it->value;
- it->value = mv.value;
- }
- } else {
- auto it = m.find(std::string_view(key));
- if (oldvalue)
- *oldvalue = it != m.end() ? it->value : nullptr;
- if (it != m.end()) {
- delete[] it->key;
- m.erase(it);
- }
+ auto mv = void_to_value(const_cast<void *>(value));
+ m.insert(mv);
}
}
- std::pair<char *, void *>_next(size_t& index) final {
- map_value kv{0, 0};
+ void _remove(const char *key) final {
+ remove(key);
+ }
+ std::pair<std::string_view, void *> _next(size_t& index) final {
auto it = m.begin() + index;
if (it < m.end()) {
- kv = *it;
index++;
+ return std::make_pair(to_key(*it), static_cast<void *>(value_to_void(*it)));
}
- return std::make_pair(kv.key, kv.value);
+ return std::make_pair(std::string_view(), nullptr);
}
void clear() {
- for (auto &mv : m)
- delete[] mv.key;
m.clear();
}
-};
-template<typename T, typename V>
-struct map_base2 : map_base1_5 {
- using value_type = V;
+ using value_type = T;
struct iterator {
using iterator_category = std::bidirectional_iterator_tag;
- using value_type = V;
+ using value_type = value_to_void_type;
using difference_type = ptrdiff_t;
using pointer = void;
- using reference = V;
+ using reference = value_to_void_type;
iterator &operator++() { ++ptr; return *this; }
iterator operator++(int) { auto it = *this; ++ptr; return it; }
iterator &operator--() { --ptr; return *this; }
iterator operator--(int) { auto it = *this; --ptr; return it; }
bool operator==(const iterator& other) const = default;
- reference operator*() const { return T::to_value(&*ptr); }
+ reference operator*() const { return value_to_void(*ptr); }
decltype(m)::iterator ptr;
};
static_assert(std::bidirectional_iterator<iterator>);
size_t size() {
return m.size();
}
-protected:
- static const char *to_key(V v) {
- return v->key;
- }
- static V to_value(map_value *v) {
- return static_cast<V>(v->value);
- }
public:
- bool has(V v) {
- return !!_get(T::to_key(v));
- }
- bool add(V v) {
- void *old;
- _set(T::to_key(v), v, &old);
- return !old;
- }
- bool remove(V v) {
- void *old;
- (void)_set(T::to_key(v), 0, &old);
- return !!old;
+ template<typename K>
+ bool has(const K& k) {
+ return m.find(k) != m.end();
+ }
+ bool add(const T &v) {
+ return m.insert(v).second;
+ }
+ template<typename K>
+ bool remove(const K &k) {
+ if (auto it = m.find(k); it != m.end()) {
+ m.erase(it);
+ return true;
+ }
+ return false;
}
- V get(const char *k) {
- return static_cast<V>(_get(k));
+ template<typename K>
+ T get(const K& k) {
+ auto it = m.find(k);
+ return it != m.end() ? *it : T();
}
- V iget(const char *k) {
- return static_cast<V>(_iget(k));
+ T iget(const char *k) {
+ return get(LowercasingView(k));
}
};
-struct Client;
-struct clientmap : map_base2<clientmap, Client *> {
+struct clientmap : map_base2<Client *> {
void rename(Client *v, const char *newk) {
- remove(v);
- _set(newk, v, 0);
+ if (remove(v)) {
+ auto pos = m.lower_bound(std::string_view(newk)) - m.begin();
+ auto vec = std::move(m).extract();
+ vec.insert(vec.begin() + pos, v);
+ // FIXME: this is actually UB. better do some const_casting and std::rotate
+ m.replace(std::move(vec));
+ }
}
};
-struct Channel;
-struct channelmap : map_base2<channelmap, Channel *> {
+struct channelmap : map_base2<Channel *> {
};
-struct stringset : map_base2<stringset, const char *> {
-protected:
- friend map_base2;
- static const char *to_key(const char *v) {
- return v;
- }
- static const char *to_value(map_value *v) {
- return v->key;
- }
-public:
- const char *get(const char *k) = delete;
- const char *iget(const char *k) = delete;
+struct stringset : map_base2<std::string> {
+ template<typename K>
+ std::string get(const K& k) = delete;
+ std::string iget(const char *k) = delete;
};
#endif