Browse Source

two types of stack

Kajetan Johannes Hammerle 1 year ago
parent
commit
f43f50a747
10 changed files with 183 additions and 27 deletions
  1. 57 0
      data/Stack.h
  2. 1 1
      math/Math.h
  3. 2 1
      meson.build
  4. 2 0
      test/Main.cpp
  5. 4 4
      test/Test.cpp
  6. 2 2
      test/Test.h
  7. 88 0
      tests/StackTests.cpp
  8. 8 0
      tests/StackTests.h
  9. 12 12
      utils/Logger.h
  10. 7 7
      utils/Utility.h

+ 57 - 0
data/Stack.h

@@ -0,0 +1,57 @@
+#ifndef STACK_H
+#define STACK_H
+
+#include "data/ArrayList.h"
+#include "data/List.h"
+
+namespace Core {
+    namespace Internal {
+        template<typename T, typename S>
+        class BaseStack final {
+            S data;
+
+        public:
+            // returns true on error
+            template<typename... Args>
+            check_return bool push(Args&&... args) {
+                return data.add(Core::forward<Args>(args)...);
+            }
+
+            void clear() {
+                data.clear();
+            }
+
+            // returns true on error
+            check_return bool pop() {
+                // removeBySwap is checked
+                return data.removeBySwap(data.getLength() - 1);
+            }
+
+            bool isEmpty() const {
+                return data.getLength() == 0;
+            }
+
+            T& peek() {
+                return data[data.getLength() - 1];
+            }
+
+            const T& peek() const {
+                return data[data.getLength() - 1];
+            }
+
+            // returns true on error
+            template<int L>
+            check_return bool toString(ArrayString<L>& s) const {
+                return s.append(data);
+            }
+        };
+    }
+
+    template<typename T>
+    using ListStack = Internal::BaseStack<T, List<T>>;
+
+    template<typename T, int N>
+    using ArrayStack = Internal::BaseStack<T, ArrayList<T, N>>;
+}
+
+#endif

+ 1 - 1
math/Math.h

@@ -53,7 +53,7 @@ namespace Core::Math {
     }
 
     template<typename T>
