From: Vsevolod Stakhov Date: Sun, 10 Apr 2022 08:06:33 +0000 (+0100) Subject: [Minor] Forgot to add a file X-Git-Tag: 3.3~293^2~40 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=c1654354869b81db2a30dc02fef3d5b82b516c33;p=thirdparty%2Frspamd.git [Minor] Forgot to add a file --- diff --git a/src/libserver/symcache/symcache_id_list.hxx b/src/libserver/symcache/symcache_id_list.hxx new file mode 100644 index 0000000000..b42cb9183a --- /dev/null +++ b/src/libserver/symcache/symcache_id_list.hxx @@ -0,0 +1,154 @@ +/*- + * Copyright 2022 Vsevolod Stakhov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RSPAMD_SYMCACHE_ID_LIST_HXX +#define RSPAMD_SYMCACHE_ID_LIST_HXX +#pragma once + +#include +#include // for memset +#include // for sort + +#include "config.h" +#include "libutil/mem_pool.h" + +namespace rspamd::symcache { +/* + * This structure is optimised to store ids list: + * - If the first element is -1 then use dynamic part, else use static part + * There is no std::variant to save space + */ +struct id_list { + union { + std::uint32_t st[4]; + struct { + std::uint32_t e; /* First element */ + std::uint16_t len; + std::uint16_t allocated; + std::uint32_t *n; + } dyn; + } data; + + id_list() = default; + auto reset() { + std::memset(&data, 0, sizeof(data)); + } + + /** + * Returns ids from a compressed list, accepting a mutable reference for number of elements + * @param nids output of the number of elements + * @return + */ + auto get_ids(std::size_t &nids) const -> const std::uint32_t * + { + if (data.dyn.e == -1) { + /* Dynamic list */ + nids = data.dyn.len; + + return data.dyn.n; + } + else { + auto cnt = 0; + + while (data.st[cnt] != 0 && cnt < G_N_ELEMENTS(data.st)) { + cnt++; + } + + nids = cnt; + + return data.st; + } + } + + auto add_id(std::uint32_t id, rspamd_mempool_t *pool) -> void + { + if (data.st[0] == -1) { + /* Dynamic array */ + if (data.dyn.len < data.dyn.allocated) { + /* Trivial, append + sort */ + data.dyn.n[data.dyn.len++] = id; + } + else { + /* Reallocate */ + g_assert(data.dyn.allocated <= G_MAXINT16); + data.dyn.allocated *= 2; + + auto *new_array = rspamd_mempool_alloc_array_type(pool, + data.dyn.allocated, std::uint32_t); + memcpy(new_array, data.dyn.n, data.dyn.len * sizeof(std::uint32_t)); + data.dyn.n = new_array; + data.dyn.n[data.dyn.len++] = id; + } + + std::sort(data.dyn.n, data.dyn.n + data.dyn.len); + } + else { + /* Static part */ + auto cnt = 0u; + while (data.st[cnt] != 0 && cnt < G_N_ELEMENTS(data.st)) { + cnt++; + } + + if (cnt < G_N_ELEMENTS(data.st)) { + data.st[cnt] = id; + } + else { + /* Switch to dynamic */ + data.dyn.allocated = G_N_ELEMENTS(data.st) * 2; + auto *new_array = rspamd_mempool_alloc_array_type(pool, + data.dyn.allocated, std::uint32_t); + memcpy(new_array, data.st, sizeof(data.st)); + data.dyn.n = new_array; + data.dyn.e = -1; /* Marker */ + data.dyn.len = G_N_ELEMENTS(data.st); + + /* Recursively jump to dynamic branch that will handle insertion + sorting */ + add_id(id, pool); // tail call + } + } + } + + auto set_ids(const std::uint32_t *ids, std::size_t nids, rspamd_mempool_t *pool) -> void { + if (nids <= G_N_ELEMENTS(data.st)) { + /* Use static version */ + reset(); + + for (auto i = 0; i < nids; i++) { + data.st[i] = ids[i]; + } + } + else { + /* Need to use a separate list */ + data.dyn.e = -1; /* Flag */ + data.dyn.n = rspamd_mempool_alloc_array_type(pool, nids, std::uint32_t); + data.dyn.len = nids; + data.dyn.allocated = nids; + + for (auto i = 0; i < nids; i++) { + data.dyn.n[i] = ids[i]; + } + + /* Keep sorted */ + std::sort(data.dyn.n, data.dyn.n + data.dyn.len); + } + } +}; + +static_assert(std::is_trivial_v); + +} + +#endif //RSPAMD_SYMCACHE_ID_LIST_HXX