4 Commits 911e5a1c36 ... 267af23382

Author SHA1 Message Date
  Kajetan Johannes Hammerle 267af23382 Use standard string functions 2 weeks ago
  Kajetan Johannes Hammerle 77a27f7db7 Rise coverage again 2 weeks ago
  Kajetan Johannes Hammerle 94f14acd54 Cast for g++ 2 weeks ago
  Kajetan Johannes Hammerle 839ad77fc8 Extend generic append by const char array cast 2 weeks ago

+ 2 - 0
include/core/utils/ArrayString.hpp

@@ -12,6 +12,8 @@ namespace Core {
         CError genericAppend(String& s, const T& t) {
             if constexpr(requires { t.toString(s); }) {
                 return t.toString(s);
+            } else if constexpr(requires { static_cast<const char*>(t); }) {
+                return s.append(static_cast<const char*>(t));
             } else {
                 char buffer[64];
                 CORE_RETURN_ERROR(toString(t, buffer, CORE_SIZE(buffer)));

+ 1 - 1
include/core/utils/HashedString.hpp

@@ -24,7 +24,7 @@ namespace Core {
     class HashedString {
         static_assert(N > 0, "length of hashed string must be positive");
         StringHash hash;
-        char data[N];
+        char data[static_cast<u32>(N)];
 
     public:
         HashedString() : hash() {

+ 1 - 0
include/core/utils/Utility.hpp

@@ -38,6 +38,7 @@ namespace Core {
     check_return Error toString(long double ld, char* buffer, int size);
 
     check_return Error putChar(int c);
+    check_return Error putChars(const char* s);
 
     void memorySet(void* p, int c, i64 n);
     void memoryCopy(void* dest, const void* src, i64 n);

+ 34 - 104
src/ArrayString.cpp

@@ -1,88 +1,45 @@
 #include "core/utils/ArrayString.hpp"
 
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <uchar.h>
+
+#include "core/data/Array.hpp"
 #include "core/math/Math.hpp"
 #include "core/utils/Error.hpp"
+#include "core/utils/Utility.hpp"
 
 using CharString = Core::CharString;
 using Char32String = Core::Char32String;
 using Error = Core::Error;
 namespace ErrorCode = Core::ErrorCode;
 
-template<typename T>
-constexpr int stringLength(const T* c) {
-    const T* i = c + 1;
+constexpr int stringLength(const c32* c) {
+    const c32* i = c + 1;
     while(*(c++) != '\0') {}
     return static_cast<int>(c - i);
 }
 
-static c32 read(const char*& s) {
-    if(*s == '\0') {
-        return 0;
-    }
-    return static_cast<c32>(*(s++));
-}
-
 static Error readUnicode(c32& u, const char*& s) {
-    u = read(s);
-    if((u & 0x80) == 0) {
-        return ErrorCode::NONE;
-    }
-    if((u & 0xE0) == 0xC0) {
-        c32 u2 = read(s);
-        if(u2 == 0) {
-            return ErrorCode::INVALID_CHAR;
-        }
-        u = ((u & 0x1F) << 6) | (u2 & 0x3F);
-        return ErrorCode::NONE;
-    } else if((u & 0xF0) == 0xE0) {
-        c32 u2 = read(s);
-        c32 u3 = read(s);
-        if(u2 == 0 || u3 == 0) {
-            return ErrorCode::INVALID_CHAR;
-        }
-        u = ((u & 0xF) << 12) | ((u2 & 0x3F) << 6) | (u3 & 0x3F);
-        return ErrorCode::NONE;
-    } else if((u & 0xF8) == 0xF0) {
-        c32 u2 = read(s);
-        c32 u3 = read(s);
-        c32 u4 = read(s);
-        if(u2 == 0 || u3 == 0 || u4 == 0) {
-            return ErrorCode::INVALID_CHAR;
-        }
-        u = ((u & 0x07) << 18) | ((u2 & 0x3F) << 12) | ((u3 & 0x3F) << 6) |
-            (u4 & 0x3F);
-        return ErrorCode::NONE;
-    }
-    return ErrorCode::INVALID_CHAR;
-}
-
-template<unsigned int L>
-static void unicodeToChar(c32 c, char (&buffer)[L]) {
-    static_assert(L >= 5, "to small char buffer");
-    buffer[0] = '\0';
-    if(c < (1 << 7)) {
-        buffer[0] = static_cast<char>(((c >> 0) & 0x7F) | 0x0);
-        buffer[1] = '\0';
-    } else if(c < (1 << 11)) {
-        buffer[0] = static_cast<char>(((c >> 6) & 0x1F) | 0xC0);
-        buffer[1] = static_cast<char>(((c >> 0) & 0x3F) | 0x80);
-        buffer[2] = '\0';
-    } else if(c < (1 << 16)) {
-        buffer[0] = static_cast<char>(((c >> 12) & 0x0F) | 0xE0);
-        buffer[1] = static_cast<char>(((c >> 6) & 0x3F) | 0x80);
-        buffer[2] = static_cast<char>(((c >> 0) & 0x3F) | 0x80);
-        buffer[3] = '\0';
-    } else if(c < (1 << 21)) {
-        buffer[0] = static_cast<char>(((c >> 18) & 0x07) | 0xF0);
-        buffer[1] = static_cast<char>(((c >> 12) & 0x3F) | 0x80);
-        buffer[2] = static_cast<char>(((c >> 6) & 0x3F) | 0x80);
-        buffer[3] = static_cast<char>(((c >> 0) & 0x3F) | 0x80);
-        buffer[4] = '\0';
+    size_t limit = MB_CUR_MAX;
+    size_t n = mbrtoc32(&u, s, limit, nullptr);
+    if(n > limit) {
+        return ErrorCode::INVALID_CHAR;
     }
+    s += n;
+    return ErrorCode::NONE;
 }
 
-static Error printChar(c32 u, u32 shift, u32 a, u32 o) {
-    return Core::putChar(static_cast<int>(((u >> shift) & a) | o));
+using C32Buffer = Core::Array<char, MB_LEN_MAX + 1>;
+
+static Error convertC32(C32Buffer& buffer, c32 c) {
+    size_t n = c32rtomb(buffer.begin(), c, nullptr);
+    if(n >= static_cast<size_t>(buffer.getLength())) {
+        return ErrorCode::INVALID_CHAR;
+    }
+    buffer[static_cast<i64>(n)] = '\0';
+    return ErrorCode::NONE;
 }
 
 CharString::CharString(char* buffer, i32 bufferSize)
@@ -96,24 +53,11 @@ Error CharString::copyFrom(const CharString& s) {
 }
 
 bool CharString::operator==(const char* s) const {
-    const char* p = data;
-    while(*s == *p && *s != '\0') {
-        s++;
-        p++;
-    }
-    return *s == *p;
+    return strcmp(data, s) == 0;
 }
 
 bool CharString::operator==(const CharString& other) const {
-    if(length != other.getLength()) {
-        return false;
-    }
-    for(int i = 0; i < length; i++) {
-        if(data[i] != other[i]) {
-            return false;
-        }
-    }
-    return true;
+    return length == other.length && strcmp(data, other.data) == 0;
 }
 
 bool CharString::operator!=(const char* s) const {
@@ -158,14 +102,14 @@ Error CharString::append(wchar_t c) {
 }
 
 Error CharString::append(c32 c) {
-    char buffer[5];
-    unicodeToChar(c, buffer);
-    return append(static_cast<const char*>(buffer));
+    C32Buffer buffer;
+    CORE_RETURN_ERROR(convertC32(buffer, c));
+    return append(static_cast<const char*>(buffer.begin()));
 }
 
 Error CharString::append(const char* s) {
     // stringLength as s could be some part of data
-    for(int i = stringLength(s); i > 0; i--) {
+    for(size_t i = strlen(s); i > 0; i--) {
         CORE_RETURN_ERROR(append(*(s++)));
     }
     return ErrorCode::NONE;
@@ -217,8 +161,7 @@ Error CharString::print() const {
 
 Error CharString::printLine() const {
     CORE_RETURN_ERROR(print());
-    CORE_RETURN_ERROR(Core::putChar('\n'));
-    return ErrorCode::NONE;
+    return Core::putChar('\n');
 }
 
 bool CharString::startsWidth(const CharString& other, int from) const {
@@ -430,22 +373,9 @@ void Char32String::clear() {
 
 Error Char32String::print() const {
     for(int i = 0; i < length; i++) {
-        c32 c = data[i];
-        if(c < (1 << 7)) {
-            CORE_RETURN_ERROR(printChar(c, 0, 0x7F, 0x0));
-        } else if(c < (1 << 11)) {
-            CORE_RETURN_ERROR(printChar(c, 6, 0x1F, 0xC0));
-            CORE_RETURN_ERROR(printChar(c, 0, 0x3F, 0x80));
-        } else if(c < (1 << 16)) {
-            CORE_RETURN_ERROR(printChar(c, 12, 0x0F, 0xE0));
-            CORE_RETURN_ERROR(printChar(c, 6, 0x3F, 0x80));
-            CORE_RETURN_ERROR(printChar(c, 0, 0x3F, 0x80));
-        } else if(c < (1 << 21)) {
-            CORE_RETURN_ERROR(printChar(c, 18, 0x07, 0xF0));
-            CORE_RETURN_ERROR(printChar(c, 12, 0x3F, 0x80));
-            CORE_RETURN_ERROR(printChar(c, 6, 0x3F, 0x80));
-            CORE_RETURN_ERROR(printChar(c, 0, 0x3F, 0x80));
-        }
+        C32Buffer buffer;
+        CORE_RETURN_ERROR(convertC32(buffer, data[i]));
+        CORE_RETURN_ERROR(putChars(buffer.begin()));
     }
     return ErrorCode::NONE;
 }

+ 5 - 0
src/Utility.cpp

@@ -54,6 +54,11 @@ Core::Error Core::putChar(int c) {
     return putchar(c) == EOF ? ErrorCode::BLOCKED_STDOUT : ErrorCode::NONE;
 }
 
+Core::Error Core::putChars(const char* s) {
+    return fputs(s, stdout) == EOF ? ErrorCode::BLOCKED_STDOUT
+                                   : ErrorCode::NONE;
+}
+
 void Core::memorySet(void* p, int c, i64 n) {
     if(n <= 0) {
         return;

+ 5 - 1
test/Main.cpp

@@ -1,3 +1,4 @@
+#include <locale.h>
 #include <string.h>
 
 #include "../src/ErrorSimulator.hpp"
@@ -5,17 +6,20 @@
 #include "Tests.hpp"
 #include "core/utils/ArrayString.hpp"
 #include "core/utils/Utility.hpp"
-
 static void onExit(int code, void* data) {
     unsigned int i = *static_cast<unsigned int*>(data);
     Core::String32<1024> s;
     CORE_TEST_ERROR(s.append("Hello from exit #: #"));
     CORE_TEST_ERROR(s.format(code, i));
     CORE_TEST_ERROR(s.printLine());
+    Core::String8<64> s8;
+    CORE_TEST_ERROR(s8.append("Hello from exit"));
+    CORE_TEST_ERROR(s8.printLine());
     Core::Test::finalize();
 }
 
 int main(int argAmount, const char** args) {
+    setlocale(LC_ALL, "en_US.utf8");
     bool light = false;
     bool outOfMemoryTest = true;
     for(int i = 0; i < argAmount; i++) {

+ 2 - 3
test/Test.cpp

@@ -20,9 +20,8 @@ void Core::Test::finalize() {
         const char* color = e.value.successTests == e.value.tests
                                 ? Logger::COLOR_GREEN
                                 : Logger::COLOR_RED;
-        Logger::log(color, "# - # / # tests succeeded",
-                    static_cast<const char*>(e.getKey()), e.value.successTests,
-                    e.value.tests);
+        Logger::log(color, "# - # / # tests succeeded", e.getKey(),
+                    e.value.successTests, e.value.tests);
     }
     Internal::results.clear();
 }

+ 3 - 3
test/Test.hpp

@@ -34,9 +34,9 @@ namespace Core::Test {
                 result->successTests++;
                 return true;
             }
-            Core::Logger::log(
-                Core::Logger::COLOR_RED, "#:# - expected '#' got '#'",
-                static_cast<const char*>(fileName), line, wanted, actual);
+            Core::Logger::log(Core::Logger::COLOR_RED,
+                              "#:# - expected '#' got '#'", fileName, line,
+                              wanted, actual);
             return false;
         }
 

+ 19 - 2
test/modules/ArrayStringTests.cpp

@@ -20,6 +20,7 @@ static void testEquality8() {
     CORE_TEST_TRUE(s == build("test"));
     CORE_TEST_TRUE("test" == s);
     CORE_TEST_TRUE(build("test") == s);
+    CORE_TEST_FALSE(build("tes2") == s);
     CORE_TEST_TRUE(s == s);
 }
 
@@ -445,6 +446,19 @@ static void testKeepHash8() {
     CORE_TEST_STRING("a # test ## ##123456789", s);
 }
 
+static void testFormatWithoutArguments8() {
+    String8 s;
+    CORE_TEST_ERROR(s.append("wusi"));
+    CORE_TEST_ERROR(s.format());
+    CORE_TEST_STRING("wusi", s);
+}
+
+static void testUnicodeString8() {
+    String8 s;
+    CORE_TEST_ERROR(s.append(U"_üö§äab"));
+    CORE_TEST_STRING("_üö§äab", s);
+}
+
 static String32 build(const c32* cs) {
     String32 s;
     CORE_TEST_ERROR(s.append(cs));
@@ -457,6 +471,7 @@ static void testEquality32() {
     CORE_TEST_TRUE(s == build(U"test"));
     CORE_TEST_TRUE(U"test" == s);
     CORE_TEST_TRUE(build(U"test") == s);
+    CORE_TEST_FALSE(build(U"tes2") == s);
     CORE_TEST_TRUE(s == s);
 }
 
@@ -889,9 +904,9 @@ static void testPrint32() {
 static void testVariousUnicode32() {
     const unsigned char buffer[] = {0xC0, 0};
     const unsigned char buffer2[] = {0xE0, 0};
-    const unsigned char buffer3[] = {0xE0, 1, 2, 0};
+    const unsigned char buffer3[] = {0xC3, 0xA4, 0};
     const unsigned char buffer4[] = {0xF0, 0};
-    const unsigned char buffer5[] = {0xF0, 1, 2, 3, 0};
+    const unsigned char buffer5[] = {0xF0, 0x9F, 0x8F, 0xA3, 0};
     const unsigned char buffer6[] = {0xFF, 0};
     String32 s;
     CORE_TEST_EQUAL(Core::ErrorCode::INVALID_CHAR, s.append(buffer));
@@ -969,6 +984,8 @@ void Core::testArrayString() {
     testAppendError8();
     testPrint8();
     testKeepHash8();
+    testFormatWithoutArguments8();
+    testUnicodeString8();
 
     testEquality32();
     testUnicodeEquality32();

+ 6 - 0
test/modules/ErrorTests.cpp

@@ -30,4 +30,10 @@ void Core::testError() {
             ErrorCode::SLEEP_INTERRUPTED | ErrorCode::THREAD_ERROR |
             ErrorCode::MUTEX_ERROR | ErrorCode::EXISTING_KEY |
             ErrorCode::CANNOT_OPEN_FILE | ErrorCode::END_OF_FILE);
+
+    char buffer[4];
+    CORE_TEST_EQUAL(
+        ErrorCode::CAPACITY_REACHED,
+        Core::toString(ErrorCode::INVALID_STATE, buffer, sizeof(buffer)));
+    CORE_TEST_STRING("000", buffer);
 }

+ 1 - 0
test/modules/HashedStringTests.cpp

@@ -33,6 +33,7 @@ static void testComparison() {
 static void testLength() {
     HString s("test");
     CORE_TEST_EQUAL(4, s.getLength());
+    CORE_TEST_EQUAL(31, s.getCapacity());
 }
 
 static void testHashCode() {

+ 7 - 0
test/modules/ProbingHashMapTests.cpp

@@ -1,6 +1,7 @@
 #include "../../src/ErrorSimulator.hpp"
 #include "../Tests.hpp"
 #include "core/data/ProbingHashMap.hpp"
+#include "core/utils/Error.hpp"
 
 template struct Core::ProbingHashMap<int, int>;
 using IntMap = Core::ProbingHashMap<int, int>;
@@ -350,6 +351,11 @@ static void testAddCollisions() {
     }
 }
 
+static void testLargeRehash() {
+    IntMap map;
+    CORE_TEST_EQUAL(Core::ErrorCode::CAPACITY_REACHED, map.rehash(1llu << 50));
+}
+
 void Core::testProbingHashMap(bool light, bool outOfMemoryTest) {
     testAdd();
     testMultipleAdd();
@@ -373,4 +379,5 @@ void Core::testProbingHashMap(bool light, bool outOfMemoryTest) {
     }
     testInsertInvalid();
     testAddCollisions();
+    testLargeRehash();
 }