diff options
Diffstat (limited to 'include/fud_format.hpp')
-rw-r--r-- | include/fud_format.hpp | 362 |
1 files changed, 133 insertions, 229 deletions
diff --git a/include/fud_format.hpp b/include/fud_format.hpp index 8985faf..ea32bd8 100644 --- a/include/fud_format.hpp +++ b/include/fud_format.hpp @@ -18,275 +18,179 @@ #ifndef FUD_FORMAT_HPP #define FUD_FORMAT_HPP -#include "fud_assert.hpp" +// #include "fud_assert.hpp" #include "fud_result.hpp" -#include "fud_span.hpp" #include "fud_status.hpp" #include "fud_string_view.hpp" +#include "fud_utf8.hpp" -#include <format> // for std::format_string #include <cstdint> #include <optional> +#include <variant> namespace fud { -template <size_t Size> -using CharSpan = Span<char, Size>; - -template <typename... Args> -using FormatLiteral = std::format_string<Args...>; +struct FormatAlign +{ + enum class Value : uint8_t + { + Left, + Right, + Center + }; + + constexpr static std::optional<FormatAlign> from(utf8 letter) + { + FormatAlign formatAlign; + switch (letter) { + case '<': + formatAlign.value = Value::Left; + break; + case '>': + formatAlign.value = Value::Right; + break; + case '^': + formatAlign.value = Value::Center; + break; + default: + return std::nullopt; + } -template <typename... Args, size_t Size> -Result<size_t, FudStatus> format(CharSpan<Size> buffer, FormatLiteral<Args...> formatLiteral, Args&&... args); + return formatAlign; + } -enum class FormatAlign : uint8_t { - Left, - Right, - Center + Value value; }; struct FormatFill { FormatAlign align; - char fill; + utf8 fill; + + constexpr static Result<std::optional<FormatFill>, FudStatus> parse(StringView formatView) { + // "{:A<X}" + using RetType = Result<std::optional<FormatFill>, FudStatus>; + if (formatView.length() < 3) { + return RetType::okay(std::nullopt); + } + + const auto* data = formatView.data(); + if (data[0] != 'A') { + return RetType::okay(std::nullopt); + } + + auto align = FormatAlign::from(data[1]); + if (!align.has_value()) { + return FudStatus::FormatInvalid; + } + + auto fill = data[2]; + if (!Ascii::valid(fill)) { + return FudStatus::Utf8Invalid; + } + + return RetType::okay(FormatFill{*align, fill}); + } }; -enum class FormatSign : uint8_t { +enum class FormatSign : uint8_t +{ Plus, Minus, Space }; -struct FormatSpec { - std::optional<FormatFill> fill; - std::optional<FormatSign> formatSign; - uint32_t minWidth; +enum class FormatStringType : uint8_t +{ + String, + Escaped, }; -namespace detail { - -template <typename Arg, typename... Args, size_t Size> -Result<size_t, FudStatus> formatHelper( - CharSpan<Size> buffer, - size_t formattedSize, - StringView formatView, - Arg&& arg, - Args&&... args); - -template <typename Arg, typename... Args, size_t Size> -Result<size_t, FudStatus> formatHelper( - CharSpan<Size> buffer, - size_t formattedSize, - StringView formatView, - Arg&& arg); - -template <size_t Size> -Result<size_t, FudStatus> formatHelper( - CharSpan<Size> buffer, - size_t formattedSize, - StringView formatView); - -} // namespace detail - -template <typename... Args, size_t Size> -Result<size_t, FudStatus> format(CharSpan<Size> buffer, FormatLiteral<Args...> formatLiteral, Args&&... args) +enum class FormatIntegerType : uint8_t { - static_assert(Size > 0); - - if (buffer.data() == nullptr) { - return FudStatus::NullPointer; - } - - StringView formatView{formatLiteral.get()}; - - if (formatView.length() == 0 || formatView.data()[0] == '\0') { - return 0U; - } - - size_t argCount = sizeof...(args); - static_cast<void>(argCount); - - size_t formattedSize = 0; + BinaryLower, + BinaryUpper, + Character, + Decimal, + Octal, + HexLower, + HexUpper, +}; - return detail::formatHelper(buffer, formattedSize, formatView, std::forward<Args>(args)...); -} +enum class FormatCharacterType : uint8_t +{ + BinaryLower, + BinaryUpper, + Character, + Decimal, + Octal, + HexLower, + HexUpper, +}; -namespace detail { +enum class FormatBoolType : uint8_t +{ + BinaryLower, + BinaryUpper, + Character, + Decimal, + Octal, + HexLower, + HexUpper, +}; -#define FUDETAIL_ADVANCE_FORMAT(FORMAT_VIEW, ADVANCE_BY) \ - fudAssert(ADVANCE_BY <= FORMAT_VIEW.m_length); \ - FORMAT_VIEW.m_length -= ADVANCE_BY; \ - FORMAT_VIEW.m_data += ADVANCE_BY; \ +enum class FormatFloatingType : uint8_t +{ + FloatHexLower, + FloatHexUpper, + ScientificLower, + ScientificUpper, + Fixed, + GeneralLower, + GeneralUpper +}; -constexpr bool findBracket(size_t& copyLength, StringView formatView) +enum class FormatPointerType : uint8_t { - while (copyLength < formatView.m_length) { - if (formatView.m_data[copyLength] == '{') { - return true; - } - copyLength++; - } + HexLower, + HexUpper +}; - return false; -} +using FormatType = std::variant< // break + std::monostate, + FormatStringType, + FormatIntegerType, + FormatCharacterType, + FormatBoolType, + FormatFloatingType, + FormatPointerType>; -template <size_t Size> -size_t copyRemaining( - CharSpan<Size> buffer, - size_t formattedSize, - StringView& formatView, - size_t copyLength) -{ - fudAssert(copyLength <= formatView.length()); - if (copyLength + formattedSize > Size) { - copyLength = Size - formattedSize; - } - auto copyResult = copyMem( - buffer.data() + formattedSize, - Size - formattedSize, - formatView.m_data, - copyLength); - fudAssert(copyResult == FudStatus::Success); - FUDETAIL_ADVANCE_FORMAT(formatView, copyLength); - return formattedSize + copyLength; -} - -template <typename Arg, size_t Size> -Result<size_t, FudStatus> handleSpec( - CharSpan<Size> buffer, - size_t formattedSize, - StringView& formatView, - Arg&& arg, - bool& consumed) -{ - fudAssert(formattedSize < Size); - fudAssert(formatView.length() > 1); - - if (formatView.m_data[1] == '{') { - consumed = false; - buffer[formattedSize] = '{'; - FUDETAIL_ADVANCE_FORMAT(formatView, 2); - return formattedSize + 1; - } +struct FormatSpec; +using FormatSpecResult = Result<FormatSpec, FudStatus>; - static_cast<void>(arg); - buffer[formattedSize] = 'X'; - formattedSize += 1; - size_t index = 0; - for (; index < formatView.m_length; ++index) { - if (formatView.m_data[index] == '}') { - break; - } - } - FUDETAIL_ADVANCE_FORMAT(formatView, index + 1); - return formattedSize; -} - -template <typename Arg, typename... Args, size_t Size> -Result<size_t, FudStatus> formatHelper( - CharSpan<Size> buffer, - size_t formattedSize, - StringView formatView, - Arg&& arg, - Args&&... args) -{ - while (formattedSize < Size) { - size_t copyLength = 0; - auto found = findBracket(copyLength, formatView); - formattedSize = copyRemaining(buffer, formattedSize, formatView, copyLength); - fudAssert(formattedSize <= Size); - if (!found || formattedSize == Size) { - return formattedSize; - } +struct FormatSpec { + size_t width; + size_t precision; + FormatFill fill; + FormatSign formatSign; - bool consumed = false; - auto specResult = handleSpec(buffer, formattedSize, formatView, std::forward<Arg>(arg), consumed); - formattedSize = M_TakeOrReturn(specResult); - fudAssert(formattedSize <= Size); - if (formattedSize == Size) { - return formattedSize; - } + FormatType formatType; - if (consumed) { - return formatHelper(buffer, formattedSize, formatView, std::forward<Args>(args)...); - } - } + bool hasWidth; + bool takesWidth; - return formattedSize; -} + bool hasPrecision; + bool takesPrecision; -template <typename Arg, typename... Args, size_t Size> -Result<size_t, FudStatus> formatHelper( - CharSpan<Size> buffer, - size_t formattedSize, - StringView formatView, - Arg&& arg) -{ - while (formattedSize < Size) { - size_t copyLength = 0; - auto found = findBracket(copyLength, formatView); - formattedSize = copyRemaining(buffer, formattedSize, formatView, copyLength); - fudAssert(formattedSize <= Size); - if (!found || formattedSize == Size) { - return formattedSize; - } + bool hasFill; - bool consumed = false; - auto specResult = handleSpec(buffer, formattedSize, formatView, std::forward<Arg>(arg), consumed); - formattedSize = M_TakeOrReturn(specResult); - if (consumed) { - return formatHelper(buffer, formattedSize, formatView); - } - } - return formattedSize; -} - -template <size_t Size> -Result<size_t, FudStatus> formatHelper( - CharSpan<Size> buffer, - size_t formattedSize, - StringView formatView) -{ - size_t index = 0; - while (formattedSize < Size && formatView.m_length > 0) { - while (index < formatView.m_length && formattedSize + index < Size) { - if (formatView.m_data[index] == '{') { - break; - } - index++; - } - bool isBracket{false}; - if (index + 1 < formatView.m_length && formattedSize + index + 1 < Size) { - if (formatView.m_data[index] == '{') { - isBracket = true; - index++; - } - } - auto copyResult = copyMem( - buffer.data() + formattedSize, - Size - formattedSize, - formatView.m_data, - index); - formattedSize += index; - formatView.m_length -= index; - formatView.m_data += index; - if (isBracket) { - index = 0; - if (formatView.m_length > 0) { - formatView.m_length--; - formatView.m_data++; - } - if (formattedSize < Size) { - buffer.data()[formattedSize] = 'X'; - formattedSize++; - } - } - } - return formattedSize; -} + bool hasFormatSign; + + bool alternateForm; -#undef FUDETAIL_ADVANCE_FORMAT + bool leadingZero; -} // namespace detail + static Result<FormatSpec, FudStatus> make(StringView& formatView, size_t specIndex); +}; } // namespace fud |