-    const T& clamp(const T& t, const T& borderA, const T& borderB) {
+    constexpr const T& clamp(const T& t, const T& borderA, const T& borderB) {
         const T& low = min(borderA, borderB);
         const T& high = max(borderA, borderB);
         return max(low, min(high, t));

+ 2 - 1
meson.build

@@ -19,6 +19,7 @@ src_tests = [
     'tests/LinkedListTests.cpp',
     'tests/UniquePointerTests.cpp',
     'tests/HashMapTests.cpp',
+    'tests/StackTests.cpp',
 ]
 
 compiler = meson.get_compiler('cpp')
@@ -59,5 +60,5 @@ core_dep = declare_dependency(
 executable('tests', 
     sources: src_tests,
     dependencies: core_dep,
-    cpp_args: error_args + compile_args + ['-DLOG_LEVEL=4'],
+    cpp_args: error_args + compile_args + ['-DCORE_LOG_LEVEL=4'],
     link_args: link_args)

+ 2 - 0
test/Main.cpp

@@ -8,6 +8,7 @@
 #include "tests/LinkedListTests.h"
 #include "tests/ListTests.h"
 #include "tests/MathTests.h"
+#include "tests/StackTests.h"
 #include "tests/UniquePointerTests.h"
 #include "tests/UtilityTests.h"
 #include "utils/Utility.h"
@@ -26,6 +27,7 @@ int main() {
     Core::LinkedListTests::test();
     Core::ListTests::test();
     Core::MathTests::test();
+    Core::StackTests::test();
     Core::UniquePointerTests::test();
     Core::UtilityTests::test();
 

+ 4 - 4
test/Test.cpp

@@ -5,9 +5,9 @@ Core::Test::Test(const char* name_) : tests(0), successTests(0), name(name_) {
 
 void Core::Test::finalize() {
     if(successTests == tests) {
-        LOG_DEBUG("# Tests: # / # succeeded", name, successTests, tests);
+        CORE_LOG_DEBUG("# Tests: # / # succeeded", name, successTests, tests);
     } else {
-        LOG_ERROR("# Tests: # / # succeeded", name, successTests, tests);
+        CORE_LOG_ERROR("# Tests: # / # succeeded", name, successTests, tests);
     }
     tests = 0;
     successTests = 0;
@@ -26,8 +26,8 @@ void Core::Test::checkFloat(float wanted, float actual, float error,
         successTests++;
     } else {
         (void)text;
-        LOG_ERROR("# Test #: # - expected '#' got '#'", name, tests, text,
-                  wanted, actual)
+        CORE_LOG_ERROR("# Test #: # - expected '#' got '#'", name, tests, text,
+                       wanted, actual)
     }
 }
 

+ 2 - 2
test/Test.h

@@ -20,8 +20,8 @@ namespace Core {
                 successTests++;
             } else {
                 (void)text;
-                LOG_ERROR("# Test #: # - expected '#' got '#'", name, tests,
-                          text, wanted, actual)
+                CORE_LOG_ERROR("# Test #: # - expected '#' got '#'", name,
+                               tests, text, wanted, actual)
             }
         }
 

+ 88 - 0
tests/StackTests.cpp

@@ -0,0 +1,88 @@
+#include "tests/StackTests.h"
+
+#include "data/Stack.h"
+#include "test/Test.h"
+
+using String = Core::ArrayString<128>;
+
+template<typename T>
+static String build(Core::Test& test, const T& t) {
+    String s;
+    test.checkFalse(s.append(t), "append works");
+    return s;
+}
+
+template<typename T>
+static void testPushPopPeek(Core::Test& test) {
+    T stack;
+    test.checkFalse(stack.push(1), "push works 1");
+    test.checkFalse(stack.push(2), "push works 2");
+    test.checkFalse(stack.push(3), "push works 3");
+    test.checkEqual(3, stack.peek(), "push pop peek 1");
+    test.checkFalse(stack.pop(), "pop without error 1");
+    test.checkEqual(2, stack.peek(), "push pop peek 2");
+    test.checkFalse(stack.pop(), "pop without error 2");
+    test.checkEqual(1, stack.peek(), "push pop peek 3");
+    test.checkFalse(stack.pop(), "pop without error 3");
+    test.checkTrue(stack.isEmpty(), "empty after popping all");
+}
+
+template<typename T>
+static void testBigPushPop(Core::Test& test, int amount) {
+    T stack;
+    for(int i = 0; i < amount; i++) {
+        test.checkFalse(stack.push(i), "big push works");
+    }
+    for(int i = 0; i < amount; i++) {
+        test.checkFalse(stack.pop(), "big push and pop");
+    }
+    test.checkTrue(stack.isEmpty(), "empty after all pops");
+}
+
+template<typename T>
+static void testToString1(Core::Test& test) {
+    T stack;
+    test.checkFalse(stack.push(1), "to string push works 1");
+    test.checkFalse(stack.push(243), "to string push works 1");
+    test.checkFalse(stack.push(-423), "to string push works 1");
+    test.checkEqual(build(test, "[1, 243, -423]"), build(test, stack),
+                    "to string 1");
+}
+
+template<typename T>
+static void testToString2(Core::Test& test) {
+    T stack;
+    test.checkFalse(stack.push(1), "to string 2 push works 1");
+    test.checkEqual(build(test, "[1]"), build(test, stack), "to string 2");
+}
+
+template<typename T>
+static void testToString3(Core::Test& test) {
+    T stack;
+    test.checkEqual(build(test, "[]"), build(test, stack), "to string 3");
+}
+
+template<typename T>
+static void testPop(Core::Test& test) {
+    T stack;
+    for(int i = 0; i < 1000000; i++) {
+        test.checkTrue(stack.pop(), "popping empty stack is safe");
+    }
+}
+
+template<typename T>
+static void testType(Core::Test& test, int amount) {
+    testPushPopPeek<T>(test);
+    testBigPushPop<T>(test, amount);
+    testToString1<T>(test);
+    testToString2<T>(test);
+    testToString3<T>(test);
+    testPop<T>(test);
+}
+
+void Core::StackTests::test() {
+    Test test("Stack");
+    testType<Core::ListStack<int>>(test, 1000000);
+    testType<Core::ArrayStack<int, 100>>(test, 100);
+    test.finalize();
+}

+ 8 - 0
tests/StackTests.h

@@ -0,0 +1,8 @@
+#ifndef CORE_STACKTESTS_H
+#define CORE_STACKTESTS_H
+
+namespace Core::StackTests {
+    void test();
+}
+
+#endif

+ 12 - 12
utils/Logger.h

@@ -28,36 +28,36 @@ namespace Core::Logger {
     }
 }
 
-#if defined(LOG_LEVEL) && LOG_LEVEL >= 1
-#define LOG_ERROR(format, ...)                                                 \
+#if defined(CORE_LOG_LEVEL) && CORE_LOG_LEVEL >= 1
+#define CORE_LOG_ERROR(format, ...)                                            \
     log(Core::Logger::Level::ERROR, __FILE__, __LINE__, "\33[1;31m[ERROR] ",   \
         format, __VA_ARGS__);
 #else
-#define LOG_ERROR(format, ...)
+#define CORE_LOG_ERROR(format, ...)
 #endif
 
-#if defined(LOG_LEVEL) && LOG_LEVEL >= 2
-#define LOG_WARNING(format, ...)                                               \
+#if defined(CORE_LOG_LEVEL) && CORE_LOG_LEVEL >= 2
+#define CORE_LOG_WARNING(format, ...)                                          \
     log(Core::Logger::Level::WARNING, __FILE__, __LINE__,                      \
         "\33[1;33m[WARNING] ", format, __VA_ARGS__);
 #else
-#define LOG_WARNING(format, ...)
+#define CORE_LOG_WARNING(format, ...)
 #endif
 
-#if defined(LOG_LEVEL) && LOG_LEVEL >= 3
-#define LOG_INFO(format, ...)                                                  \
+#if defined(CORE_LOG_LEVEL) && CORE_LOG_LEVEL >= 3
+#define CORE_LOG_INFO(format, ...)                                             \
     log(Core::Logger::Level::INFO, __FILE__, __LINE__, "\33[1;37m[INFO] ",     \
         format, __VA_ARGS__);
 #else
-#define LOG_INFO(format, ...)
+#define CORE_LOG_INFO(format, ...)
 #endif
 
-#if defined(LOG_LEVEL) && LOG_LEVEL >= 4
-#define LOG_DEBUG(format, ...)                                                 \
+#if defined(CORE_LOG_LEVEL) && CORE_LOG_LEVEL >= 4
+#define CORE_LOG_DEBUG(format, ...)                                            \
     log(Core::Logger::Level::DEBUG, __FILE__, __LINE__, "\33[1;32m[DEBUG] ",   \
         format, __VA_ARGS__);
 #else
-#define LOG_DEBUG(format, ...)
+#define CORE_LOG_DEBUG(format, ...)
 #endif
 
 #endif

+ 7 - 7
utils/Utility.h

@@ -8,36 +8,36 @@
 namespace Core {
     namespace Internal {
         template<typename T>
-        struct RemoveReferenceBase {
+        struct BaseRemoveReference {
             typedef T t;
         };
 
         template<typename T>
-        struct RemoveReferenceBase<T&> {
+        struct BaseRemoveReference<T&> {
             typedef T t;
         };
 
         template<typename T>
-        struct RemoveReferenceBase<T&&> {
+        struct BaseRemoveReference<T&&> {
             typedef T t;
         };
 
         template<typename A, typename B>
-        struct IsSameBase {
+        struct BaseIsSame {
             static constexpr bool value = false;
         };
 
         template<typename T>
-        struct IsSameBase<T, T> {
+        struct BaseIsSame<T, T> {
             static constexpr bool value = true;
         };
     }
 
     template<typename T>
-    using RemoveReference = Internal::RemoveReferenceBase<T>::t;
+    using RemoveReference = Internal::BaseRemoveReference<T>::t;
 
     template<typename T, typename U>
-    constexpr bool IsSame = Internal::IsSameBase<T, U>::value;
+    constexpr bool IsSame = Internal::BaseIsSame<T, U>::value;
 
     template<typename T>
     constexpr RemoveReference<T>&& move(T&& t) {