xo-umbrella2/xo-indentlog2/include/xo/indentlog2/print/PpToken.hpp
Roland Conybeare 82252666f2
All checks were successful
cmake-docker / cmake-build (clang, clang++) (push) Successful in 32m4s
cmake-docker / cmake-build (gcc, g++) (push) Successful in 29m34s
CI / smoke-test (push) Successful in 52m15s
xo-ppsink: allow lpos-relative begin [FEATURE]
2026-08-22 14:11:30 -04:00

172 lines
6.4 KiB
C++

/** @file PpToken.hpp
*
* @author Roland Conybeare, Jul 2026
**/
#pragma once
#include "PpTokenType.hpp"
#include <xo/arena/span.hpp>
#include <cstdint>
namespace xo {
namespace pp {
class PpToken {
public:
using uint32_t = std::uint32_t;
public:
uint32_t tk_flags() const { return tk_flags_; }
int32_t tk_viz_len() const { return tk_viz_len_; }
int32_t tk_len() const { return tk_len_; }
/** for k_begin: added to the running indent while the group is open.
* for k_split: added to the indent of the line this break starts.
**/
int32_t tk_offset() const { return tk_offset_; }
bool is_string() const { return (tk_flags_ & k_type_mask) == k_string; }
bool is_begin() const { return (tk_flags_ & k_type_mask) == k_begin; }
bool is_forced() const { return (tk_flags_ & k_forced) != 0; }
/** mark a k_begin token's group as must-break (contains a forced break) **/
void set_forced_flag() { tk_flags_ |= k_forced; }
bool size_established() const {
auto tk_type = tk_flags_ & k_type_mask;
if (tk_type == k_begin)
return (tk_flags_ & k_size_established) != 0;
// {string, split, end} token size is always established
return true;
}
uint32_t alloc_size() const;
void set_fits_flag(bool x) {
uint32_t fits = (x ? k_fits : 0);
tk_flags_ = (tk_flags_ & ~k_fits) | fits;
}
void establish_size(int32_t tk_viz_len, int32_t tk_len) {
tk_flags_ = (tk_flags_ & ~k_size_established) | k_size_established;
tk_viz_len_ = tk_viz_len;
tk_len_ = tk_len;
}
protected:
PpToken(PpTokenFlags tk_flags,
int32_t tk_viz_len,
int32_t tk_len,
int32_t tk_offset = 0);
friend class PpState;
private:
/** token type: k_string|k_begin|k_break|k_end.
* fits flag: k_fits
**/
uint32_t tk_flags_ = k_nominal;
/**
* -1 :: does not fit -> visible length doesn't matter
* 0 :: visible length unknown
* >0 :: visible token length
**/
int32_t tk_viz_len_ = 0;
/**
* -1 :: doesn't matter, doesn't fit.
* 0 :: token length unknown
* +ve :: actual token length (characters)
**/
int32_t tk_len_ = 0;
/** k_begin: indent contributed while the group is open.
* k_split: extra indent for the line this break starts.
* (unused for k_string/k_end)
**/
int32_t tk_offset_ = 0;
};
/** @brief a k_begin token, which carries indent state the other
* token types do not need.
*
* Same variable-size-token pattern as @ref PpStringToken: the type is
* recovered from k_type_mask and the size from PpToken::alloc_size(),
* so the flat token buffer stays walkable without a vtable.
**/
class PpBeginToken : public PpToken {
public:
PpBeginToken(int32_t tk_viz_len,
int32_t tk_len,
int32_t tk_offset,
bool align_here)
: PpToken(static_cast<PpTokenFlags>(k_begin
| (align_here ? k_align_here : 0)),
tk_viz_len, tk_len, tk_offset)
{}
static uint32_t alloc_size() { return sizeof(PpBeginToken); }
/** indent origin is the output column at this begin, not the
* running indent. @see PpState::begin_here()
**/
bool is_align_here() const { return (this->tk_flags() & k_align_here) != 0; }
/** running indent as of this begin; end() restores it.
*
* Restoring beats subtracting tk_offset(): an align-here begin
* REPLACES the running indent rather than adding to it, so a
* subtraction would leave the enclosing indent wrong once such a
* group closes.
**/
int32_t saved_indent() const { return saved_indent_; }
void set_saved_indent(int32_t x) { saved_indent_ = x; }
private:
int32_t saved_indent_ = 0;
};
class PpStringToken : public PpToken {
public:
using Span = xo::mm::span<const char>;
public:
PpStringToken(int32_t tk_viz_z,
uint32_t tk_size,
uint32_t tk_mem,
const char * tk_chars);
/** padded size in bytes for a PpStringToken instance
* with space for tk_size characters.
* Return value includes sizeof(PpStringToken) itself;
* @p tk_size does not.
**/
static uint32_t alloc_size(uint32_t tk_size);
uint32_t tk_mem() const { return tk_mem_; }
Span span() const { return Span(&(tk_chars_[0]),
&(tk_chars_[this->tk_len()])); }
Span mem_span() const { return Span(&(tk_chars_[0]),
&(tk_chars_[this->tk_mem()])); }
uint32_t alloc_size() const { return sizeof(PpStringToken) + tk_mem_; }
/** finalize string token in-place
* @p tk_viz_len token visible length
* @p tk_len token length (including non-visible chars)
* @p tk_mem Space actually used by tk_chars.
* (will round up for alignment reasons)
**/
void finalize_inplace(uint32_t tk_viz_len, uint32_t tk_len, uint32_t tk_mem) {
this->establish_size(tk_viz_len, tk_len);
this->tk_mem_ = tk_mem;
}
private:
/** amount of space used by tk_chars_[]. **/
uint32_t tk_mem_ = 0;
/** k_string: array of characters to print.
* Not used for k_begin|k_break|k_end.
*/
char tk_chars_[];
};
} /*namespace pp*/
} /*namespace xo*/
/* end PpToken.hpp */