// SPDX-License-Identifier: MIT
#pragma once
#include <cstdint>
#include <iosfwd>
/// \file Indentation.hh
/// \brief Step-based indentation tracker for code generators.
namespace fedem
{
namespace parser
{
/// \brief A small value type that tracks a current indentation width and a
/// step size, and streams itself as that many spaces.
///
/// `Indentation` is the code-generation side's counterpart to a text
/// editor's indent level. `right()` and `left()` move by whole steps;
/// `operator<<` writes the current width as spaces. It holds no stream and
/// owns no resources — copy it freely, keep one per `Generator`.
///
/// All operations are `noexcept`. `left()` saturates at zero and `right()`
/// saturates at the maximum of `uint_fast16_t` rather than wrapping.
///
/// \see https://cparse.fedem.eu/reference/indentation — reference manual page.
/// \see Generator
class Indentation final
{
public:
/// \brief Construct with a step size; the current indentation starts at zero.
/// \param step_size Columns per step. Defaults to #DEFAULT_STEPSIZE.
/// \see https://cparse.fedem.eu/reference/indentation-ctor
explicit Indentation( uint_fast16_t step_size = DEFAULT_STEPSIZE ) noexcept;
/// \brief Destructor. Trivial — `Indentation` owns nothing.
/// \see https://cparse.fedem.eu/reference/indentation-dtor
~Indentation( ) noexcept;
/// \brief Copy constructor. Copies both the step size and the current width.
/// \param object Instance to copy from.
Indentation( Indentation const& object ) noexcept;
/// \brief Copy assignment. Copies both the step size and the current width.
/// \param object Instance to copy from.
/// \return `*this`.
/// \see https://cparse.fedem.eu/reference/indentation-operator-assign
Indentation& operator=( Indentation const& object ) noexcept;
/// \brief Decrease the indentation by whole steps, saturating at zero.
/// \param step_size Number of steps to dedent. Defaults to 1.
/// \see https://cparse.fedem.eu/reference/indentation-left
void left( uint_fast16_t step_size = 1 ) noexcept;
/// \brief Increase the indentation by whole steps, saturating at the
/// maximum representable width.
/// \param step_size Number of steps to indent. Defaults to 1.
/// \see https://cparse.fedem.eu/reference/indentation-right
void right( uint_fast16_t step_size = 1 ) noexcept;
/// \brief Set the number of columns one step represents.
/// \param step_size New step size, in columns.
/// \note Does not rescale the current width; it changes what the next
/// `left()` / `right()` moves by.
/// \see https://cparse.fedem.eu/reference/indentation-set-step-size
void setStepSize( uint_fast16_t step_size ) noexcept;
/// \brief The number of columns one step represents.
/// \return The current step size, in columns.
/// \see https://cparse.fedem.eu/reference/indentation-get-step-size
uint_fast16_t getStepSize( ) const noexcept;
/// \brief Set the current indentation width directly.
/// \param indent New width, in columns (not steps).
/// \see https://cparse.fedem.eu/reference/indentation-set-indentation
void setIndentation( uint_fast16_t indent ) noexcept;
/// \brief The current indentation width.
/// \return The current width, in columns.
/// \see https://cparse.fedem.eu/reference/indentation-get-indentation
uint_fast16_t getIndentation( ) const noexcept;
/// \brief Set the current width back to zero and, optionally, change the
/// step size.
/// \param step_size New step size. Defaults to #DEFAULT_STEPSIZE.
/// \see https://cparse.fedem.eu/reference/indentation-reset
void reset( uint_fast16_t step_size = DEFAULT_STEPSIZE ) noexcept;
/// \brief Default step size used when none is supplied: two columns.
/// \see https://cparse.fedem.eu/reference/indentation-default-stepsize
static constexpr uint_fast16_t const DEFAULT_STEPSIZE = 2U;
protected:
uint_fast16_t stepSize; ///< Columns per step.
uint_fast16_t indent; ///< Current indentation width, in columns.
private:
Indentation( Indentation&& object ) noexcept = delete;
Indentation& operator=( Indentation&& object ) noexcept = delete;
};
/// \brief Write `object.getIndentation()` spaces to `stream`.
/// \param stream Destination stream.
/// \param object Indentation whose width is written.
/// \return `stream`, for chaining.
/// \see https://cparse.fedem.eu/reference/indentation-operator-shl
std::ostream& operator<<( std::ostream& stream, Indentation const& object );
} // end namespace parser
} // end namespace fedem