summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorDominick Allen <djallen@librehumanitas.org>2024-10-23 13:21:10 -0500
committerDominick Allen <djallen@librehumanitas.org>2024-10-23 13:21:10 -0500
commit5cc7cbc3704ec255eb5d0ac53b2cc0fcb1221d63 (patch)
tree169d4d2d8dffe014851712e31a55036deb0c7c0c /source
parentb2dbcb55e2832c373fecb4033a3ed77e5dbc77aa (diff)
String conversion and parsing format spec.
Diffstat (limited to 'source')
-rw-r--r--source/fud_assert.cpp1
-rw-r--r--source/fud_format.cpp515
-rw-r--r--source/fud_string.cpp2
-rw-r--r--source/fud_string_convert.cpp110
-rw-r--r--source/fud_string_view.cpp701
-rw-r--r--source/fud_utf8.cpp207
6 files changed, 775 insertions, 761 deletions
diff --git a/source/fud_assert.cpp b/source/fud_assert.cpp
index 3df6734..ccc90a5 100644
--- a/source/fud_assert.cpp
+++ b/source/fud_assert.cpp
@@ -1,6 +1,7 @@
#include "fud_assert.hpp"
// #include "fud_array.hpp"
+// #include "fud_format.hpp"
#include <climits>
#include <cstdio>
diff --git a/source/fud_format.cpp b/source/fud_format.cpp
index ab1bb4f..04e611e 100644
--- a/source/fud_format.cpp
+++ b/source/fud_format.cpp
@@ -1,14 +1,515 @@
-// #include "fud_format.hpp"
+#include "fud_format.hpp"
+
+#include "fud_string_convert.hpp"
+#include "fud_utf8.hpp"
namespace fud {
-/*
-Result<FormatSpec, FudStatus> FormatSpec::make(StringView view, size_t& length)
+namespace impl {
+
+Result<size_t, FudStatus> preScanSpec(StringView formatView, FormatSpec& spec, bool& hasPosition, bool& hasColon);
+
+FudStatus getPosition(StringView& formatView, FormatSpec& spec, bool& hasPosition);
+
+FudStatus getFill(StringView& formatView, FormatSpec& spec);
+
+FudStatus getSpecialOpts(StringView& formatView, FormatSpec& spec);
+
+FudStatus getWidth(StringView& formatView, FormatSpec& spec);
+
+FudStatus getPrecision(StringView& formatView, FormatSpec& spec);
+
+FudStatus getFormatSign(StringView& formatView, FormatSpec& spec);
+
+} // namespace impl
+
+Result<FormatSpec, FudStatus> FormatSpec::make(StringView formatView, size_t& specLength)
+{
+ static_cast<void>(formatView);
+ static_cast<void>(specLength);
+
+ if (formatView[0] != FormatSpec::openBracket) {
+ return FudStatus::ArgumentInvalid;
+ }
+
+ auto hasEnded = [](StringView& view) {
+ fudAssert(view.length() > 0);
+ return view[0] == FormatSpec::closeBracket;
+ };
+
+ FormatSpec spec{};
+ size_t length = 1;
+
+ formatView.advanceUnsafe();
+
+ bool hasPosition{false};
+ bool hasColon{false};
+ auto lengthResult = impl::preScanSpec(formatView, spec, hasPosition, hasColon);
+ if (lengthResult.isError()) {
+ return lengthResult.takeError();
+ }
+
+ length += lengthResult.takeOkay();
+ if (length < 1) {
+ return FudStatus::FormatInvalid;
+ }
+ specLength = length;
+
+ auto status = impl::getPosition(formatView, spec, hasPosition);
+ if (status != FudStatus::Success) {
+ return status;
+ }
+
+ // check early ending
+
+ if (!hasColon) {
+ if (hasEnded(formatView)) {
+ return spec;
+ }
+ return FudStatus::FormatInvalid;
+ }
+
+ // check validity for being non-default spec and advance
+
+ if (formatView[0] != ':') {
+ return FudStatus::FormatInvalid;
+ }
+
+ formatView.advanceUnsafe();
+ if (hasEnded(formatView)) {
+ return spec;
+ }
+
+ // Spec
+
+ status = impl::getFill(formatView, spec);
+ if (status != FudStatus::Success) {
+ return status;
+ }
+
+ if (hasEnded(formatView)) {
+ return spec;
+ }
+
+ // sign, alternate, leading zero
+
+ status = impl::getSpecialOpts(formatView, spec);
+ if (status != FudStatus::Success) {
+ return status;
+ }
+
+ if (hasEnded(formatView)) {
+ return spec;
+ }
+
+ // Width
+
+ status = impl::getWidth(formatView, spec);
+ if (status != FudStatus::Success) {
+ return status;
+ }
+
+ if (hasEnded(formatView)) {
+ return spec;
+ }
+
+ // Precision
+
+ status = impl::getPrecision(formatView, spec);
+ if (status != FudStatus::Success) {
+ return status;
+ }
+
+ if (hasEnded(formatView)) {
+ return spec;
+ }
+
+ // Locale
+
+ if (formatView[0] == FormatSpec::localeChar) {
+ spec.hasLocale = true;
+ formatView.advanceUnsafe();
+ }
+
+ if (hasEnded(formatView)) {
+ return spec;
+ }
+
+ // Format Sign
+ status = impl::getFormatSign(formatView, spec);
+ if (status != FudStatus::Success) {
+ return status;
+ }
+
+ if (!hasEnded(formatView)) {
+ return FudStatus::FormatInvalid;
+ }
+
+ return spec;
+}
+
+namespace impl {
+
+Result<size_t, FudStatus> preScanSpec(StringView formatView, FormatSpec& spec, bool& hasPosition, bool& hasColon)
+{
+ int nesting = 0;
+ uint32_t captureGroups = 0;
+ size_t index = 0;
+ hasColon = false;
+ while (index < formatView.length() && (formatView[index] != FormatSpec::closeBracket || nesting > 0)) {
+ auto letter = formatView[index];
+ bool isDigit = classify::isDigit(static_cast<char>(letter));
+ bool priorDot = index > 0 && formatView[index - 1] == '.';
+ bool takesWidth = not spec.takesWidth and not priorDot;
+ bool takesPrecision = not spec.takesPrecision and priorDot;
+ switch (letter) {
+ case FormatSpec::openBracket:
+ if (not hasColon) {
+ return FudStatus::FormatInvalid;
+ }
+ if (takesWidth) {
+ spec.takesWidth = true;
+ } else if (takesPrecision) {
+ spec.takesPrecision = true;
+ } else {
+ return FudStatus::FormatInvalid;
+ }
+ nesting++;
+ captureGroups++;
+ break;
+ case FormatSpec::closeBracket:
+ nesting--;
+ break;
+ case ':':
+ hasColon = true;
+ break;
+ case '.':
+ break;
+ case 'L':
+ spec.hasLocale = true;
+ break;
+ default:
+ if (not hasColon and isDigit) {
+ hasPosition = true;
+ }
+ break;
+ }
+
+ if (nesting > 1) {
+ return FudStatus::FormatInvalid;
+ }
+
+ index++;
+ }
+
+ if (nesting != 0 || captureGroups > 2 || index >= formatView.length() ||
+ formatView[index] != FormatSpec::closeBracket) {
+ return FudStatus::FormatInvalid;
+ }
+
+ return index + 1U;
+}
+
+FudStatus getPosition(StringView& formatView, FormatSpec& spec, bool& hasPosition)
{
- static_cast<void>(view);
- static_cast<void>(length);
- return FudStatus::NotImplemented;
+ if (hasPosition) {
+ auto positionResult{fromString<decltype(spec.position)>(formatView, Radix::Decimal)};
+ if (positionResult.isError()) {
+ return positionResult.takeError();
+ }
+ auto positionValue{positionResult.takeOkay()};
+ spec.position = positionValue.value;
+ auto advanceStatus = formatView.advance(positionValue.nextIndex);
+ if (!advanceStatus) {
+ return FudStatus::Failure;
+ }
+ }
+
+ return FudStatus::Success;
}
-*/
+
+FudStatus getFill(StringView& formatView, FormatSpec& spec)
+{
+ Option<FormatFill> fillOpt = NullOpt;
+ if (formatView[0] != FormatSpec::openBracket) {
+ size_t fillLength = 0;
+ auto fillResult = FormatFill::make(formatView, fillLength);
+ if (fillResult.isError()) {
+ return fillResult.takeError();
+ }
+ fillOpt = fillResult.takeOkay();
+ formatView.advanceUnsafe(fillLength);
+ }
+ spec.fill = fillOpt.valueOr(FormatFill::make());
+ return FudStatus::Success;
+}
+
+FudStatus getSpecialOpts(StringView& formatView, FormatSpec& spec)
+{
+ if (formatView.length() < 1) {
+ return FudStatus::ArgumentInvalid;
+ }
+
+ bool done = false;
+ switch (formatView[0]) {
+ case static_cast<utf8>(FormatSign::Plus):
+ spec.formatSign = FormatSign::Plus;
+ break;
+ case static_cast<utf8>(FormatSign::Minus):
+ spec.formatSign = FormatSign::Minus;
+ break;
+ case static_cast<utf8>(FormatSign::Space):
+ spec.formatSign = FormatSign::Space;
+ break;
+ case '#':
+ spec.alternateForm = true;
+ break;
+ case '0':
+ spec.leadingZero = true;
+ done = true;
+ break;
+ default:
+ return FudStatus::Success;
+ }
+
+ formatView.advanceUnsafe();
+ if (done || formatView.length() < 1) {
+ return FudStatus::Success;
+ }
+
+ switch (formatView[0]) {
+ case '#':
+ if (spec.alternateForm) {
+ return FudStatus::FormatInvalid;
+ }
+ spec.alternateForm = true;
+ break;
+ case '0':
+ spec.leadingZero = true;
+ done = true;
+ break;
+ default:
+ return FudStatus::Success;
+ }
+
+ formatView.advanceUnsafe();
+ if (done || formatView.length() < 1) {
+ return FudStatus::Success;
+ }
+
+ if (formatView[0] == '0') {
+ spec.leadingZero = true;
+ formatView.advanceUnsafe();
+ }
+
+ return FudStatus::Success;
+}
+
+FudStatus getWidthTakesWidth(StringView& formatView, FormatSpec& spec);
+
+FudStatus getWidth(StringView& formatView, FormatSpec& spec)
+{
+ if (spec.takesWidth) {
+ return getWidthTakesWidth(formatView, spec);
+ }
+
+ if (formatView.length() < 1 || not classify::isDigit(formatView[0])) {
+ return FudStatus::Success;
+ }
+
+ auto widthResult{fromString<decltype(spec.width)>(formatView, Radix::Decimal)};
+ if (widthResult.isError()) {
+ return widthResult.takeError();
+ }
+ auto widthValue{widthResult.takeOkay()};
+ if (widthValue.value < 1) {
+ return FudStatus::FormatInvalid;
+ }
+ spec.width = widthValue.value;
+ if (formatView.length() < widthValue.nextIndex) {
+ return FudStatus::Failure;
+ }
+ formatView.advanceUnsafe(widthValue.nextIndex);
+
+ return FudStatus::Success;
+}
+
+FudStatus getWidthTakesWidth(StringView& formatView, FormatSpec& spec)
+{
+ if (!spec.takesWidth) {
+ return FudStatus::OperationInvalid;
+ }
+
+ if (formatView.length() < 2 || formatView[0] != FormatSpec::openBracket) {
+ return FudStatus::ArgumentInvalid;
+ }
+ formatView.advanceUnsafe();
+ if (formatView.length() > 0 && formatView[0] == FormatSpec::closeBracket &&
+ spec.position == FormatSpec::positionUnspecified) {
+ formatView.advanceUnsafe();
+ return FudStatus::Success;
+ }
+
+ if (spec.position == FormatSpec::positionUnspecified) {
+ return FudStatus::FormatInvalid;
+ }
+
+ auto positionResult{fromString<decltype(spec.position)>(formatView, Radix::Decimal)};
+ if (positionResult.isError()) {
+ return positionResult.takeError();
+ }
+ auto positionValue{positionResult.takeOkay()};
+ spec.width = positionValue.value;
+ if (formatView.length() + 1 < positionValue.nextIndex) {
+ return FudStatus::Failure;
+ }
+ if (formatView[positionValue.nextIndex + 1] != FormatSpec::closeBracket) {
+ return FudStatus::FormatInvalid;
+ }
+ formatView.advanceUnsafe(positionValue.nextIndex + 1);
+ return FudStatus::Success;
+}
+
+FudStatus getPrecisionTakesPrecision(StringView& formatView, FormatSpec& spec);
+
+FudStatus getPrecision(StringView& formatView, FormatSpec& spec)
+{
+ if (formatView.length() < 1 || formatView[0] != '.') {
+ return FudStatus::Success;
+ }
+
+ formatView.advanceUnsafe();
+
+ if (spec.takesPrecision) {
+ return getPrecisionTakesPrecision(formatView, spec);
+ }
+
+ if (formatView.length() < 1 || not classify::isDigit(formatView[0])) {
+ return FudStatus::Success;
+ }
+
+ auto precisionResult{fromString<decltype(spec.width)>(formatView, Radix::Decimal)};
+ if (precisionResult.isError()) {
+ return precisionResult.takeError();
+ }
+ auto precisionValue{precisionResult.takeOkay()};
+ if (precisionValue.value < 1) {
+ return FudStatus::FormatInvalid;
+ }
+ spec.precision = precisionValue.value;
+ if (formatView.length() < precisionValue.nextIndex) {
+ return FudStatus::Failure;
+ }
+ formatView.advanceUnsafe(precisionValue.nextIndex);
+
+ return FudStatus::Success;
+}
+
+FudStatus getPrecisionTakesPrecision(StringView& formatView, FormatSpec& spec)
+{
+ if (!spec.takesPrecision) {
+ return FudStatus::OperationInvalid;
+ }
+
+ if (formatView.length() < 2 || formatView[0] != FormatSpec::openBracket) {
+ return FudStatus::ArgumentInvalid;
+ }
+ formatView.advanceUnsafe();
+ if (formatView.length() > 0 && formatView[0] == FormatSpec::closeBracket &&
+ spec.position == FormatSpec::positionUnspecified) {
+ formatView.advanceUnsafe();
+ return FudStatus::Success;
+ }
+
+ if (spec.position == FormatSpec::positionUnspecified) {
+ return FudStatus::FormatInvalid;
+ }
+
+ auto positionResult{fromString<decltype(spec.position)>(formatView, Radix::Decimal)};
+ if (positionResult.isError()) {
+ return positionResult.takeError();
+ }
+ auto positionValue{positionResult.takeOkay()};
+ spec.precision = positionValue.value;
+ if (formatView.length() + 1 < positionValue.nextIndex) {
+ return FudStatus::Failure;
+ }
+ if (formatView[positionValue.nextIndex + 1] != FormatSpec::closeBracket) {
+ return FudStatus::FormatInvalid;
+ }
+ formatView.advanceUnsafe(positionValue.nextIndex + 1);
+ return FudStatus::Success;
+}
+
+FudStatus getFormatSign(StringView& formatView, FormatSpec& spec)
+{
+ if (formatView.length() < 1) {
+ spec.formatType = FormatType::Unspecified;
+ return FudStatus::Success;
+ }
+
+ auto letter = formatView[0];
+ switch (letter) {
+ case static_cast<utf8>(FormatType::String):
+ spec.formatType = FormatType::String;
+ break;
+ case static_cast<utf8>(FormatType::Escaped):
+ spec.formatType = FormatType::Escaped;
+ break;
+ case static_cast<utf8>(FormatType::BinaryLower):
+ spec.formatType = FormatType::BinaryLower;
+ break;
+ case static_cast<utf8>(FormatType::BinaryUpper):
+ spec.formatType = FormatType::BinaryUpper;
+ break;
+ case static_cast<utf8>(FormatType::Character):
+ spec.formatType = FormatType::Character;
+ break;
+ case static_cast<utf8>(FormatType::Decimal):
+ spec.formatType = FormatType::Decimal;
+ break;
+ case static_cast<utf8>(FormatType::Octal):
+ spec.formatType = FormatType::Octal;
+ break;
+ case static_cast<utf8>(FormatType::HexLower):
+ spec.formatType = FormatType::HexLower;
+ break;
+ case static_cast<utf8>(FormatType::HexUpper):
+ spec.formatType = FormatType::HexUpper;
+ break;
+ case static_cast<utf8>(FormatType::FloatHexLower):
+ spec.formatType = FormatType::FloatHexLower;
+ break;
+ case static_cast<utf8>(FormatType::FloatHexUpper):
+ spec.formatType = FormatType::FloatHexUpper;
+ break;
+ case static_cast<utf8>(FormatType::ScientificLower):
+ spec.formatType = FormatType::ScientificLower;
+ break;
+ case static_cast<utf8>(FormatType::ScientificUpper):
+ spec.formatType = FormatType::ScientificUpper;
+ break;
+ case static_cast<utf8>(FormatType::FixedLower):
+ spec.formatType = FormatType::FixedLower;
+ break;
+ case static_cast<utf8>(FormatType::FixedUpper):
+ spec.formatType = FormatType::FixedUpper;
+ break;
+ case static_cast<utf8>(FormatType::GeneralLower):
+ spec.formatType = FormatType::GeneralLower;
+ break;
+ case static_cast<utf8>(FormatType::GeneralUpper):
+ spec.formatType = FormatType::GeneralUpper;
+ break;
+ case static_cast<utf8>(FormatType::Unspecified):
+ default:
+ return FudStatus::FormatInvalid;
+ }
+
+ formatView.advanceUnsafe();
+ return FudStatus::Success;
+}
+
+} // namespace impl
} // namespace fud
diff --git a/source/fud_string.cpp b/source/fud_string.cpp
index b714dfc..6e16741 100644
--- a/source/fud_string.cpp
+++ b/source/fud_string.cpp
@@ -1,5 +1,5 @@
/*
- * LibFud
+ * libfud
* Copyright 2024 Dominick Allen
*
* Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/source/fud_string_convert.cpp b/source/fud_string_convert.cpp
new file mode 100644
index 0000000..428ab36
--- /dev/null
+++ b/source/fud_string_convert.cpp
@@ -0,0 +1,110 @@
+/*
+ * 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 "fud_string_convert.hpp"
+
+namespace fud::impl {
+
+FudStatus checkPlusSigned(StringView& view, size_t& skipIndex)
+{
+ auto isPlusSigned = view.data()[0] == '+';
+ if (isPlusSigned && view.length() == 1) {
+ return FudStatus::ArgumentInvalid;
+ }
+ if (isPlusSigned) {
+ view.advanceUnsafe();
+ skipIndex++;
+ }
+ return FudStatus::Success;
+}
+
+Result<bool, FudStatus> checkNegative(StringView& view, size_t& skipIndex)
+{
+ bool isNegative = view.data()[0] == '-';
+ if (isNegative && view.length() == 1) {
+ return FudStatus::ArgumentInvalid;
+ }
+ if (isNegative) {
+ skipIndex += 1;
+ view.advanceUnsafe();
+ }
+ return isNegative;
+}
+
+Result<Radix, FudStatus> determineRadix(StringView input, size_t& index)
+{
+ if (input.length() < 1) {
+ return FudStatus::ArgumentInvalid;
+ }
+
+ if (input.length() == 1 && input.data()[0] == '0') {
+ return Radix::Octal;
+ }
+
+ if (input.length() == 1) {
+ return Radix::Decimal;
+ }
+
+ if (input.data()[0] == '0' && (input.data()[1] == 'x' || input.data()[1] == 'X')) {
+ index += 2;
+ return Radix::Hexadecimal;
+ }
+
+ if (input.data()[0] == '0') {
+ auto nextChar = input.data()[1];
+ auto nextVal = AsciiLookup[nextChar];
+ if (nextVal >= 0 && nextVal < static_cast<uint8_t>(Radix::Octal)) {
+ return Radix::Octal;
+ }
+ if (nextVal >= static_cast<uint8_t>(Radix::Octal)) {
+ return FudStatus::ArgumentInvalid;
+ }
+ }
+
+ return Radix::Decimal;
+}
+
+Result<uint8_t, FudStatus> getRadix(StringView& view, size_t& skipIndex, Option<uint8_t> specifiedRadixOption)
+{
+ if (specifiedRadixOption.isNone()) {
+ size_t radixIndex = 0;
+ auto status = determineRadix(view, radixIndex);
+ if (status.isOkay()) {
+ skipIndex += radixIndex;
+ view.advanceUnsafe(radixIndex);
+ return static_cast<uint8_t>(status.takeOkay());
+ }
+ return status.takeError();
+ }
+
+ auto radix = specifiedRadixOption.value();
+ if (radix == static_cast<uint8_t>(Radix::Hexadecimal) && view.length() > 2 &&
+ (view.data()[1] == 'x' || view.data()[1] == 'X')) {
+ skipIndex += 2;
+ view.advanceUnsafe(2);
+ } else if (radix == static_cast<uint8_t>(Radix::Binary) && view.length() > 2 && view.data()[1] == 'b') {
+ skipIndex += 2;
+ view.advanceUnsafe(2);
+ } else if (radix == static_cast<uint8_t>(Radix::Octal) && view.length() > 2 && view.data()[1] == '0') {
+ skipIndex += 2;
+ view.advanceUnsafe(2);
+ }
+
+ return radix;
+}
+
+} // namespace fud::impl
diff --git a/source/fud_string_view.cpp b/source/fud_string_view.cpp
index 1cc73a6..090dd6d 100644
--- a/source/fud_string_view.cpp
+++ b/source/fud_string_view.cpp
@@ -1,5 +1,5 @@
/*
- * LibFud
+ * libfud
* Copyright 2024 Dominick Allen
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -61,7 +61,7 @@ Result<size_t, FudStatus> StringView::skipWhitespace()
return RetType::error(FudStatus::NullPointer);
}
size_t index = 0;
- while (m_length > 0 && charIsSpace(static_cast<char>(m_data[0]))) {
+ while (m_length > 0 && classify::isSpace(static_cast<char>(m_data[0]))) {
m_data++;
m_length--;
index++;
@@ -78,7 +78,7 @@ Result<size_t, FudStatus> StringView::trimWhitespace()
}
size_t count = 0;
- while (m_length > 0 && charIsSpace(static_cast<char>(m_data[m_length - 1]))) {
+ while (m_length > 0 && classify::isSpace(static_cast<char>(m_data[m_length - 1]))) {
m_length--;
count++;
}
@@ -120,6 +120,19 @@ void StringView::advanceUnsafe(size_t size)
m_data += size;
}
+FudStatus skipWhitespace(StringView& view, size_t& skipIndex)
+{
+ auto skipResult = view.skipWhitespace();
+ if (skipResult.isError()) {
+ return skipResult.getError();
+ }
+ skipIndex = skipResult.getOkay();
+ if (view.length() < 1) {
+ return FudStatus::ArgumentInvalid;
+ }
+ return FudStatus::Success;
+}
+
#if 0
FudStatus fud_string_truncate(ExtBasicString* source, ssize_t newLength)
@@ -134,7 +147,7 @@ FudStatus fud_string_truncate(ExtBasicString* source, ssize_t newLength)
if ((newLength > 0 && static_cast<size_t>(newLength) > source->m_length) ||
(static_cast<size_t>(-newLength) > source->m_length)) {
- return FudStatus::InvalidInput;
+ return FudStatus::ArgumentInvalid;
}
if (newLength < 0) {
@@ -158,10 +171,10 @@ FudStatus fud_string_reverse_substring(ExtBasicString* source, StringView subStr
{
auto dataOffset = subString.data - source->m_data;
if (dataOffset < 0 || static_cast<size_t>(dataOffset) > source->m_length) {
- return FudStatus::InvalidInput;
+ return FudStatus::ArgumentInvalid;
}
if (static_cast<size_t>(dataOffset) + subString.length > source->m_length) {
- return FudStatus::InvalidInput;
+ return FudStatus::ArgumentInvalid;
}
if (source == nullptr || source->m_data == nullptr) {
@@ -476,682 +489,6 @@ FudStatus fud_string_find_substring(StringView haystack, StringView needle, Stri
return ExtNotFound;
}
-FudStatus skipWhitespace(StringView& view, size_t& skipIndex)
-{
- auto skipResult = view.skipWhitespace();
- if (skipResult.isError()) {
- return skipResult.getError();
- }
- skipIndex = skipResult.getOkay();
- if (view.length < 1) {
- return FudStatus::InvalidInput;
- }
- return FudStatus::Success;
-}
-
-FudStatus fud_string_view_skip_whitespace(StringView* view)
-{
- if (view == nullptr) {
- return FudStatus::NullPointer;
- }
-
- StringView sView{*view};
- auto skipResult = sView.skipWhitespace();
- if (skipResult.isError()) {
- return skipResult.getError();
- }
- view->data = sView.data;
- view->length = sView.length;
- return FudStatus::Success;
-}
-
-FudStatus fud_string_view_trim_whitespace(StringView* view)
-{
- if (view == nullptr) {
- return FudStatus::NullPointer;
- }
-
- StringView sView{*view};
- auto skipResult = sView.trimWhitespace();
- if (skipResult.isError()) {
- return skipResult.getError();
- }
- view->data = sView.data;
- view->length = sView.length;
- return FudStatus::Success;
-}
-
-namespace impl {
-constexpr Array<int8_t, 256> AsciiLookup{
- {-1, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
- -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
- -2, -2, -2, -2, -2, -2, -2, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, -2, -2, -2, -2, -2, -2, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
- 29, 30, 31, 32, 33, 34, 35, -2, -2, -2, -2, -2, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3,
- -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3,
- -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3,
- -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3,
- -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3}};
-
-// NOLINTBEGIN(readability-magic-numbers)
-static_assert(AsciiLookup[static_cast<size_t>('0')] == 0);
-static_assert(AsciiLookup[static_cast<size_t>('9')] == 9);
-static_assert(AsciiLookup[static_cast<size_t>('a')] == 10);
-static_assert(AsciiLookup[static_cast<size_t>('A')] == 10);
-static_assert(AsciiLookup[static_cast<size_t>('f')] == 15);
-static_assert(AsciiLookup[static_cast<size_t>('F')] == 15);
-static_assert(AsciiLookup[127] == -2);
-static_assert(AsciiLookup[128] == -3);
-static_assert(AsciiLookup[255] == -3);
-// NOLINTEND(readability-magic-numbers)
-
-FudStatus determineRadix(StringView input, uint8_t& radix, size_t& index)
-{
- if (input.length < 1) {
- return FudStatus::InvalidInput;
- }
-
- if (input.length == 1 && input.data[0] == '0') {
- radix = ExtRadixOctal;
- return FudStatus::Success;
- }
-
- if (input.length == 1) {
- radix = ExtRadixDecimal;
- return FudStatus::Success;
- }
-
- if (input.data[0] == '0' && (input.data[1] == 'x' || input.data[1] == 'X')) {
- radix = ExtRadixHexadecimal;
- index += 2;
- return FudStatus::Success;
- }
-
- if (input.data[0] == '0') {
- auto nextChar = input.data[1];
- auto nextVal = AsciiLookup[nextChar];
- if (nextVal >= 0 && nextVal < ExtRadixOctal) {
- radix = ExtRadixOctal;
- return FudStatus::Success;
- }
- if (nextVal >= ExtRadixOctal) {
- return FudStatus::InvalidInput;
- }
- }
-
- radix = ExtRadixDecimal;
- return FudStatus::Success;
-}
-
-FudStatus getRadix(StringView& view, uint8_t& radix, size_t& skipIndex)
-{
- if (radix == 0) {
- size_t radixIndex = 0;
- auto status = determineRadix(view, radix, radixIndex);
- if (status != FudStatus::Success) {
- return status;
- }
- skipIndex += radixIndex;
- view.data += radixIndex;
- view.length -= radixIndex;
- } else if (radix == ExtRadixHexadecimal && view.length > 2 && (view.data[1] == 'x' || view.data[1] == 'X')) {
- skipIndex += 2;
- view.data += 2;
- view.length -= 2;
- }
- return FudStatus::Success;
-}
-
-FudStatus checkNegative(StringView& view, bool& isNegative, size_t& skipIndex)
-{
- isNegative = view.data[0] == '-';
- if (isNegative && view.length == 1) {
- return FudStatus::InvalidInput;
- }
- if (isNegative) {
- skipIndex += 1;
- view.data++;
- view.length--;
- }
- return FudStatus::Success;
-}
-
-FudStatus checkPlusSigned(StringView& view, size_t& skipIndex)
-{
- auto isPlusSigned = view.data[0] == '+';
- if (isPlusSigned && view.length == 1) {
- return FudStatus::InvalidInput;
- }
- if (isPlusSigned) {
- skipIndex += 1;
- view.data++;
- view.length--;
- }
- return FudStatus::Success;
-}
-
-template <typename T>
-FudStatus stringViewToUnsignedInteger(StringView input, T& number, uint8_t specifiedRadix, size_t& index)
-{
- if (input.data == nullptr) {
- return FudStatus::NullPointer;
- }
-
- if (specifiedRadix == 1 || specifiedRadix > ExtMaxRadix || input.length < 1) {
- return FudStatus::InvalidInput;
- }
-
- uint8_t radix = specifiedRadix;
-
- StringView view{input};
- size_t skipIndex = 0;
- auto status = skipWhitespace(view, skipIndex);
- if (status != FudStatus::Success) {
- return status;
- }
-
- status = checkPlusSigned(view, skipIndex);
- if (status != FudStatus::Success) {
- return FudStatus::InvalidInput;
- }
-
- status = getRadix(view, radix, skipIndex);
-
- T num = 0;
- size_t digitIndex = 0;
-
- while (digitIndex < view.length) {
- auto digitResult = impl::AsciiLookup[view.data[digitIndex]];
- if (digitResult >= radix || digitResult < 0) {
- break;
- }
-
- auto digit = static_cast<uint8_t>(digitResult);
- if (std::numeric_limits<T>::max() / radix < num) {
- return FudStatus::InvalidInput;
- }
- num *= radix;
- if (std::numeric_limits<T>::max() - digit < num) {
- return FudStatus::InvalidInput;
- }
- num += digit;
- digitIndex++;
- }
- if (digitIndex < 1) {
- return FudStatus::InvalidInput;
- }
-
- index = skipIndex + digitIndex;
- number = num;
-
- return FudStatus::Success;
-}
-
-template <typename T>
-FudStatus stringViewToUnsignedInteger(StringView input, T* number, uint8_t specifiedRadix, size_t* index)
-{
- if (anyAreNull(input.data, number)) {
- return FudStatus::NullPointer;
- }
-
- size_t localIndex = 0;
-
- auto status = stringViewToUnsignedInteger(input, *number, specifiedRadix, localIndex);
- if (status == FudStatus::Success && index != nullptr) {
- *index = localIndex;
- }
- return status;
-}
-
-template <typename T>
-FudStatus viewToSignedIntPositive(StringView view, uint8_t radix, size_t& digitIndex, T& num)
-{
- digitIndex = 0;
- while (digitIndex < view.length) {
- int8_t digitResult = impl::AsciiLookup[view.data[digitIndex]];
- if (digitResult >= radix) {
- return FudStatus::InvalidInput;
- }
- if (digitResult < 0) {
- break;
- }
- auto digit = static_cast<uint8_t>(digitResult);
- if (std::numeric_limits<T>::max() / radix < num) {
- return FudStatus::InvalidInput;
- }
- num = static_cast<T>(num * radix);
- if (std::numeric_limits<T>::max() - digit < num) {
- return FudStatus::InvalidInput;
- }
- num = static_cast<T>(num + digit);
- digitIndex++;
- }
-
- return FudStatus::Success;
-}
-
-template <typename T>
-FudStatus viewToSignedIntNegative(StringView view, uint8_t radix, size_t& digitIndex, T& num)
-{
- digitIndex = 0;
- while (digitIndex < view.length) {
- int8_t digitResult = impl::AsciiLookup[view.data[digitIndex]];
- if (digitResult >= radix) {
- return FudStatus::InvalidInput;
- }
- if (digitResult < 0) {
- break;
- }
- auto digit = static_cast<uint8_t>(digitResult);
- if ((std::numeric_limits<T>::min() / radix > num)) {
- return FudStatus::InvalidInput;
- }
- num = static_cast<T>(num * radix);
- if (std::numeric_limits<T>::min() + digit > num) {
- return FudStatus::InvalidInput;
- }
- num = static_cast<T>(num - digit);
- digitIndex++;
- }
-
- return FudStatus::Success;
-}
-
-template <typename T>
-FudStatus stringViewToSignedInteger(StringView input, T& number, uint8_t specifiedRadix, size_t& index)
-{
- if (input.data == nullptr) {
- return FudStatus::NullPointer;
- }
-
- auto radix = specifiedRadix;
-
- StringView view{input};
- size_t skipIndex = 0;
- auto status = skipWhitespace(view, skipIndex);
- if (status != FudStatus::Success) {
- return status;
- }
-
- bool isNegative = false;
- status = checkNegative(view, isNegative, skipIndex);
- if (status != FudStatus::Success) {
- return FudStatus::InvalidInput;
- }
-
- if (!isNegative) {
- status = checkPlusSigned(view, skipIndex);
- if (status != FudStatus::Success) {
- return FudStatus::InvalidInput;
- }
- }
-
- status = getRadix(view, radix, skipIndex);
-
- T num = 0;
- size_t digitIndex = 0;
-
- if (isNegative) {
- status = viewToSignedIntNegative(view, radix, digitIndex, num);
- } else {
- status = viewToSignedIntPositive(view, radix, digitIndex, num);
- }
- if (status != FudStatus::Success) {
- return status;
- }
-
- if (digitIndex < 1) {
- return FudStatus::InvalidInput;
- }
-
- index = skipIndex + digitIndex;
- number = num;
- return FudStatus::Success;
-}
-
-template <typename T>
-FudStatus stringViewToSignedInteger(StringView input, T* number, uint8_t specifiedRadix, size_t* index)
-{
- if (anyAreNull(input.data, number)) {
- return FudStatus::NullPointer;
- }
-
- if (specifiedRadix == 1 || specifiedRadix > ExtMaxRadix || input.length < 1) {
- return FudStatus::InvalidInput;
- }
-
- size_t localIndex = 0;
- auto status = stringViewToSignedInteger(input, *number, specifiedRadix, localIndex);
- if (status == FudStatus::Success && index != nullptr) {
- *index = localIndex;
- }
- return status;
-}
-
-} // namespace impl
-
-FudStatus fud_string_to_uint8(StringView input, uint8_t* number, uint8_t specifiedRadix, size_t* index)
-{
- return impl::stringViewToUnsignedInteger(input, number, specifiedRadix, index);
-}
-
-FudStatus fud_string_to_uint16(StringView input, uint16_t* number, uint8_t specifiedRadix, size_t* index)
-{
- return impl::stringViewToUnsignedInteger(input, number, specifiedRadix, index);
-}
-
-FudStatus fud_string_to_uint32(StringView input, uint32_t* number, uint8_t specifiedRadix, size_t* index)
-{
- return impl::stringViewToUnsignedInteger(input, number, specifiedRadix, index);
-}
-
-FudStatus fud_string_to_uint64(StringView input, uint64_t* number, uint8_t specifiedRadix, size_t* index)
-{
- return impl::stringViewToUnsignedInteger(input, number, specifiedRadix, index);
-}
-
-FudStatus fud_string_to_int8(StringView input, int8_t* number, uint8_t specifiedRadix, size_t* index)
-{
- return impl::stringViewToSignedInteger(input, number, specifiedRadix, index);
-}
-
-FudStatus fud_string_to_int16(StringView input, int16_t* number, uint8_t specifiedRadix, size_t* index)
-{
- return impl::stringViewToSignedInteger(input, number, specifiedRadix, index);
-}
-
-FudStatus fud_string_to_int32(StringView input, int32_t* number, uint8_t specifiedRadix, size_t* index)
-{
- return impl::stringViewToSignedInteger(input, number, specifiedRadix, index);
-}
-
-FudStatus fud_string_to_int64(StringView input, int64_t* number, uint8_t specifiedRadix, size_t* index)
-{
- return impl::stringViewToSignedInteger(input, number, specifiedRadix, index);
-}
-
-namespace impl {
-
-template <typename T>
-bool isNanOrInf(T& num, StringView& view, T& sign, size_t& digitIndex)
-{
- if (view.length >= 3) {
- Array<uint8_t, 3> letters{{view.data[0], view.data[1], view.data[2]}};
- mapMut(letters, fud_char_to_lower);
- if (letters[0] == 'i' && letters[1] == 'n' && letters[2] == 'f') {
- num = sign * std::numeric_limits<T>::infinity();
- digitIndex = 3;
- return true;
- }
- if (letters[0] == 'n' && letters[1] == 'a' && letters[2] == 'n') {
- num = std::numeric_limits<T>::quiet_NaN();
- ;
- digitIndex = 3;
- return true;
- }
- }
- return false;
-}
-
-template <typename T>
-FudStatus getWhole(
- const StringView view,
- size_t& digitIndex,
- T& num,
- T sign,
- uint8_t radix,
- bool& foundDecimal,
- bool& foundExponent)
-{
- while (digitIndex < view.length) {
- auto nextChar = view.data[digitIndex];
- if (nextChar == '.') {
- foundDecimal = true;
- digitIndex++;
- break;
- }
-
- if (radix == ExtRadixDecimal && (nextChar == 'e' || nextChar == 'E')) {
- foundExponent = true;
- digitIndex++;
- break;
- }
-
- auto digitResult = impl::AsciiLookup[nextChar];
- if (digitResult >= radix) {
- return FudStatus::InvalidInput;
- }
- if (digitResult < 0) {
- break;
- }
- auto digit = static_cast<T>(digitResult) * sign;
- num *= static_cast<T>(radix);
-
- num += digit;
- digitIndex++;
- }
- return FudStatus::Success;
-}
-
-template <typename T>
-FudStatus getExponent(StringView view, size_t& digitIndex, T& num, uint8_t radix)
-{
- int32_t exponent{};
- StringView tempView{view.length - digitIndex, view.data + digitIndex};
- size_t exponentLength{};
- auto status = tempView.toInt32(exponent, ExtRadixDecimal, exponentLength);
- if (status != FudStatus::Success) {
- return status;
- }
- digitIndex += exponentLength;
- num = num * std::pow(static_cast<T>(radix), static_cast<T>(exponent));
- return FudStatus::Success;
-}
-
-template <typename T>
-FudStatus getFraction(const StringView view, size_t& digitIndex, T& num, T sign, uint8_t radix, bool& foundExponent)
-{
- auto radixDiv = 1.0F / static_cast<T>(radix);
- while (digitIndex < view.length) {
- auto nextChar = view.data[digitIndex];
- if (radix == ExtRadixDecimal && (nextChar == 'e' || nextChar == 'E')) {
- foundExponent = true;
- digitIndex++;
- break;
- }
-
- auto digitResult = impl::AsciiLookup[nextChar];
- if (digitResult >= radix) {
- return FudStatus::InvalidInput;
- }
- if (digitResult < 0) {
- break;
- }
- auto digit = static_cast<T>(digitResult) * sign;
- num += digit * radixDiv;
- radixDiv /= static_cast<T>(radix);
- digitIndex++;
- }
- return FudStatus::Success;
-}
-
-template <typename T>
-FudStatus stringViewToFloat(StringView input, T& number, size_t& index)
-{
- if (input.data == nullptr) {
- return FudStatus::NullPointer;
- }
-
- if (input.length < 1) {
- return FudStatus::InvalidInput;
- }
-
- uint8_t radix = 0;
-
- StringView view{input};
- size_t skipIndex = 0;
-
- auto status = skipWhitespace(view, skipIndex);
- if (status != FudStatus::Success) {
- return status;
- }
-
- T sign = 1.0;
- bool isNegative = false;
- status = impl::checkNegative(view, isNegative, skipIndex);
- if (status != FudStatus::Success) {
- return FudStatus::InvalidInput;
- }
-
- if (!isNegative) {
- status = checkPlusSigned(view, skipIndex);
- } else {
- sign = -1.0;
- }
-
- if (status != FudStatus::Success) {
- return FudStatus::InvalidInput;
- }
-
- T num = 0;
- size_t digitIndex = 0;
-
- auto retSuccess = [&]() {
- index = skipIndex + digitIndex;
- number = num;
- return FudStatus::Success;
- };
-
- if (impl::isNanOrInf(num, view, sign, digitIndex)) {
- return retSuccess();
- }
-
- status = impl::getRadix(view, radix, skipIndex);
- if (status != FudStatus::Success) {
- return status;
- }
-
- bool foundDecimal = false;
- bool foundExponent = false;
- status = getWhole(view, digitIndex, num, sign, radix, foundDecimal, foundExponent);
-
- if (status == FudStatus::Success && foundExponent) {
- status = getExponent(view, digitIndex, num, radix);
- }
-
- if (status != FudStatus::Success) {
- return status;
- }
-
- if (!foundDecimal) {
- if (digitIndex < 1) {
- return FudStatus::InvalidInput;
- }
-
- return retSuccess();
- }
-
- status = getFraction(view, digitIndex, num, sign, radix, foundExponent);
-
- if (foundExponent) {
- status = getExponent(view, digitIndex, num, radix);
- if (status != FudStatus::Success) {
- return status;
- }
- }
-
- if (digitIndex < 1) {
- return FudStatus::InvalidInput;
- }
-
- if (std::isinf(num) || std::isnan(num)) // isnan is dubious here - likely unreachable
- {
- return FudStatus::RangeError;
- }
-
- return retSuccess();
-}
-
-template <typename T>
-FudStatus stringViewToFloat(StringView input, T* number, size_t* index)
-{
- if (anyAreNull(input.data, number)) {
- return FudStatus::NullPointer;
- }
-
- size_t localIndex{0};
- auto status = stringViewToFloat(input, *number, localIndex);
-
- if (status == FudStatus::Success && index != nullptr) {
- *index = localIndex;
- }
- return status;
-}
-
-} // namespace impl
-
-FudStatus fud_string_to_float(StringView input, float* number, size_t* index)
-{
- return impl::stringViewToFloat(input, number, index);
-}
-
-FudStatus fud_string_to_double(StringView input, double* number, size_t* index)
-{
- return impl::stringViewToFloat(input, number, index);
-}
-
-namespace fud {
-
-FudStatus StringView::toUint8(uint8_t& number, uint8_t specifiedRadix, size_t& strLen) const
-{
- return ::impl::stringViewToUnsignedInteger(*this, number, specifiedRadix, strLen);
-}
-
-FudStatus StringView::toUint16(uint16_t& number, uint8_t specifiedRadix, size_t& strLen) const
-{
- return ::impl::stringViewToUnsignedInteger(*this, number, specifiedRadix, strLen);
-}
-
-FudStatus StringView::toUint32(uint32_t& number, uint8_t specifiedRadix, size_t& strLen) const
-{
- return ::impl::stringViewToUnsignedInteger(*this, number, specifiedRadix, strLen);
-}
-
-FudStatus StringView::toUint64(uint64_t& number, uint8_t specifiedRadix, size_t& strLen) const
-{
- return ::impl::stringViewToUnsignedInteger(*this, number, specifiedRadix, strLen);
-}
-
-FudStatus StringView::toInt8(int8_t& number, uint8_t specifiedRadix, size_t& strLen) const
-{
- return ::impl::stringViewToSignedInteger(*this, number, specifiedRadix, strLen);
-}
-
-FudStatus StringView::toInt16(int16_t& number, uint8_t specifiedRadix, size_t& strLen) const
-{
- return ::impl::stringViewToSignedInteger(*this, number, specifiedRadix, strLen);
-}
-
-FudStatus StringView::toInt32(int32_t& number, uint8_t specifiedRadix, size_t& strLen) const
-{
- return ::impl::stringViewToSignedInteger(*this, number, specifiedRadix, strLen);
-}
-
-FudStatus StringView::toInt64(int64_t& number, uint8_t specifiedRadix, size_t& strLen) const
-{
- return ::impl::stringViewToSignedInteger(*this, number, specifiedRadix, strLen);
-}
-
-FudStatus StringView::toFloat(float& number, size_t& strLen) const
-{
- return ::impl::stringViewToFloat(*this, number, strLen);
-}
-
-FudStatus StringView::toDouble(double& number, size_t& strLen) const
-{
- return ::impl::stringViewToFloat(*this, number, strLen);
-}
-
#endif
} // namespace fud
diff --git a/source/fud_utf8.cpp b/source/fud_utf8.cpp
index 4d617da..bffb5c1 100644
--- a/source/fud_utf8.cpp
+++ b/source/fud_utf8.cpp
@@ -27,7 +27,6 @@ FudUtf8 FudUtf8::from(const String& fudString, size_t index) noexcept
return invalidAscii();
}
-
return from(StringView{fudString}, index);
}
@@ -69,20 +68,26 @@ FudUtf8 FudUtf8::from(StringView view, size_t index) noexcept
return invalidAscii();
}
-bool charIsAscii(char character)
+namespace classify {
+
+bool isAscii(char character)
+{
+ return isAscii(static_cast<utf8>(character));
+}
+
+bool isAscii(utf8 character)
{
- return static_cast<uint8_t>(character & ~ASCII_MASK) == 0;
+ return (character & ~ASCII_MASK) == 0;
}
-bool utf8IsAscii(FudUtf8 character)
+bool isAscii(FudUtf8 character)
{
return character.getType() == Utf8Type::Ascii && character.valid();
}
namespace impl {
-template <typename Predicate>
-bool isAsciiPredicate(FudUtf8 character, Predicate&& predicate)
+bool isAsciiPredicate(FudUtf8 character, bool (*predicate)(char))
{
auto maybeAscii = character.getAscii();
if (!maybeAscii.has_value()) {
@@ -90,92 +95,122 @@ bool isAsciiPredicate(FudUtf8 character, Predicate&& predicate)
}
auto asciiChar = *maybeAscii;
- return std::forward<Predicate>(predicate)(asciiChar.asChar());
+ return predicate(asciiChar.asChar());
}
} // namespace impl
-bool charIsAlphanumeric(char character)
+bool isAlphanumeric(char character)
{
- if (!charIsAscii(character)) {
+ return isAlphanumeric(static_cast<utf8>(character));
+}
+
+bool isAlphanumeric(utf8 character)
+{
+ if (!isAscii(character)) {
return false;
}
- if (charIsAlpha(character)) {
+ if (isAlpha(character)) {
return true;
}
- return charIsDigit(character);
+ return isDigit(character);
+}
+
+bool isAlphanumeric(FudUtf8 character)
+{
+ return impl::isAsciiPredicate(character, isAlphanumeric);
}
-bool utf8IsAlphanumeric(FudUtf8 character)
+bool isAlpha(char character)
{
- return impl::isAsciiPredicate(character, charIsAlphanumeric);
+ return isAlpha(static_cast<utf8>(character));
}
-bool charIsAlpha(char character)
+bool isAlpha(utf8 character)
{
- if (!charIsAscii(character)) {
+ if (!isAscii(character)) {
return false;
}
- if (charIsUppercase(character)) {
+ if (isUppercase(character)) {
return true;
}
- return charIsLowercase(character);
+ return isLowercase(character);
}
-bool utf8IsAlpha(FudUtf8 character)
+bool isAlpha(FudUtf8 character)
{
- return impl::isAsciiPredicate(character, charIsAlpha);
+ return impl::isAsciiPredicate(character, isAlpha);
}
-bool charIsLowercase(char character)
+bool isLowercase(char character)
{
- if (!charIsAscii(character)) {
+ return isLowercase(static_cast<utf8>(character));
+}
+
+bool isLowercase(utf8 character)
+{
+ if (!isAscii(character)) {
return false;
}
return 'a' <= character && character <= 'z';
}
-bool utf8IsLowercase(FudUtf8 character)
+bool isLowercase(FudUtf8 character)
+{
+ return impl::isAsciiPredicate(character, isLowercase);
+}
+
+bool isUppercase(char character)
{
- return impl::isAsciiPredicate(character, charIsLowercase);
+ return isUppercase(static_cast<utf8>(character));
}
-bool charIsUppercase(char character)
+bool isUppercase(utf8 character)
{
- if (!charIsAscii(character)) {
+ if (!isAscii(character)) {
return false;
}
return 'A' <= character && character <= 'Z';
}
-bool utf8IsUppercase(FudUtf8 character)
+bool isUppercase(FudUtf8 character)
{
- return impl::isAsciiPredicate(character, charIsUppercase);
+ return impl::isAsciiPredicate(character, isUppercase);
}
-bool charIsDigit(char character)
+bool isDigit(char character)
{
- if (!charIsAscii(character)) {
+ return isDigit(static_cast<utf8>(character));
+}
+
+bool isDigit(utf8 character)
+{
+ if (!isAscii(character)) {
return false;
}
return '0' <= character && character <= '9';
}
-bool utf8IsDigit(FudUtf8 character)
+bool isDigit(FudUtf8 character)
+{
+ return impl::isAsciiPredicate(character, isDigit);
+}
+
+bool isHexDigit(char character)
{
- return impl::isAsciiPredicate(character, charIsDigit);
+ return isHexDigit(static_cast<utf8>(character));
}
-bool charIsHexDigit(char character)
+bool isHexDigit(utf8 character)
{
- if (!charIsAscii(character)) {
+ if (!isAscii(character)) {
return false;
}
@@ -183,86 +218,116 @@ bool charIsHexDigit(char character)
('A' <= character && character <= 'F');
}
-bool utf8IsHexDigit(FudUtf8 character)
+bool isHexDigit(FudUtf8 character)
+{
+ return impl::isAsciiPredicate(character, isHexDigit);
+}
+
+bool isControl(char character)
{
- return impl::isAsciiPredicate(character, charIsHexDigit);
+ return isControl(static_cast<utf8>(character));
}
-bool charIsControl(char character)
+bool isControl(utf8 character)
{
- if (!charIsAscii(character)) {
+ if (!isAscii(character)) {
return false;
}
constexpr char maxControlChar = 0x1F;
constexpr const char deleteChar = 0x7F;
- return ((static_cast<uint8_t>(character) <= maxControlChar)) || character == deleteChar;
+ return ((static_cast<utf8>(character) <= maxControlChar)) || character == deleteChar;
}
-bool utf8IsControl(FudUtf8 character)
+bool isControl(FudUtf8 character)
{
- return impl::isAsciiPredicate(character, charIsControl);
+ return impl::isAsciiPredicate(character, isControl);
}
-bool charIsGraphical(char character)
+bool isGraphical(char character)
{
- if (!charIsAscii(character)) {
+ return isGraphical(static_cast<utf8>(character));
+}
+
+bool isGraphical(utf8 character)
+{
+ if (!isAscii(character)) {
return false;
}
- return charIsAlphanumeric(character) || charIsPunctuation(character);
+ return isAlphanumeric(character) || isPunctuation(character);
+}
+
+bool isGraphical(FudUtf8 character)
+{
+ return impl::isAsciiPredicate(character, isGraphical);
}
-bool utf8IsGraphical(FudUtf8 character)
+bool isSpace(char character)
{
- return impl::isAsciiPredicate(character, charIsGraphical);
+ return isSpace(static_cast<utf8>(character));
}
-bool charIsSpace(char character)
+bool isSpace(utf8 character)
{
- if (!charIsAscii(character)) {
+ if (!isAscii(character)) {
return false;
}
return character == ' ' || character == '\t' || character == '\n' || character == '\r' || character == '\v';
}
-bool utf8IsSpace(FudUtf8 character)
+bool isSpace(FudUtf8 character)
{
- return impl::isAsciiPredicate(character, charIsSpace);
+ return impl::isAsciiPredicate(character, isSpace);
}
-bool charIsBlank(char character)
+bool isBlank(char character)
{
- if (!charIsAscii(character)) {
+ return isBlank(static_cast<utf8>(character));
+}
+
+bool isBlank(utf8 character)
+{
+ if (!isAscii(character)) {
return false;
}
return character == ' ' || character == '\t';
}
-bool utf8IsBlank(FudUtf8 character)
+bool isBlank(FudUtf8 character)
+{
+ return impl::isAsciiPredicate(character, isBlank);
+}
+
+bool isPrintable(char character)
{
- return impl::isAsciiPredicate(character, charIsBlank);
+ return isPrintable(static_cast<utf8>(character));
}
-bool charIsPrintable(char character)
+bool isPrintable(utf8 character)
{
- if (!charIsAscii(character)) {
+ if (!isAscii(character)) {
return false;
}
return (character >= ' ' && character <= '~');
}
-bool utf8IsPrintable(FudUtf8 character)
+bool isPrintable(FudUtf8 character)
{
- return impl::isAsciiPredicate(character, charIsPrintable);
+ return impl::isAsciiPredicate(character, isPrintable);
}
-bool charIsPunctuation(char character)
+bool isPunctuation(char character)
{
- if (!charIsAscii(character)) {
+ return isPunctuation(static_cast<utf8>(character));
+}
+
+bool isPunctuation(utf8 character)
+{
+ if (!isAscii(character)) {
return false;
}
@@ -270,45 +335,45 @@ bool charIsPunctuation(char character)
(character >= '[' && character <= '`') || (character >= '{' && character <= '~');
}
-bool utf8IsPunctuation(FudUtf8 character)
+bool isPunctuation(FudUtf8 character)
{
- return impl::isAsciiPredicate(character, charIsPunctuation);
+ return impl::isAsciiPredicate(character, isPunctuation);
}
+} // namespace classify
+
uint8_t charToLower(uint8_t character)
{
- if (charIsUppercase(static_cast<char>(character))) {
+ if (classify::isUppercase(static_cast<char>(character))) {
constexpr uint8_t lowerA = 'a';
constexpr uint8_t upperA = 'A';
- return static_cast<uint8_t>(character - upperA) + lowerA;
+ return static_cast<utf8>(character - upperA) + lowerA;
}
return character;
}
FudUtf8 utf8ToLower(FudUtf8 character)
{
- static_cast<void>(character.transformAscii([](Ascii& ascii) {
- ascii = Ascii{charToLower(static_cast<uint8_t>(ascii.asChar()))};
- }));
+ static_cast<void>(
+ character.transformAscii([](Ascii& ascii) { ascii = Ascii{charToLower(static_cast<utf8>(ascii.asChar()))}; }));
return character;
}
uint8_t charToUpper(uint8_t character)
{
- if (charIsLowercase(static_cast<char>(character))) {
+ if (classify::isLowercase(static_cast<char>(character))) {
constexpr uint8_t lowerA = 'a';
constexpr uint8_t upperA = 'A';
- return static_cast<uint8_t>(character - lowerA) + upperA;
+ return static_cast<utf8>(character - lowerA) + upperA;
}
return character;
}
FudUtf8 utf8ToUpper(FudUtf8 character)
{
- static_cast<void>(character.transformAscii([](Ascii& ascii) {
- ascii = Ascii{charToUpper(static_cast<uint8_t>(ascii.asChar()))};
- }));
+ static_cast<void>(
+ character.transformAscii([](Ascii& ascii) { ascii = Ascii{charToUpper(static_cast<utf8>(ascii.asChar()))}; }));
return character;
}