blob: 82994b9bbe34b6e9e1792698836bf39e76c76fbc [file]
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Pool for Regular Expression AST nodes (Class Definitions).
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC___SUPPORT_REGEX_REGEX_EXPR_POOL_H
#define LLVM_LIBC_SRC___SUPPORT_REGEX_REGEX_EXPR_POOL_H
#include "src/__support/CPP/expected.h"
#include "src/__support/macros/config.h"
#include "src/__support/regex/regex_ast.h"
#include <stddef.h>
namespace LIBC_NAMESPACE_DECL {
namespace regex {
/// An arena-based pool for Regular Expression AST nodes.
///
/// This class manages the allocation and hash-consing of Expr nodes. All
/// nodes created through this pool are owned by it and will be freed when
/// the pool is destroyed. Hash-consing ensures that identical expressions
/// are represented by the same pointer, enabling fast comparison and
/// derivative normalization.
class ExprPool {
/// Internal storage block for AST nodes.
///
/// Blocks are allocated on demand to avoid large contiguous allocations
/// and are linked together in a list for cleanup.
/// TODO: Consider adopting cpp::forward_list for block management once
/// it is available in LLVM-libc.
struct Block {
/// Number of Expr nodes stored in each block.
static constexpr size_t BLOCK_SIZE = 256;
/// The actual storage for Expr nodes.
Expr nodes[BLOCK_SIZE];
/// Pointer to the next block in the chain.
Block *next = nullptr;
/// Number of nodes currently used in this block.
size_t used = 0;
};
/// The first block in the allocation chain.
Block *head = nullptr;
/// The block currently being used for new node allocations.
Block *current = nullptr;
/// Total number of nodes allocated across all blocks.
size_t node_count = 0;
/// The size of the hash table used for hash-consing (interning) expression
/// nodes. Choosing 0x4000 (16,384) is the smallest power of two that keeps
/// the load factor below 70% when the pool reaches its limit of 10,000 nodes
/// (peak load factor is ~61%). Using a power of two allows the compiler to
/// optimize the modulo indexing into an efficient bitwise AND, while the low
/// load factor minimizes collisions and guarantees O(1) average interning
/// time.
static constexpr size_t HASH_TABLE_SIZE = 0x4000;
/// The maximum number of nodes allowed in the pool to prevent memory
/// exhaustion during compilation of highly complex or maliciously crafted
/// regular expressions. A limit of 10,000 nodes provides a sufficient budget
/// for most practical regexes while keeping the peak memory footprint
/// manageable (approx. 320KB-500KB depending on architecture).
static constexpr size_t MAX_NODE_LIMIT = 10000;
/// Hash table storing pointers to unique Expr nodes.
Expr **hashtable = nullptr;
/// Core hash-consing function (Interning).
///
/// Guarantees that for any two identical structural definitions of an Expr,
/// this function will return the same pointer. This enables O(1) structural
/// equality via pointer comparison.
///
/// \param e A structural definition (proto-node) to intern.
/// \returns A pointer to the unique, stable instance in the arena,
/// or REG_ESPACE on failure.
cpp::expected<Expr *, int> intern(const Expr &e);
public:
ExprPool();
~ExprPool();
// TODO: Use fluent interface (and_then, transform) for these factories once
// implemented in cpp::expected.
/// Returns an EmptySet node.
cpp::expected<Expr *, int> empty_set();
/// Returns an EmptyStr node.
cpp::expected<Expr *, int> empty_str();
/// Creates or returns an existing Literal node for the given character.
cpp::expected<Expr *, int> make_lit(char c);
/// Normalizing factory for Concatenation (L · R).
///
/// Applies algebraic simplifications before interning:
/// - (Ø · R) or (R · Ø) => Ø
/// - (ε · R) or (R · ε) => R
cpp::expected<Expr *, int> make_concat(Expr *l, Expr *r);
/// Normalizing factory for Alternation (L | R).
///
/// Applies algebraic simplifications before interning:
/// - (Ø | R) or (R | Ø) => R
/// - (R | R) => R (Idempotency)
cpp::expected<Expr *, int> make_alt(Expr *l, Expr *r);
};
} // namespace regex
} // namespace LIBC_NAMESPACE_DECL
#endif // LLVM_LIBC_SRC___SUPPORT_REGEX_REGEX_EXPR_POOL_H