summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/fud_assert.hpp13
-rw-r--r--include/fud_format.hpp293
-rw-r--r--include/fud_span.hpp16
-rw-r--r--include/fud_string_view.hpp16
-rw-r--r--include/fud_utf8.hpp2
5 files changed, 321 insertions, 19 deletions
diff --git a/include/fud_assert.hpp b/include/fud_assert.hpp
index ecfaa2f..6b21fdc 100644
--- a/include/fud_assert.hpp
+++ b/include/fud_assert.hpp
@@ -22,22 +22,9 @@
// #include <stacktrace>
#include <source_location>
-#include "fud_span.hpp"
namespace fud {
-constexpr std::size_t MAX_FILE_CHARS = 256;
-constexpr std::size_t MAX_FUNCTION_CHARS = 256;
-constexpr std::size_t BITS_PER_OCTAL = 3;
-constexpr auto MAX_LINE_CHARS = BITS_PER_OCTAL * sizeof(decltype(std::source_location{}.line())) + 3;
-constexpr std::size_t MAX_ASSERT_CHARS = 512 - MAX_LINE_CHARS;
-constexpr std::size_t ASSERT_MSG_SIZE = MAX_FILE_CHARS + MAX_LINE_CHARS + MAX_FUNCTION_CHARS + MAX_ASSERT_CHARS;
-
-void assertFormat(
- const char* assertion,
- std::source_location sourceLocation,
- Span<char, ASSERT_MSG_SIZE> buffer);
-
[[noreturn]] void assertFail(
const char* assertion,
std::source_location sourceLocation = std::source_location::current());
diff --git a/include/fud_format.hpp b/include/fud_format.hpp
new file mode 100644
index 0000000..8985faf
--- /dev/null
+++ b/include/fud_format.hpp
@@ -0,0 +1,293 @@
+/*
+ * 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_span.hpp"
+#include "fud_status.hpp"
+#include "fud_string_view.hpp"
+
+#include <format> // for std::format_string
+#include <cstdint>
+#include <optional>
+
+namespace fud {
+
+template <size_t Size>
+using CharSpan = Span<char, Size>;
+
+template <typename... Args>
+using FormatLiteral = std::format_string<Args...>;
+
+template <typename... Args, size_t Size>
+Result<size_t, FudStatus> format(CharSpan<Size> buffer, FormatLiteral<Args...> formatLiteral, Args&&... args);
+
+enum class FormatAlign : uint8_t {
+ Left,
+ Right,
+ Center
+};
+
+struct FormatFill {
+ FormatAlign align;
+ char fill;
+};
+
+enum class FormatSign : uint8_t {
+ Plus,
+ Minus,
+ Space
+};
+
+struct FormatSpec {
+ std::optional<FormatFill> fill;
+ std::optional<FormatSign> formatSign;
+ uint32_t minWidth;
+};
+
+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)
+{
+ 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;
+
+ return detail::formatHelper(buffer, formattedSize, formatView, std::forward<Args>(args)...);
+}
+
+namespace detail {
+
+#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; \
+
+constexpr bool findBracket(size_t& copyLength, StringView formatView)
+{
+ while (copyLength < formatView.m_length) {
+ if (formatView.m_data[copyLength] == '{') {
+ return true;
+ }
+ copyLength++;
+ }
+
+ return false;
+}
+
+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;
+ }
+
+ 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;
+ }
+
+ 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;
+ }
+
+ if (consumed) {
+ return formatHelper(buffer, formattedSize, formatView, std::forward<Args>(args)...);
+ }
+ }
+
+ 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)
+{
+ 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 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;
+}
+
+#undef FUDETAIL_ADVANCE_FORMAT
+
+} // namespace detail
+
+} // namespace fud
+
+#endif
diff --git a/include/fud_span.hpp b/include/fud_span.hpp
index e8c5704..cc693f8 100644
--- a/include/fud_span.hpp
+++ b/include/fud_span.hpp
@@ -43,6 +43,22 @@ struct Span {
return output;
}
+ template <typename U>
+ static Span make(Array<U, Size>& array) {
+ static_assert(std::convertible_to<U, T>);
+ Span<T, Size> output{};
+ output.m_data = array.data();
+ return output;
+ }
+
+ template <size_t ArraySize>
+ static Span makeCStringBuffer(Array<T, ArraySize>& array) {
+ static_assert(ArraySize > Size);
+ Span<T, Size> output{};
+ output.m_data = array.data();
+ return output;
+ }
+
T* m_data;
[[nodiscard]] constexpr size_t size() const
diff --git a/include/fud_string_view.hpp b/include/fud_string_view.hpp
index 4796003..7b4925e 100644
--- a/include/fud_string_view.hpp
+++ b/include/fud_string_view.hpp
@@ -15,23 +15,27 @@
* limitations under the License.
*/
-
#ifndef FUD_STRING_VIEW_HPP
#define FUD_STRING_VIEW_HPP
#include "fud_status.hpp"
#include "fud_utf8.hpp"
+#include <string_view>
+
namespace fud {
class String;
-class StringView {
- public:
+struct StringView {
constexpr StringView() noexcept = default;
+
constexpr StringView(const StringView& rhs) noexcept = default;
+
constexpr StringView(StringView&& rhs) noexcept = default;
+
constexpr ~StringView() noexcept = default;
+
constexpr StringView& operator=(const StringView& rhs) = default;
constexpr StringView& operator=(StringView&& rhs) = default;
@@ -40,11 +44,13 @@ class StringView {
}
StringView(size_t strLen, const char* strData) :
- m_length(strLen), // line break
+ m_length(strLen), // line break
m_data{reinterpret_cast<const utf8*>(strData)} // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
{
}
+ StringView(std::string_view rhs) noexcept : StringView(rhs.length(), rhs.data()) {}
+
explicit StringView(const String& fudString) noexcept;
[[nodiscard]] constexpr size_t length() const
@@ -85,8 +91,8 @@ class StringView {
FudStatus toDouble(double& number, size_t& strLen) const;
- private:
size_t m_length{0};
+
const utf8* m_data{nullptr};
};
diff --git a/include/fud_utf8.hpp b/include/fud_utf8.hpp
index 058e4f9..539e0f4 100644
--- a/include/fud_utf8.hpp
+++ b/include/fud_utf8.hpp
@@ -31,7 +31,7 @@ namespace fud {
using utf8 = unsigned char;
class String;
-class StringView;
+struct StringView;
constexpr utf8 ASCII_MASK = 0x7F;