From bf81e34921e3e30b05313efbcf5c9fa839cb7c05 Mon Sep 17 00:00:00 2001 From: Dominick Allen Date: Sun, 22 Sep 2024 10:19:15 -0500 Subject: Initial commit. --- source/c_file.cpp | 60 +++++++++ source/libfud.cpp | 24 ++++ source/memory.cpp | 127 ++++++++++++++++++ source/string.cpp | 19 +++ source/utf8.cpp | 343 +++++++++++++++++++++++++++++++++++++++++++++++ source/utf8_iterator.cpp | 38 ++++++ 6 files changed, 611 insertions(+) create mode 100644 source/c_file.cpp create mode 100644 source/libfud.cpp create mode 100644 source/memory.cpp create mode 100644 source/string.cpp create mode 100644 source/utf8.cpp create mode 100644 source/utf8_iterator.cpp (limited to 'source') 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 + +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(destination); + const auto* sourcePtr = static_cast(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(lhs)[idx] - static_cast(rhs)[idx]; + if (localDifference != 0) { + *difference = localDifference; + return FudStatus::Success; + } + } + *difference = localDifference; + + return FudStatus::Success; +} + +Result 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::error(status); + } + + return Result::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(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(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 // 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(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 +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)(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(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(character))) { + constexpr uint8_t lowerA = 'a'; + constexpr uint8_t upperA = 'A'; + return static_cast(character - upperA) + lowerA; + } + return character; +} + +ExtUtf8* ext_lib_utf8_to_lower(ExtUtf8* character) +{ + if (character == nullptr) { + return character; + } + + static_cast(character->transformAscii([](Ascii& ascii) { + ascii = Ascii{ext_lib_char_to_lower(static_cast(ascii.asChar()))}; + })); + + return character; +} + +uint8_t ext_lib_char_to_upper(uint8_t character) +{ + if (ext_lib_char_is_lowercase(static_cast(character))) { + constexpr uint8_t lowerA = 'a'; + constexpr uint8_t upperA = 'A'; + return static_cast(character - lowerA) + upperA; + } + return character; +} + +ExtUtf8* ext_lib_utf8_to_upper(ExtUtf8* character) +{ + if (character == nullptr) { + return character; + } + + static_cast(character->transformAscii([](Ascii& ascii) { + ascii = Ascii{ext_lib_char_to_upper(static_cast(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 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 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 -- cgit v1.2.3