summaryrefslogtreecommitdiff
path: root/include/fud_format.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'include/fud_format.hpp')
-rw-r--r--include/fud_format.hpp362
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