/* *****************************************************************************
* kblib is a general utility library for C++14 and C++17, intended to provide
* performant high-level abstractions and more expressive ways to do simple
* things.
*
* Copyright (c) 2021 killerbee
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
* ****************************************************************************/
/**
* @file
* @brief Provides the trie data structure.
*
* @author killerbee
* @date 2019-2021
* @copyright GNU General Public Licence v3.0
*/
#ifndef TRIE_H
#define TRIE_H
#include "tdecl.h"
#if KBLIB_USE_CXX17
# include "sort.h"
# include "traits.h"
# include
# include
# include
namespace KBLIB_NS {
enum class extractor_policy {
forward_iteration,
random_access,
};
template
struct iterator_extractor {
using value_type =
typename std::remove_cv()))>::type>::type;
};
template
struct indexer_extractor : iterator_extractor {
using value_type =
typename std::remove_cv()[0])>::type>::type;
template
KBLIB_NODISCARD constexpr static auto subscript(
Container&& c, index_type index) noexcept(noexcept(c[index]))
-> decltype(auto) {
return c[index];
}
};
template
struct extractor_policy_for {
constexpr static extractor_policy value
= extractor_policy::forward_iteration;
};
template
struct extractor_policy_for()[0])>> {
constexpr static extractor_policy value = extractor_policy::random_access;
};
template
using default_extractor_t = typename std::conditional<
extractor_policy_for::value == extractor_policy::random_access,
indexer_extractor, iterator_extractor>::type;
namespace detail {
template
struct node {};
} // namespace detail
template ,
bool = kblib::is_linear_container::value>
class trie {
public:
using key_type = Key;
using mapped_type = T;
using value_type = std::pair;
using extractor = Extractor;
using node_type = detail::node;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using reference = T&;
using const_reference = const T&;
using pointer = T*;
using const_pointer = const T*;
using iterator = void;
using const_iterator = void;
using reverse_iterator = std::reverse_iterator;
using const_reverse_iterator = std::reverse_iterator;
private:
std::unique_ptr root;
public:
};
template
class trie {};
template
class trie {};
// Array-mapped tries are better for denser sets
// Tree-based tries are better for sparser sets
// trie_map and trie_set are mostly API compatible with std::map, std::set
// trie_qmap and trie_qset use proxy iterators to avoid having to store Keys
// (saves memory, less compatible with stdlib)
template
struct default_extract;
template
struct default_extract>> {
using value_type = typename Key::value_type;
static_assert(static_cast(max) < static_cast(max),
"Key too large to index array");
// won't overflow because of above assertion
KBLIB_CONSTANT_M std::size_t key_cardinality
= static_cast(max) + std::size_t{1};
static_assert(std::is_integral::value,
"Key elements must be integral");
KBLIB_NODISCARD static constexpr auto begin(Key& key) noexcept(
noexcept(key.begin())) -> decltype(auto) {
return key.begin();
}
KBLIB_NODISCARD static constexpr auto end(Key& key) noexcept(
noexcept(key.end())) -> decltype(auto) {
return key.end();
}
KBLIB_NODISCARD static constexpr auto index(
Key& key, std::size_t idx) noexcept(noexcept(key[idx]))
-> decltype(auto) {
return key[idx];
}
};
template
struct default_extract>> {
using value_type = KeyElem;
static_assert(static_cast(max) < static_cast(max),
"Key too large to index array");
// won't overflow because of above assertion
KBLIB_CONSTANT_M std::size_t key_cardinality
= static_cast(max) + std::size_t{1};
static_assert(std::is_integral::value,
"Key elements must be integral");
template
KBLIB_NODISCARD static constexpr auto begin(KeyElem (&key)[Size]) noexcept(
noexcept(std::begin(key))) -> decltype(auto) {
return std::begin(key);
}
template
KBLIB_NODISCARD static constexpr auto end(KeyElem (&key)[Size]) noexcept(
noexcept(std::end(key))) -> decltype(auto) {
return std::end(key);
}
template
KBLIB_NODISCARD static constexpr auto index(
KeyElem (&key)[Size], std::size_t idx) noexcept(noexcept(key[idx]))
-> decltype(auto) {
return key[idx];
}
};
template
struct default_extract>>;
// qset: does not store Keys (generates them on-demand)
// Key: the type used for lookup
// Extractor: controls how lookup is performed from the key
// offset_type: used to represent jumps in the internal array. Must be a signed
// integral type
template ,
typename offset_type = std::ptrdiff_t>
class trie_qset {
public:
using key_type = Key;
using value_type = Key;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using reference = value_type&;
using const_reference = const value_type&;
using pointer = value_type*;
using const_pointer = const value_type*;
using extractor = Extractor;
using key_elem = typename extractor::value_type;
KBLIB_CONSTANT_M std::size_t key_elem_cardinality
= extractor::key_cardinality;
private:
// Bitset stores leaf status, array holds jumps, 0 represents no jump (leaf
// or no entry)
using row_type = std::pair,
std::array>;
std::vector data_;
};
template ,
typename offset_type = std::ptrdiff_t>
class trie_set {
public:
using key_type = Key;
using value_type = Key;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using reference = value_type&;
using const_reference = const value_type&;
using pointer = value_type*;
using const_pointer = const value_type*;
using extractor = Extractor;
using key_elem = typename extractor::value_type;
KBLIB_CONSTANT_M std::size_t key_elem_cardinality
= extractor::key_cardinality;
private:
// offset 0 represents no jump (leaf or no entry)
using row_type = std::array, offset_type>,
key_elem_cardinality>;
std::vector data_;
};
template ,
typename offset_type = std::ptrdiff_t,
template typename SequenceContainer = std::vector>
class trie_map {};
template ,
typename offset_type = std::ptrdiff_t,
template typename SequenceContainer = std::vector>
class trie_qmap {};
template >
class sparse_trie_set {};
template >
class sparse_trie_map {};
} // namespace KBLIB_NS
#endif // KBLIB_USE_CXX17
#endif // TRIE_H