/* * libfud * Copyright 2024 Dominick Allen * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef FUD_FORMAT_HPP #define FUD_FORMAT_HPP // #include "fud_assert.hpp" #include "fud_result.hpp" #include "fud_status.hpp" #include "fud_string_view.hpp" #include "fud_option.hpp" #include "fud_utf8.hpp" #include #include #include namespace fud { struct FormatAlign { enum class Value : utf8 { Left = '<', Right = '>', Center = '^', Default = std::numeric_limits::max() }; constexpr static FormatAlign makeDefault() noexcept { return {Value::Default}; } constexpr static Option 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 NullOpt; } return formatAlign; } Value operator()() const { return value; } Value value; }; struct FormatFill { FormatAlign align; utf8 fill; constexpr static FormatFill make() noexcept { return FormatFill {FormatAlign::makeDefault(), ' '}; } constexpr static Result, FudStatus> make(StringView formatView, size_t& length) noexcept { using RetType = Result, FudStatus>; if (formatView.length() < 1) { return RetType::okay(NullOpt); } const auto* data = formatView.data(); auto align1 = FormatAlign::from(data[0]); decltype(align1) align2 = NullOpt; if (formatView.length() > 1) { align2 = FormatAlign::from(data[1]); } if (align2.hasValue()) { length = 2; auto fill = data[0]; if (not Ascii::valid(fill)) { return FudStatus::Utf8Invalid; } if (fill == '{' || fill == '}') { return FudStatus::FormatInvalid; } return RetType::okay(FormatFill{std::move(align2).value(), data[0]}); } if (align1.hasValue()) { length = 1; return RetType::okay(FormatFill{std::move(align1).value(), ' '}); } return RetType::okay(NullOpt); } }; enum class FormatSign : uint8_t { Plus = '+', Minus = '-', Space = ' ', Default = std::numeric_limits::max() }; enum class FormatStringType : uint8_t { String, Escaped, }; enum class FormatIntegerType : uint8_t { BinaryLower, BinaryUpper, Character, Decimal, Octal, HexLower, HexUpper, }; enum class FormatCharacterType : uint8_t { BinaryLower, BinaryUpper, Character, Decimal, Octal, HexLower, HexUpper, }; enum class FormatBoolType : uint8_t { BinaryLower, BinaryUpper, Character, Decimal, Octal, HexLower, HexUpper, }; enum class FormatFloatingType : uint8_t { FloatHexLower, FloatHexUpper, ScientificLower, ScientificUpper, Fixed, GeneralLower, GeneralUpper }; enum class FormatPointerType : uint8_t { HexLower, HexUpper }; /* using FormatType = std::variant< // break std::monostate, FormatStringType, FormatIntegerType, FormatCharacterType, FormatBoolType, FormatFloatingType, FormatPointerType>; */ enum class FormatType : utf8 { Unspecified = '\0', String = 's', Escaped = '?', BinaryLower = 'b', BinaryUpper = 'B', Character = 'c', Decimal = 'd', Octal = 'o', HexLower = 'x', HexUpper = 'X', FloatHexLower = 'a', FloatHexUpper = 'A', ScientificLower = 'e', ScientificUpper = 'E', FixedLower = 'f', FixedUpper = 'F', GeneralLower = 'g', GeneralUpper = 'G', }; struct FormatSpec; using FormatSpecResult = Result; struct FormatSpec { static constexpr uint32_t widthUnspecified = std::numeric_limits::max(); static constexpr uint32_t precisionUnspecified = std::numeric_limits::max(); static constexpr uint16_t positionUnspecified = std::numeric_limits::max(); static constexpr utf8 openBracket = '{'; static constexpr utf8 closeBracket = '}'; static constexpr utf8 formatTypeUnspecified = std::numeric_limits::max(); static constexpr utf8 localeChar = 'L'; uint32_t width{widthUnspecified}; uint32_t precision{precisionUnspecified}; uint16_t position{positionUnspecified}; FormatFill fill{FormatFill::make()}; FormatSign formatSign{FormatSign::Default}; FormatType formatType{}; bool takesWidth{false}; bool takesPrecision{false}; bool alternateForm{false}; bool leadingZero{false}; bool hasLocale{false}; static Result make(StringView formatView, size_t& specLength); }; } // namespace fud #endif