Browse Source

replaced std string with own string

Kajetan Johannes Hammerle 3 years ago
parent
commit
36cfde4210

+ 0 - 4
common/block/BlockRegistry.cpp

@@ -26,8 +26,4 @@ const Block& BlockRegistry::getBlock(u16 id) const {
         return blocks[id];
     }
     return blocks[0];
-}
-
-size_t BlockRegistry::Hasher::operator()(const HashedString& key) const {
-    return key.hashCode();
 }

+ 1 - 4
common/block/BlockRegistry.h

@@ -17,10 +17,7 @@ private:
     void add(const char* registry, const BlockBuilder& builder);
 
     std::vector<Block> blocks;
-    struct Hasher {
-        size_t operator()(const HashedString& key) const;
-    };
-    std::unordered_map<HashedString, u16, Hasher> registryToId;
+    std::unordered_map<HashedString, u16, HashedString::Hasher> registryToId;
 };
 
 #endif

+ 9 - 1
common/utils/HashedString.cpp

@@ -1,5 +1,9 @@
 #include "common/utils/HashedString.h"
 
+HashedString::HashedString() : length(0), hash(0) {
+    data[length] = '\0';
+}
+
 HashedString::HashedString(const char* str) : length(0), hash(0) {
     for(; length < LENGTH - 1 && str[length] != '\0'; length++) {
         data[length] = str[length];
@@ -22,4 +26,8 @@ HashedString::operator const char*() const {
 
 u32 HashedString::hashCode() const {
     return hash;
-}
+}
+
+u32 HashedString::Hasher::operator()(const HashedString& key) const {
+    return key.hash;
+}

+ 8 - 5
common/utils/HashedString.h

@@ -1,20 +1,23 @@
 #ifndef HASHEDSTRING_H
 #define HASHEDSTRING_H
 
-#include <unordered_map>
-
 #include "common/utils/Types.h"
 
 class HashedString {
 public:
+    HashedString();
     HashedString(const char* str);
-    
+
     bool operator==(const HashedString& other) const;
     bool operator!=(const HashedString& other) const;
     operator const char*() const;
-    
+
     u32 hashCode() const;
 
+    struct Hasher {
+        u32 operator()(const HashedString& key) const;
+    };
+
 private:
     static constexpr uint LENGTH = 32 - sizeof (u8) - sizeof (u32);
     char data[LENGTH];
@@ -22,4 +25,4 @@ private:
     u32 hash;
 };
 
-#endif
+#endif

+ 43 - 0
common/utils/List.h

@@ -0,0 +1,43 @@
+#ifndef LIST_H
+#define LIST_H
+
+#include "common/utils/Types.h"
+
+template<typename T, uint L>
+class List {
+public:
+
+    List() : entries(0) {
+    }
+
+    List& add(const T& t) {
+        if(entries >= L) {
+            return *this;
+        }
+        data[entries++] = t;
+        return *this;
+    }
+    
+    List& clear() {
+        entries = 0;
+        return *this;
+    }
+
+    uint getLength() const {
+        return entries;
+    }
+
+    T& operator[](uint index) {
+        return data[index];
+    }
+
+    const T& operator[](uint index) const {
+        return data[index];
+    }
+
+private:
+    uint entries;
+    T data[L];
+};
+
+#endif

+ 44 - 0
common/utils/SplitString.cpp

@@ -0,0 +1,44 @@
+#include "common/utils/SplitString.h"
+
+SplitString::SplitString(const char* str) : entries(0) {
+    for(uint i = 0; str[i] != '\0'; i++) {
+        if(str[i] == '"') {
+            if(i >= 1 && str[i - 1] != ' ') {
+                return;
+            }
+            data += '"';
+            i++;
+            while(str[i] != '"') {
+                if(str[i] == '\0') {
+                    return;
+                }
+                data += str[i++];
+            }
+            if(str[i + 1] != '\0' && str[i + 1] != ' ') {
+                return;
+            }
+            data += '\0';
+            continue;
+        }
+        data += (str[i] == ' ' ? '\0' : str[i]);
+    }
+    uint last = 0;
+    for(uint i = 0; i < data.getLength() + 1; i++) {
+        if(data[i] != '\0' && data[i] != '"') {
+            continue;
+        }
+        if(i - last > 0 || (i >= 1 && data[i - 1] == '"')) {
+            starts[entries++] = last;
+        }
+        last = i + 1;
+    }
+}
+
+uint SplitString::getLength() const {
+    return entries;
+}
+
+const char* SplitString::operator[](uint index) const {
+    return data + starts[index];
+}
+

+ 19 - 0
common/utils/SplitString.h

@@ -0,0 +1,19 @@
+#ifndef SPLITSTRING_H
+#define SPLITSTRING_H
+
+#include "common/utils/String.h"
+
+class SplitString {
+public:
+    SplitString(const char* str);
+    
+    uint getLength() const;
+    const char* operator[](uint index) const;
+
+private:
+    String data;
+    uint entries;
+    u8 starts[String::MAX_LENGTH];
+};
+
+#endif

+ 19 - 2
common/utils/String.cpp

@@ -7,7 +7,7 @@ String::String() : length(0) {
 }
 
 String::String(const char* str) : length(0) {
-    for(; length < BUFFER_LENGTH - 1 && str[length] != '\0'; length++) {
+    for(; length < MAX_LENGTH - 1 && str[length] != '\0'; length++) {
         data[length] = str[length];
     }
     data[length] = '\0';
@@ -23,4 +23,21 @@ bool String::operator!=(const String& other) const {
 
 String::operator const char*() const {
     return data;
-}
+}
+
+String& String::operator+=(char c) {
+    if(length < MAX_LENGTH - 1) {
+        data[length++] = c;
+        data[length] = '\0';
+    }
+    return *this;
+}
+
+char String::operator[](uint index) const {
+    return data[index];
+}
+
+uint String::getLength() const {
+    return length;
+}
+

+ 7 - 3
common/utils/String.h

@@ -11,11 +11,15 @@ public:
     bool operator==(const String& other) const;
     bool operator!=(const String& other) const;
     operator const char*() const;
+    String& operator+=(char c);
+    char operator[](uint index) const;
+    
+    uint getLength() const;
 
+    static constexpr uint MAX_LENGTH = 255;
 private:
-    static constexpr uint BUFFER_LENGTH = 256;
-    uint length;
-    char data[BUFFER_LENGTH];
+    char data[MAX_LENGTH];
+    u8 length;
 };
 
 #endif

+ 6 - 5
meson.build

@@ -2,13 +2,13 @@ project('cubes plus plus', 'cpp')
 
 # 'common/world/Chunk.cpp', 'common/world/World.cpp', 'common/utils/Face.cpp'
 
-sourcesCommon = ['common/block/BlockBuilder.cpp', 'common/block/Block.cpp', 'common/block/BlockRegistry.cpp', 'common/utils/HashedString.cpp', 'common/stream/Stream.cpp', 'common/utils/DataVector.cpp', 'common/utils/String.cpp']
+sourcesCommon = ['common/block/BlockBuilder.cpp', 'common/block/Block.cpp', 'common/block/BlockRegistry.cpp', 'common/utils/HashedString.cpp', 'common/stream/Stream.cpp', 'common/utils/DataVector.cpp', 'common/utils/String.cpp', 'common/utils/SplitString.cpp']
 
-sourcesServer = ['server/Main.cpp', 'server/network/Server.cpp', 'server/GameServer.cpp', 'server/commands/CommandUtils.cpp', 'server/commands/ServerCommands.cpp', 'server/commands/CommandManager.cpp', 'server/network/Socket.cpp', 'server/commands/CommandEditor.cpp', 'server/Clock.cpp']
+sourcesServer = ['server/Main.cpp', 'server/network/Server.cpp', 'server/GameServer.cpp', 'server/commands/ServerCommands.cpp', 'server/commands/CommandManager.cpp', 'server/network/Socket.cpp', 'server/commands/CommandEditor.cpp', 'server/Clock.cpp']
 
 sourcesClient = ['client/Main.cpp', 'client/rendering/WindowSize.cpp', 'client/math/Frustum.cpp', 'client/math/Ray.cpp', 'client/rendering/Framebuffers.cpp', 'client/rendering/wrapper/GLFWWrapper.cpp', 'client/rendering/wrapper/Window.cpp', 'client/rendering/Engine.cpp', 'client/input/Keys.cpp', 'client/rendering/wrapper/Shader.cpp', 'client/rendering/Shaders.cpp', 'client/utils/Utils.cpp', 'client/rendering/Mesh.cpp', 'client/math/Matrix.cpp', 'client/math/MatrixStack.cpp', 'client/math/Vector.cpp', 'client/math/Camera.cpp', 'client/math/Plane.cpp', 'client/Game.cpp', 'client/input/MouseButtons.cpp', 'client/rendering/FileTexture.cpp', 'client/rendering/FontRenderer.cpp', 'client/rendering/wrapper/Framebuffer.cpp', 'client/rendering/NoiseTexture.cpp', 'client/utils/Clock.cpp', 'client/input/Control.cpp', 'client/rendering/RenderSettings.cpp', 'client/rendering/wrapper/VertexBuffer.cpp', 'client/rendering/wrapper/StreamBuffer.cpp', 'client/rendering/wrapper/Texture.cpp', 'client/utils/PNGReader.cpp', 'client/rendering/wrapper/GLWrapper.cpp', 'client/rendering/Renderer.cpp']
 
-sourcesTest = ['tests/Main.cpp', 'server/commands/CommandUtils.cpp']
+sourcesTest = ['tests/Main.cpp', 'common/utils/String.cpp', 'common/utils/SplitString.cpp']
 
 c_compiler = meson.get_compiler('cpp')
 readline = c_compiler.find_library('readline', required: true)
@@ -23,8 +23,9 @@ executable('game_server',
     dependencies : [threadDep, readline],
     cpp_args: ['-Wall', '-Wextra', '-pedantic', '-Werror'])
     
-#executable('game_tests', 
-#    sources: sourcesTest)
+executable('game_tests', 
+    sources: sourcesTest,
+    cpp_args: ['-Wall', '-Wextra', '-pedantic', '-Werror'])
     
 executable('game_client', 
     sources: sourcesCommon + sourcesClient,

+ 4 - 5
server/GameServer.cpp

@@ -12,8 +12,7 @@ void GameServer::tick() {
 void GameServer::handleCommands(CommandEditor& editor, ServerCommands& serverCommands) {
     while(editor.hasCommand()) {
         String s = editor.readCommand();
-        std::string s2 = static_cast<const char*> (s);
-        CommandManager::execute(serverCommands, s2);
+        CommandManager::execute(serverCommands, s);
     }
 }
 
@@ -32,15 +31,15 @@ void GameServer::onClientConnect(int socket) {
 }
 
 void GameServer::onClientPackage(int socket, Stream& in) {
-    std::string s = "";
+    String s = "";
     while(in.hasData()) {
         char c;
         in.read(&c, 1);
-        s = c + s;
+        s += c;
     }
 
     Stream answer;
-    answer.write(s.data(), s.length());
+    answer.write(s, s.getLength());
     answer.sendToSocket(socket);
 }
 

+ 12 - 12
server/commands/CommandManager.cpp

@@ -1,37 +1,37 @@
 #include <iostream>
 #include <unordered_map>
-#include <vector>
 
 #include "server/commands/CommandManager.h"
-#include "server/commands/CommandUtils.h"
+#include "common/utils/HashedString.h"
+#include "common/utils/SplitString.h"
 
-static void commandTest(ServerCommands&, const std::vector<std::string>& args) {
+static void commandTest(ServerCommands&, const SplitString& args) {
     std::cout << "test command" << std::endl;
-    for(size_t i = 0; i < args.size(); i++) {
+    for(size_t i = 0; i < args.getLength(); i++) {
         std::cout << " - " << args[i] << std::endl;
     }
 }
 
-static void commandStop(ServerCommands& sc, const std::vector<std::string>&) {
+static void commandStop(ServerCommands& sc, const SplitString&) {
     sc.stop();
 }
 
-typedef void (*Command) (ServerCommands&, const std::vector<std::string>&);
+typedef void (*Command) (ServerCommands&, const SplitString&);
 
-static std::unordered_map<std::string, Command> commands( {
+static std::unordered_map<HashedString, Command, HashedString::Hasher> commands( {
     {"test", commandTest},
     {"stop", commandStop}
 });
 
-void CommandManager::execute(ServerCommands& sc, const std::string& rawCommand) {
-    std::vector<std::string> args;
-    std::string command;
-    if(CommandUtils::splitString(rawCommand, command, args)) {
+void CommandManager::execute(ServerCommands& sc, const String& rawCommand) {
+    SplitString args(rawCommand);
+    if(args.getLength() == 0) {
         std::cout << "Invalid command syntax: '" << rawCommand << "'\n";
         return;
     }
 
-    const std::unordered_map<std::string, Command>::const_iterator& iter = commands.find(command);
+    HashedString command(args[0]);
+    auto iter = commands.find(command);
     if(iter == commands.end()) {
         std::cout << "Unknown command: '" << command << "'" << std::endl;
         return;

+ 3 - 2
server/commands/CommandManager.h

@@ -1,10 +1,11 @@
 #ifndef COMMANDMANAGER_H
 #define COMMANDMANAGER_H
 
-#include "ServerCommands.h"
+#include "server/commands/ServerCommands.h"
+#include "common/utils/String.h"
 
 namespace CommandManager {
-    void execute(ServerCommands& sc, const std::string& rawCommand);
+    void execute(ServerCommands& sc, const String& rawCommand);
 }
 
 #endif

+ 0 - 69
server/commands/CommandUtils.cpp

@@ -1,69 +0,0 @@
-#include "server/commands/CommandUtils.h"
-
-static bool splitStringIntern(const std::string& rawCommand, std::string& command, std::vector<std::string>& args) {
-    size_t old = 0;
-    size_t index = 0;
-
-    // parse first argument
-    while(index < rawCommand.size()) {
-        if(rawCommand[index] == ' ') {
-            command = rawCommand.substr(old, index - old);
-            old = index + 1;
-            index++;
-            break;
-        }
-        index++;
-    }
-    // if the command name is the whole raw command
-    if(index == rawCommand.size()) {
-        command = rawCommand.substr(old, index - old);
-        return false;
-    }
-
-    // parse remainding arguments
-    while(index < rawCommand.size()) {
-        if(rawCommand[index] == '"') {
-            // no space before the quotation mark
-            if(index != old) {
-                return true;
-            }
-            old = index + 1;
-            while(true) {
-                index++;
-                // quotation mark not closed
-                if(index >= rawCommand.size()) {
-                    return true;
-                } else if(rawCommand[index] == '"') {
-                    break;
-                }
-            }
-            // no space after quotation mark
-            if(index + 1 < rawCommand.size() && rawCommand[index + 1] != ' ') {
-                return true;
-            }
-            args.push_back(rawCommand.substr(old, index - old));
-            old = index + 2;
-        } else if(rawCommand[index] == ' ') {
-            if(index > old && index - old > 0) {
-                args.push_back(rawCommand.substr(old, index - old));
-            }
-            old = index + 1;
-        }
-        index++;
-    }
-
-    if(index > old && index - old > 0) {
-        args.push_back(rawCommand.substr(old, index - old));
-    }
-
-    return false;
-}
-
-bool CommandUtils::splitString(const std::string& rawCommand, std::string& command, std::vector<std::string>& args) {
-    bool b = splitStringIntern(rawCommand, command, args);
-    if(b) {
-        args.clear();
-        command = "";
-    }
-    return b;
-}

+ 0 - 11
server/commands/CommandUtils.h

@@ -1,11 +0,0 @@
-#ifndef COMMANDUTILS_H
-#define COMMANDUTILS_H
-
-#include <string>
-#include <vector>
-
-namespace CommandUtils {
-    bool splitString(const std::string& rawCommand, std::string& command, std::vector<std::string>& args);
-}
-
-#endif

+ 51 - 103
tests/Main.cpp

@@ -1,140 +1,88 @@
 #include <iostream>
-#include "server/commands/CommandUtils.h"
+#include <array>
 
-using namespace std;
+#include "common/utils/SplitString.h"
+#include "common/utils/List.h"
 
-// -----------------------------------------------------------------------------
-// test feedback
-// -----------------------------------------------------------------------------
+typedef List<const char*, 16> StringList;
 
 const char* RED = "\033[0;31m";
 const char* GREEN = "\033[0;32m";
 
-int tests = 0;
-int successTests = 0;
-
-void notifySuccess(string text) {
-    tests++;
-    successTests++;
-    cout << GREEN << tests << ". " << text << endl;
-}
-
-void notifyFail(string text) {
-    tests++;
-    cout << RED << tests << ". " << text << endl;
-}
+uint tests = 0;
+uint successTests = 0;
 
 void finalizeTest() {
-    cout << successTests << " / " << tests << " succeeded" << endl;
+    std::cout << ((successTests == tests) ? GREEN : RED);
+    std::cout << successTests << " / " << tests << " succeeded\n";
     tests = 0;
     successTests = 0;
 }
 
-// -----------------------------------------------------------------------------
-// checks
-// -----------------------------------------------------------------------------
-
-void checkEqual(int a, int b, string text) {
-    if(a == b) {
-        notifySuccess(text);
+template<typename T>
+void checkEqual(const T& wanted, const T& actual, const char* text) {
+    if(wanted == actual) {
+        tests++;
+        successTests++;
+        std::cout << GREEN << tests << ": " << text << "\n";
     } else {
-        notifyFail(text + " - expected '" + std::to_string(a) + "' got '" + std::to_string(b) + "'");
+        tests++;
+        std::cout << RED << tests << ": " << text << " - ";
+        std::cout << RED << "expected '" << wanted << "' got '" << actual << "'\n";
     }
 }
 
-void checkEqual(string a, string b, string text) {
-    if(a == b) {
-        notifySuccess(text);
-    } else {
-        notifyFail(text + " - expected '" + a + "' got '" + b + "'");
-    }
-}
-
-void checkBool(bool a, bool b, string text) {
-    if(a == b) {
-        notifySuccess(text);
-    } else {
-        notifyFail(text + " - expected '" + std::to_string(a) + "' got '" + std::to_string(b) + "'");
-    }
-}
-
-void checkGreaterOrEqual(int a, int b, string text) {
-    if(a >= b) {
-        notifySuccess(text);
-    } else {
-        notifyFail(text + " - expected " + std::to_string(a) + " >= " + std::to_string(b));
-    }
-}
-
-// -----------------------------------------------------------------------------
-// tests of command parser
-// -----------------------------------------------------------------------------
-
-void checkCommandParser(string rawCommand, string command, vector<string>& args, string text) {
-    string parsedCommand;
-    vector<string> parsedArgs;
-
-    CommandUtils::splitString(rawCommand, parsedCommand, parsedArgs);
-
-    checkEqual(command, parsedCommand, text);
-    checkEqual(args.size(), parsedArgs.size(), text);
-
-    for(unsigned long i = 0; i < args.size() && i < parsedArgs.size(); i++) {
-        checkEqual(args[i], parsedArgs[i], text);
+void checkCommandParser(const char* rawCommand, const StringList& result, const char* text) {
+    SplitString split(rawCommand);
+    checkEqual(result.getLength(), split.getLength(), text);
+    for(uint i = 0; i < result.getLength() && i < split.getLength(); i++) {
+        checkEqual(String(result[i]), String(split[i]), text);
     }
 }
 
 void testCommandParser() {
-    vector<string> args;
-
-    args = {};
-    checkCommandParser("test", "test", args, "command without arguments");
+    StringList list;
 
-    args = {"aaa"};
-    checkCommandParser("test aaa", "test", args, "command with one argument");
+    list.clear().add("test");
+    checkCommandParser("test", list, "command without arguments");
 
-    args = {"aaa", "bbbb"};
-    checkCommandParser("test aaa bbbb", "test", args, "command with two arguments");
+    list.clear().add("test").add("aaa");
+    checkCommandParser("test aaa", list, "command with one argument");
 
-    args = {"aaa", "bbbb", "ccccc"};
-    checkCommandParser("test aaa bbbb ccccc", "test", args, "command with three arguments");
+    list.clear().add("test").add("aaa").add("bbbb");
+    checkCommandParser("test aaa bbbb", list, "command with two arguments");
 
-    args = {};
-    checkCommandParser("test    ", "test", args, "command with spaces");
+    list.clear().add("test").add("aaa").add("bbbb").add("ccccc");
+    checkCommandParser("test aaa bbbb ccccc", list, "command with three arguments");
 
-    args = {"aaa", "bbbb"};
-    checkCommandParser("test  aaa   bbbb", "test", args, "command with arguments and spaces");
+    list.clear().add("test");
+    checkCommandParser("test    ", list, "command with spaces");
 
-    args = {"aaa", "bbbb"};
-    checkCommandParser("test  aaa   bbbb", "test", args, "command with arguments and spaces");
+    list.clear().add("test").add("aaa").add("bbbb");
+    checkCommandParser("test  aaa   bbbb", list, "command with arguments and spaces");
 
-    args = {"aaa bbbb"};
-    checkCommandParser("test \"aaa bbbb\"", "test", args, "command with one argument and quotation marks");
+    list.clear().add("test").add("aaa bbbb");
+    checkCommandParser("test \"aaa bbbb\"", list, "command with one argument and quotation marks");
 
-    args = {"aaa bbbb", "ccc"};
-    checkCommandParser("test \"aaa bbbb\" ccc", "test", args, "command with two arguments and quotation marks");
+    list.clear().add("test").add("aaa bbbb").add("ccc");
+    checkCommandParser("test \"aaa bbbb\" ccc", list, "command with two arguments and quotation marks");
 
-    args = {"ddd", "aaa bbbb", "ccc"};
-    checkCommandParser("test ddd \"aaa bbbb\" ccc", "test", args, "command with tree arguments and quotation marks");
+    list.clear().add("test").add("ddd").add("aaa bbbb").add("ccc");
+    checkCommandParser("test ddd \"aaa bbbb\" ccc", list, "command with tree arguments and quotation marks");
 
-    args = {};
-    checkCommandParser("test \"", "", args, "command syntax exception 1");
+    list.clear().add("test").add("");
+    checkCommandParser("test \"\"", list, "command with empty argument");
+    
+    list.clear();
+    checkCommandParser("test \"", list, "command syntax exception 1");
+    checkCommandParser("test aaa\"", list, "command syntax exception 2");
+    checkCommandParser("test aaa\"bbb\"", list, "command syntax exception 3");
+    checkCommandParser("test aaa \"bbb\"ccc", list, "command syntax exception 4");
 
-    args = {};
-    checkCommandParser("test aaa\"", "", args, "command syntax exception 2");
-
-    args = {};
-    checkCommandParser("test aaa\"bbb\"", "", args, "command syntax exception 3");
-
-    args = {};
-    checkCommandParser("test aaa \"bbb\"ccc", "", args, "command syntax exception 4");
+    finalizeTest();
 }
 
-// -----------------------------------------------------------------------------
-// main
-// -----------------------------------------------------------------------------
-
-int main(int argc, char** argv) {
+int main() {
     testCommandParser();
     return 0;
 }