summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/c_file.cpp60
-rw-r--r--source/libfud.cpp24
-rw-r--r--source/memory.cpp127
-rw-r--r--source/string.cpp19
-rw-r--r--source/utf8.cpp343
-rw-r--r--source/utf8_iterator.cpp38
6 files changed, 611 insertions, 0 deletions
diff --git a/source/c_file.cpp b/source/c_file.cpp
new file mode 100644
index 0000000..f64e024
--- /dev/null
+++ b/source/c_file.cpp
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+#include "c_file.hpp"
+
+namespace fud {
+
+CBinaryFile::CBinaryFile(const std::string& filename, CFileMode mode)
+ : m_filename{filename},
+ m_mode{CBinaryFileModeFromFlags(mode)},
+ m_modeFlags{mode}
+{
+}
+
+CBinaryFile::CBinaryFile(const std::string& filename, CFileMode mode, const std::string& extraFlags)
+ : m_filename{filename},
+ m_extraFlags{extraFlags},
+ m_mode{std::string(CBinaryFileModeFromFlags(mode) + extraFlags)},
+ m_modeFlags{mode}
+{
+}
+
+CBinaryFile::~CBinaryFile() {
+ close();
+}
+
+FileResult CBinaryFile::open()
+{
+ m_file = fopen(m_filename.c_str(), m_mode.c_str());
+ return m_file != nullptr ? FileResult::Success : FileResult::Error;
+}
+
+void CBinaryFile::close()
+{
+ if (m_file != nullptr) {
+ fclose(m_file);
+ m_file = nullptr;
+ }
+}
+
+const FILE* CBinaryFile::file() const
+{
+ return m_file;
+}
+
+} // namespace fud
diff --git a/source/libfud.cpp b/source/libfud.cpp
new file mode 100644
index 0000000..fa0e3a0
--- /dev/null
+++ b/source/libfud.cpp
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+#include "libfud.hpp"
+
+namespace fud {
+
+void fud() {
+}
+
+} // namespace fud
diff --git a/source/memory.cpp b/source/memory.cpp
new file mode 100644
index 0000000..9f5d358
--- /dev/null
+++ b/source/memory.cpp
@@ -0,0 +1,127 @@
+/*
+ * ExtLib
+ * 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.
+ */
+
+#include "memory.hpp"
+
+#include <cstdint>
+
+namespace fud {
+
+FudStatus copyMem(void* destination, size_t destination_size, const void* source, size_t count)
+{
+ if (anyAreNull(destination, source)) {
+ return FudStatus::NullPointer;
+ }
+
+ if (destination_size < count) {
+ return FudStatus::InvalidInput;
+ }
+
+ auto* destPtr = static_cast<uint8_t*>(destination);
+ const auto* sourcePtr = static_cast<const uint8_t*>(source);
+ for (decltype(destination_size) idx = 0; idx < count; ++idx) {
+ destPtr[idx] = sourcePtr[idx];
+ }
+
+ return FudStatus::Success;
+}
+
+FudStatus compareMem(const void* lhs, size_t destination_size, const void* rhs, size_t count, int* difference)
+{
+ if (anyAreNull(lhs, rhs, difference)) {
+ return FudStatus::NullPointer;
+ }
+
+ if (destination_size < count) {
+ return FudStatus::InvalidInput;
+ }
+
+ int localDifference = 0;
+ // NOLINTBEGIN(readability-magic-numbers)
+ for (decltype(destination_size) idx = 0; idx < count; idx++) {
+ localDifference = static_cast<const uint8_t*>(lhs)[idx] - static_cast<const uint8_t*>(rhs)[idx];
+ if (localDifference != 0) {
+ *difference = localDifference;
+ return FudStatus::Success;
+ }
+ }
+ *difference = localDifference;
+
+ return FudStatus::Success;
+}
+
+Result<int, FudStatus> compareMem(const void* lhs, size_t destination_size, const void* rhs, size_t count)
+{
+ int difference = 0;
+ auto status = compareMem(lhs, destination_size, rhs, count, &difference);
+ if (status != FudStatus::Success)
+ {
+ return Result<int, FudStatus>::error(status);
+ }
+
+ return Result<int, FudStatus>::okay(difference);
+}
+
+FudStatus setMemory(void* data, size_t dataSize, uint8_t pattern, size_t count)
+{
+ if (data == nullptr)
+ {
+ return FudStatus::NullPointer;
+ }
+
+ if (count > dataSize)
+ {
+ return FudStatus::InvalidInput;
+ }
+
+ for (size_t idx = 0; idx < count; ++idx)
+ {
+ static_cast<uint8_t*>(data)[idx] = pattern;
+ }
+
+ return FudStatus::Success;
+}
+
+FudStatus setMemory(
+ void* data,
+ size_t collectionCount,
+ size_t eltOffset,
+ size_t eltSize,
+ uint8_t pattern,
+ size_t eltCount)
+{
+ if (eltOffset >= collectionCount)
+ {
+ return FudStatus::InvalidInput;
+ }
+
+ if (eltOffset + eltCount > collectionCount)
+ {
+ return FudStatus::InvalidInput;
+ }
+
+ auto dataSize = collectionCount * eltSize;
+ auto byteOffset = eltOffset * eltSize;
+ auto byteCount = eltCount * eltSize;
+
+ auto remainingSize = dataSize - byteOffset;
+
+ auto* offsetData = static_cast<uint8_t*>(data) + byteOffset;
+ return setMemory(offsetData, remainingSize, pattern, byteCount);
+}
+
+} // namespace fud
diff --git a/source/string.cpp b/source/string.cpp
new file mode 100644
index 0000000..a121418
--- /dev/null
+++ b/source/string.cpp
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+
+
+#include "string.hpp"
diff --git a/source/utf8.cpp b/source/utf8.cpp
new file mode 100644
index 0000000..c94ac1f
--- /dev/null
+++ b/source/utf8.cpp
@@ -0,0 +1,343 @@
+/*
+ * 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.
+ */
+
+#include "utf8.hpp"
+
+#include "string.hpp"
+
+#include <new> // IWYU pragma: keep - this is for placement new overloads.
+
+namespace fud {
+
+ExtUtf8 ExtUtf8::fromString(const String& fudString, size_t index) noexcept
+{
+ if (!fudString.valid()) {
+ return invalidAscii();
+ }
+
+
+ return fromStringView(StringView{fudString}, index);
+}
+
+ExtUtf8 ExtUtf8::fromStringView(const StringView& view, size_t index) noexcept
+{
+ return fromStringView(StringView{view}, index);
+}
+
+ExtUtf8 ExtUtf8::fromStringView(StringView&& view, size_t index) noexcept
+{
+ auto len = view.length();
+ const auto* data = view.data();
+ if (data == nullptr) {
+ return invalidAscii();
+ }
+
+ ExtUtf8 localChar{Ascii{data[index]}};
+ if (localChar.valid()) {
+ return localChar;
+ }
+
+ if (index + 1 < len) {
+ localChar.m_variant = Utf82Byte{data[index], data[index + 1]};
+ }
+ if (localChar.valid()) {
+ return localChar;
+ }
+
+ if (index + 2 < len) {
+ localChar.m_variant = Utf83Byte{data[index], data[index + 1], data[index + 2]};
+ }
+ if (localChar.valid()) {
+ return localChar;
+ }
+
+ if (index + 3 < len) {
+ localChar.m_variant = Utf84Byte{data[index], data[index + 1], data[index + 2], data[index + 3]};
+ }
+ if (localChar.valid()) {
+ return localChar;
+ }
+
+ return invalidAscii();
+}
+
+bool ext_lib_char_is_ascii(char character)
+{
+ return static_cast<uint8_t>(character & ~ASCII_MASK) == 0;
+}
+
+FudStatus ext_lib_utf8_is_ascii(ExtUtf8* character, bool* isAscii)
+{
+ if (anyAreNull(character, isAscii)) {
+ return FudStatus::NullPointer;
+ }
+
+ *isAscii = character->getType() == ExtUtf8Type::Ascii && character->valid();
+
+ return FudStatus::Success;
+}
+
+namespace impl {
+
+/* Assumes that predicate is not a null pointer! */
+template <typename Predicate>
+inline FudStatus isAsciiPredicate(ExtUtf8* character, bool* pred, Predicate&& predicate)
+{
+ if (anyAreNull(character, pred)) {
+ return FudStatus::NullPointer;
+ }
+
+ auto maybeAscii = character->getAscii();
+ if (!maybeAscii.has_value()) {
+ return FudStatus::InvalidInput;
+ }
+
+ auto asciiChar = *maybeAscii;
+ *pred = std::forward<Predicate>(predicate)(asciiChar.asChar());
+
+ return FudStatus::Success;
+}
+
+} // namespace impl
+
+bool ext_lib_char_is_alphanumeric(char character)
+{
+ if (!ext_lib_char_is_ascii(character)) {
+ return false;
+ }
+
+ if (ext_lib_char_is_alpha(character)) {
+ return true;
+ }
+
+ return ext_lib_char_is_digit(character);
+}
+
+FudStatus ext_lib_utf8_is_alphanumeric(ExtUtf8* character, bool* pred)
+{
+ return impl::isAsciiPredicate(character, pred, ext_lib_char_is_alphanumeric);
+}
+
+bool ext_lib_char_is_alpha(char character)
+{
+ if (!ext_lib_char_is_ascii(character)) {
+ return false;
+ }
+
+ if (ext_lib_char_is_uppercase(character)) {
+ return true;
+ }
+
+ return ext_lib_char_is_lowercase(character);
+}
+
+FudStatus ext_lib_utf8_is_alpha(ExtUtf8* character, bool* pred)
+{
+ return impl::isAsciiPredicate(character, pred, ext_lib_char_is_alpha);
+}
+
+bool ext_lib_char_is_lowercase(char character)
+{
+ if (!ext_lib_char_is_ascii(character)) {
+ return false;
+ }
+
+ return 'a' <= character && character <= 'z';
+}
+
+FudStatus ext_lib_utf8_is_lowercase(ExtUtf8* character, bool* pred)
+{
+ return impl::isAsciiPredicate(character, pred, ext_lib_char_is_lowercase);
+}
+
+bool ext_lib_char_is_uppercase(char character)
+{
+ if (!ext_lib_char_is_ascii(character)) {
+ return false;
+ }
+
+ return 'A' <= character && character <= 'Z';
+}
+
+FudStatus ext_lib_utf8_is_uppercase(ExtUtf8* character, bool* pred)
+{
+ return impl::isAsciiPredicate(character, pred, ext_lib_char_is_uppercase);
+}
+
+bool ext_lib_char_is_digit(char character)
+{
+ if (!ext_lib_char_is_ascii(character)) {
+ return false;
+ }
+
+ return '0' <= character && character <= '9';
+}
+
+FudStatus ext_lib_utf8_is_digit(ExtUtf8* character, bool* pred)
+{
+ return impl::isAsciiPredicate(character, pred, ext_lib_char_is_digit);
+}
+
+bool ext_lib_char_is_hex_digit(char character)
+{
+ if (!ext_lib_char_is_ascii(character)) {
+ return false;
+ }
+
+ return ('0' <= character && character <= '9') || ('a' <= character && character <= 'f') ||
+ ('A' <= character && character <= 'F');
+}
+
+FudStatus ext_lib_utf8_is_hex_digit(ExtUtf8* character, bool* pred)
+{
+ return impl::isAsciiPredicate(character, pred, ext_lib_char_is_hex_digit);
+}
+
+bool ext_lib_char_is_control(char character)
+{
+ if (!ext_lib_char_is_ascii(character)) {
+ return false;
+ }
+
+ constexpr char maxControlChar = 0x1F;
+ constexpr const char deleteChar = 0x7F;
+ return ((static_cast<uint8_t>(character) <= maxControlChar)) || character == deleteChar;
+}
+
+FudStatus ext_lib_utf8_is_control(ExtUtf8* character, bool* pred)
+{
+ return impl::isAsciiPredicate(character, pred, ext_lib_char_is_control);
+}
+
+bool ext_lib_char_is_graphical(char character)
+{
+ if (!ext_lib_char_is_ascii(character)) {
+ return false;
+ }
+
+ return ext_lib_char_is_alphanumeric(character) || ext_lib_char_is_punctuation(character);
+}
+
+FudStatus ext_lib_utf8_is_graphical(ExtUtf8* character, bool* pred)
+{
+ return impl::isAsciiPredicate(character, pred, ext_lib_char_is_graphical);
+}
+
+bool ext_lib_char_is_space(char character)
+{
+ if (!ext_lib_char_is_ascii(character)) {
+ return false;
+ }
+
+ return character == ' ' || character == '\t' || character == '\n' || character == '\r' || character == '\v';
+}
+
+FudStatus ext_lib_utf8_is_space(ExtUtf8* character, bool* pred)
+{
+ return impl::isAsciiPredicate(character, pred, ext_lib_char_is_space);
+}
+
+bool ext_lib_char_is_blank(char character)
+{
+ if (!ext_lib_char_is_ascii(character)) {
+ return false;
+ }
+
+ return character == ' ' || character == '\t';
+}
+
+FudStatus ext_lib_utf8_is_blank(ExtUtf8* character, bool* pred)
+{
+ return impl::isAsciiPredicate(character, pred, ext_lib_char_is_blank);
+}
+
+bool ext_lib_char_is_printable(char character)
+{
+ if (!ext_lib_char_is_ascii(character)) {
+ return false;
+ }
+
+ return (character >= ' ' && character <= '~');
+}
+
+FudStatus ext_lib_utf8_is_printable(ExtUtf8* character, bool* pred)
+{
+ return impl::isAsciiPredicate(character, pred, ext_lib_char_is_printable);
+}
+
+bool ext_lib_char_is_punctuation(char character)
+{
+ if (!ext_lib_char_is_ascii(character)) {
+ return false;
+ }
+
+ return (character >= '!' && character <= '/') || (character >= ':' && character <= '@') ||
+ (character >= '[' && character <= '`') || (character >= '{' && character <= '~');
+}
+
+FudStatus ext_lib_utf8_is_punctuation(ExtUtf8* character, bool* pred)
+{
+ return impl::isAsciiPredicate(character, pred, ext_lib_char_is_punctuation);
+}
+
+uint8_t ext_lib_char_to_lower(uint8_t character)
+{
+ if (ext_lib_char_is_uppercase(static_cast<char>(character))) {
+ constexpr uint8_t lowerA = 'a';
+ constexpr uint8_t upperA = 'A';
+ return static_cast<uint8_t>(character - upperA) + lowerA;
+ }
+ return character;
+}
+
+ExtUtf8* ext_lib_utf8_to_lower(ExtUtf8* character)
+{
+ if (character == nullptr) {
+ return character;
+ }
+
+ static_cast<void>(character->transformAscii([](Ascii& ascii) {
+ ascii = Ascii{ext_lib_char_to_lower(static_cast<uint8_t>(ascii.asChar()))};
+ }));
+
+ return character;
+}
+
+uint8_t ext_lib_char_to_upper(uint8_t character)
+{
+ if (ext_lib_char_is_lowercase(static_cast<char>(character))) {
+ constexpr uint8_t lowerA = 'a';
+ constexpr uint8_t upperA = 'A';
+ return static_cast<uint8_t>(character - lowerA) + upperA;
+ }
+ return character;
+}
+
+ExtUtf8* ext_lib_utf8_to_upper(ExtUtf8* character)
+{
+ if (character == nullptr) {
+ return character;
+ }
+
+ static_cast<void>(character->transformAscii([](Ascii& ascii) {
+ ascii = Ascii{ext_lib_char_to_upper(static_cast<uint8_t>(ascii.asChar()))};
+ }));
+
+ return character;
+}
+
+} // namespace ext_lib
diff --git a/source/utf8_iterator.cpp b/source/utf8_iterator.cpp
new file mode 100644
index 0000000..e439687
--- /dev/null
+++ b/source/utf8_iterator.cpp
@@ -0,0 +1,38 @@
+#include "utf8_iterator.hpp"
+
+namespace fud {
+
+std::optional<ExtUtf8> Utf8Iterator::peek() const
+{
+ if (m_index >= m_view.length()) {
+ return std::nullopt;
+ }
+
+ auto utf8 = ExtUtf8::fromStringView(m_view, m_index);
+
+ if (!utf8.valid()) {
+ return std::nullopt;
+ }
+
+ return utf8;
+}
+
+std::optional<ExtUtf8> Utf8Iterator::next()
+{
+ if (m_index >= m_view.length()) {
+ m_index = m_view.length();
+ return std::nullopt;
+ }
+
+ auto utf8 = ExtUtf8::fromStringView(m_view, m_index);
+
+ if (!utf8.valid()) {
+ m_index = m_view.length();
+ return std::nullopt;
+ }
+
+ m_index += utf8.size();
+ return utf8;
+}
+
+} // namespace fud