From 787d12925916a14e16472095702713fd8569f957 Mon Sep 17 00:00:00 2001 From: Noah Attwood Date: Sun, 7 May 2023 23:35:55 -0300 Subject: [PATCH 1/5] adds operator implementations for less than, greater than, equals, and not equals --- include/attwoodn/expression_tree.hpp | 32 ++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/include/attwoodn/expression_tree.hpp b/include/attwoodn/expression_tree.hpp index 0675a73..e65f87f 100644 --- a/include/attwoodn/expression_tree.hpp +++ b/include/attwoodn/expression_tree.hpp @@ -3,6 +3,38 @@ #include namespace attwoodn::expression_tree { + + namespace op { + + template + class less_than { + bool operator()(A a, B b) { + return a < b; + } + }; + + template + class greater_than { + bool operator()(A a, B b) { + return a > b; + } + }; + + template + class equals { + bool operator()(A a, B b) { + return a == b; + } + }; + + template + class not_equals { + bool operator()(A a, B b) { + return a != b; + } + }; + } + static inline void say_hello() { std::cout << "hello world!" << std::endl; } From 791d6557373ac1463af11814e93bcc6bd2e26a33 Mon Sep 17 00:00:00 2001 From: Noah Attwood Date: Sun, 7 May 2023 23:43:32 -0300 Subject: [PATCH 2/5] adds new operators test --- tests/CMakeLists.txt | 3 +++ tests/operators.cpp | 12 ++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 tests/operators.cpp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f6626cb..9ddca6f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,4 +1,7 @@ if(BUILD_TESTING) add_executable( expression_tree_test test.cpp ) add_test( expression_tree_test ${EXECUTABLE_OUTPUT_PATH}/expression_tree_test ) + + add_executable( operators_test operators.cpp ) + add_test( operators_test ${EXECUTABLE_OUTPUT_PATH}/operators_test ) endif() \ No newline at end of file diff --git a/tests/operators.cpp b/tests/operators.cpp new file mode 100644 index 0000000..60dffab --- /dev/null +++ b/tests/operators.cpp @@ -0,0 +1,12 @@ +#include +#include + +using namespace attwoodn::expression_tree; + +int main(int argc, char** argv) { + std::string hello = "hello world"; + + //assert(op::equals(hello, hello)); + + return EXIT_SUCCESS; +} \ No newline at end of file From dd486674e00b44f1c76da1d0da0eb260a5dce500 Mon Sep 17 00:00:00 2001 From: Noah Attwood Date: Mon, 8 May 2023 00:51:52 -0300 Subject: [PATCH 3/5] adds tests for equals operator --- .gitignore | 3 +- CMakeLists.txt | 4 ++ include/attwoodn/expression_tree.hpp | 33 ++++++--------- tests/operators.cpp | 61 ++++++++++++++++++++++++++-- 4 files changed, 77 insertions(+), 24 deletions(-) diff --git a/.gitignore b/.gitignore index c795b05..1899660 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -build \ No newline at end of file +build +.vscode \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 45f1c82..7e0836b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,5 +10,9 @@ if (NOT DEFINED CMAKE_CXX_STANDARD) set(CMAKE_CXX_STANDARD 11) endif() +if (NOT CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "") + set(CMAKE_BUILD_TYPE "Release" CACHE STRING "" FORCE) +endif() + include_directories( include ) add_subdirectory( tests ) \ No newline at end of file diff --git a/include/attwoodn/expression_tree.hpp b/include/attwoodn/expression_tree.hpp index e65f87f..0e0ddfb 100644 --- a/include/attwoodn/expression_tree.hpp +++ b/include/attwoodn/expression_tree.hpp @@ -7,32 +7,25 @@ namespace attwoodn::expression_tree { namespace op { template - class less_than { - bool operator()(A a, B b) { - return a < b; - } - }; + inline bool less_than(A a, B b) { + return a < b; + } template - class greater_than { - bool operator()(A a, B b) { - return a > b; - } - }; + inline bool greater_than(A a, B b) { + return a > b; + } template - class equals { - bool operator()(A a, B b) { - return a == b; - } - }; + inline bool equals(A a, B b) { + return a == b; + } template - class not_equals { - bool operator()(A a, B b) { - return a != b; - } - }; + inline bool not_equals(A a, B b) { + return a != b; + } + } static inline void say_hello() { diff --git a/tests/operators.cpp b/tests/operators.cpp index 60dffab..b81e167 100644 --- a/tests/operators.cpp +++ b/tests/operators.cpp @@ -1,12 +1,67 @@ #include +#include +#include #include using namespace attwoodn::expression_tree; -int main(int argc, char** argv) { - std::string hello = "hello world"; +void test_equals(); - //assert(op::equals(hello, hello)); +int main(int argc, char** argv) { + test_equals(); return EXIT_SUCCESS; +} + +void test_equals() { + // test string equality/inequality + { + std::string hello = "hello world"; + + assert(op::equals(hello, hello)); + assert(op::equals(hello, "hello world")); + assert(op::equals("hello world", "hello world")); + assert(op::equals(" ", " ")); + + assert(!op::equals(" ", " ")); + assert(!op::equals("hello world", "hey, world")); + assert(!op::equals("test", " test ")); + } + + // test integer equality/inequality + { + assert(op::equals(5, 5)); + assert(op::equals(0, 0)); + assert(op::equals(-5, -5)); + assert(op::equals(123456789, 123456789)); + assert(op::equals(123456789, 123456789L)); + assert(op::equals(255, 0xff)); + assert(op::equals(0xbeef, 0xbeef)); + assert(op::equals(std::numeric_limits::max(), std::numeric_limits::max())); + assert(op::equals(std::numeric_limits::max(), std::numeric_limits::max())); + assert(op::equals(std::numeric_limits::max(), std::numeric_limits::max() / 2)); + + assert(!op::equals(-5, 5)); + assert(!op::equals(0, 1)); + assert(!op::equals(254, 0xff)); + assert(!op::equals(123456789, 123456789000L)); + assert(!op::equals(std::numeric_limits::max(), std::numeric_limits::max() / 2.0)); + } + + // test float equality/inequality + { + assert(op::equals(5.0, 5.0)); + assert(op::equals(0.000, 0.000)); + assert(op::equals(-5.0, -5.0)); + assert(op::equals(3.400f, 3.4f)); + assert(op::equals((float) 99999.0, (double) 99999.0)); + assert(op::equals(12345.999f, 12345.999f)); + + assert(!op::equals(5.0, -5.0)); + assert(!op::equals(0.000, 0.000001)); + assert(!op::equals(-5.0, -4.999999)); + + // there are some understandable difficulties with comparing floats directly. These should be equal + assert(!op::equals((float) 99999.999, (double) 99999.999)); + } } \ No newline at end of file From 1940b5c87b80c286be5ee2c30e6dd2adfee41551 Mon Sep 17 00:00:00 2001 From: Noah Attwood Date: Mon, 8 May 2023 01:13:05 -0300 Subject: [PATCH 4/5] adds expression tree node base class --- include/attwoodn/expression_tree.hpp | 20 ++++++++++++++++---- tests/test.cpp | 4 ++-- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/include/attwoodn/expression_tree.hpp b/include/attwoodn/expression_tree.hpp index 0e0ddfb..de882d5 100644 --- a/include/attwoodn/expression_tree.hpp +++ b/include/attwoodn/expression_tree.hpp @@ -1,7 +1,5 @@ #pragma once -#include - namespace attwoodn::expression_tree { namespace op { @@ -28,7 +26,21 @@ namespace attwoodn::expression_tree { } - static inline void say_hello() { - std::cout << "hello world!" << std::endl; + namespace tree { + + /** + * The base class representing expression tree nodes + */ + template + class expression_tree_node_base { + public: + virtual ~expression_tree_node_base() {}; + virtual bool evaluate(const Obj& obj) = 0; + }; + + class expression_tree_op_node; + class expression_tree_leaf_node; + + } } \ No newline at end of file diff --git a/tests/test.cpp b/tests/test.cpp index f9076ac..997deb8 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -1,7 +1,7 @@ -#include +#include int main(int argc, char** argv) { - attwoodn::expression_tree::say_hello(); + std::cout << "hello world!" << std::endl; return EXIT_SUCCESS; } \ No newline at end of file From 528a2bbb1b1eac56fdbad78ec6688b04caffe0a7 Mon Sep 17 00:00:00 2001 From: Noah Attwood Date: Mon, 8 May 2023 23:05:57 -0300 Subject: [PATCH 5/5] implements operators whose parameters are pointer types, and implements remaining unit test cases for operators --- include/attwoodn/expression_tree.hpp | 41 ++++- tests/operators.cpp | 235 +++++++++++++++++++++++++-- 2 files changed, 254 insertions(+), 22 deletions(-) diff --git a/include/attwoodn/expression_tree.hpp b/include/attwoodn/expression_tree.hpp index de882d5..00e703e 100644 --- a/include/attwoodn/expression_tree.hpp +++ b/include/attwoodn/expression_tree.hpp @@ -4,26 +4,51 @@ namespace attwoodn::expression_tree { namespace op { - template - inline bool less_than(A a, B b) { + template + inline bool less_than(T a, T b) { return a < b; } - template - inline bool greater_than(A a, B b) { + template + inline bool less_than(T* a, T* b) { + if(a == nullptr || b == nullptr) return false; + return *a < *b; + } + + template + inline bool greater_than(T a, T b) { return a > b; } - template - inline bool equals(A a, B b) { + template + inline bool greater_than(T* a, T* b) { + if(a == nullptr || b == nullptr) return false; + return *a > *b; + } + + template + inline bool equals(T a, T b) { return a == b; } - template - inline bool not_equals(A a, B b) { + template + inline bool equals(T* a, T* b) { + if(a == nullptr && b == nullptr) return true; + if(a == nullptr || b == nullptr) return false; + return *a == *b; + } + + template + inline bool not_equals(T a, T b) { return a != b; } + template + inline bool not_equals(T* a, T* b) { + if(a == nullptr && b == nullptr) return false; + if(a == nullptr || b == nullptr) return true; + return *a != *b; + } } namespace tree { diff --git a/tests/operators.cpp b/tests/operators.cpp index b81e167..6a8f0be 100644 --- a/tests/operators.cpp +++ b/tests/operators.cpp @@ -6,9 +6,15 @@ using namespace attwoodn::expression_tree; void test_equals(); +void test_not_equals(); +void test_less_than(); +void test_greater_than(); int main(int argc, char** argv) { test_equals(); + test_not_equals(); + test_less_than(); + test_greater_than(); return EXIT_SUCCESS; } @@ -19,49 +25,250 @@ void test_equals() { std::string hello = "hello world"; assert(op::equals(hello, hello)); - assert(op::equals(hello, "hello world")); - assert(op::equals("hello world", "hello world")); - assert(op::equals(" ", " ")); - - assert(!op::equals(" ", " ")); - assert(!op::equals("hello world", "hey, world")); - assert(!op::equals("test", " test ")); + assert(op::equals(hello, std::string("hello world"))); + assert(op::equals(std::string("hello world"), std::string("hello world"))); + assert(op::equals(std::string(" "), std::string(" "))); + assert(op::equals(std::string("100 100 100 10000"), std::string("100 100 100 10000"))); + + // NOTE: pointer types are dereferenced prior to comparison. This may be misleading. + // E.g., if the type is a char*, only the first character is compared. + assert(op::equals("1", "1 ")); + assert(op::equals("test", "testing testing 123")); + assert(op::equals("hello world", "hey, world")); + assert(op::equals("A", "A")); + + assert(!op::equals("\"", "\'")); + assert(!op::equals("1", " 1")); + assert(!op::equals("A", "B")); + assert(!op::equals(std::string("hello world"), std::string("hey, world"))); + assert(!op::equals(std::string("test"), std::string(" test "))); + assert(!op::equals(std::string(" "), std::string(" "))); + assert(!op::equals(std::string("1"), std::string("1 "))); + assert(!op::equals(std::string("1"), std::string(" 1"))); } // test integer equality/inequality { + int low = 55, low_too = 55; + int high = 999999, high_too = 999999; + assert(op::equals(5, 5)); assert(op::equals(0, 0)); assert(op::equals(-5, -5)); assert(op::equals(123456789, 123456789)); - assert(op::equals(123456789, 123456789L)); + assert(op::equals(123456789L, 123456789L)); assert(op::equals(255, 0xff)); assert(op::equals(0xbeef, 0xbeef)); assert(op::equals(std::numeric_limits::max(), std::numeric_limits::max())); assert(op::equals(std::numeric_limits::max(), std::numeric_limits::max())); - assert(op::equals(std::numeric_limits::max(), std::numeric_limits::max() / 2)); + assert(op::equals(std::numeric_limits::min(), std::numeric_limits::min())); + assert(op::equals(low, low)); + assert(op::equals(&low, &low)); + assert(op::equals(low, low_too)); + assert(op::equals(&low, &low_too)); + assert(op::equals(high, high)); + assert(op::equals(&high, &high)); + assert(op::equals(high, high_too)); + assert(op::equals(&high, &high_too)); assert(!op::equals(-5, 5)); assert(!op::equals(0, 1)); assert(!op::equals(254, 0xff)); - assert(!op::equals(123456789, 123456789000L)); - assert(!op::equals(std::numeric_limits::max(), std::numeric_limits::max() / 2.0)); + assert(!op::equals(123456789L, 123456789000L)); + assert(!op::equals(low, high)); + assert(!op::equals(&low, &high)); } // test float equality/inequality { + float low = 55.5555, low_too = 55.5555; + float high = 999999.999, high_too = 999999.999; + assert(op::equals(5.0, 5.0)); assert(op::equals(0.000, 0.000)); assert(op::equals(-5.0, -5.0)); assert(op::equals(3.400f, 3.4f)); - assert(op::equals((float) 99999.0, (double) 99999.0)); + assert(op::equals((float) 99999.0, (float) 99999.0)); assert(op::equals(12345.999f, 12345.999f)); + assert(op::equals((double) 99999.999, (double) 99999.999)); + assert(op::equals(low, low)); + assert(op::equals(&low, &low)); + assert(op::equals(low, low_too)); + assert(op::equals(&low, &low_too)); + assert(op::equals(high, high)); + assert(op::equals(&high, &high)); + assert(op::equals(high, high_too)); + assert(op::equals(&high, &high_too)); assert(!op::equals(5.0, -5.0)); assert(!op::equals(0.000, 0.000001)); assert(!op::equals(-5.0, -4.999999)); + assert(!op::equals(low, high)); + assert(!op::equals(&low, &high)); + } + + // test other + { + char* a = nullptr; + assert(op::equals(a, a)); + + assert(!op::equals((char*) "a", a)); + } +} + +void test_not_equals() { + // test string equality/inequality + { + std::string hello = "hello world"; + + assert(op::not_equals("\"", "\'")); + assert(op::not_equals("1", " 1")); + assert(op::not_equals("A", "B")); + assert(op::not_equals(std::string("hello world"), std::string("hey, world"))); + assert(op::not_equals(std::string("test"), std::string(" test "))); + assert(op::not_equals(std::string(" "), std::string(" "))); + assert(op::not_equals(std::string("1"), std::string("1 "))); + assert(op::not_equals(std::string("1"), std::string(" 1"))); + + assert(!op::not_equals(hello, hello)); + assert(!op::not_equals(hello, std::string("hello world"))); + assert(!op::not_equals(std::string("hello world"), std::string("hello world"))); + assert(!op::not_equals(std::string(" "), std::string(" "))); + assert(!op::not_equals(std::string("100 100 100 10000"), std::string("100 100 100 10000"))); + + // NOTE: pointer types are dereferenced prior to comparison. This may be misleading. + // E.g., if the type is a char*, only the first character is compared. + assert(!op::not_equals("1", "1 ")); + assert(!op::not_equals("test", "testing testing 123")); + assert(!op::not_equals("hello world", "hey, world")); + assert(!op::not_equals("A", "A")); + } + + // test integer equality/inequality + { + int low = 55, low_too = 55; + int high = 999999, high_too = 999999; + + assert(op::not_equals(-5, 5)); + assert(op::not_equals(0, 1)); + assert(op::not_equals(254, 0xff)); + assert(op::not_equals(123456789L, 123456789000L)); + assert(op::not_equals(low, high)); + assert(op::not_equals(&low, &high)); + + assert(!op::not_equals(5, 5)); + assert(!op::not_equals(0, 0)); + assert(!op::not_equals(-5, -5)); + assert(!op::not_equals(123456789, 123456789)); + assert(!op::not_equals(123456789L, 123456789L)); + assert(!op::not_equals(255, 0xff)); + assert(!op::not_equals(0xbeef, 0xbeef)); + assert(!op::not_equals(std::numeric_limits::max(), std::numeric_limits::max())); + assert(!op::not_equals(std::numeric_limits::max(), std::numeric_limits::max())); + assert(!op::not_equals(std::numeric_limits::min(), std::numeric_limits::min())); + assert(!op::not_equals(low, low)); + assert(!op::not_equals(&low, &low)); + assert(!op::not_equals(low, low_too)); + assert(!op::not_equals(&low, &low_too)); + assert(!op::not_equals(high, high)); + assert(!op::not_equals(&high, &high)); + assert(!op::not_equals(high, high_too)); + assert(!op::not_equals(&high, &high_too)); + } + + // test float equality/inequality + { + float low = 55.5555, low_too = 55.5555; + float high = 999999.999, high_too = 999999.999; + + assert(op::not_equals(5.0, -5.0)); + assert(op::not_equals(0.000, 0.000001)); + assert(op::not_equals(-5.0, -4.999999)); + assert(op::not_equals(low, high)); + assert(op::not_equals(&low, &high)); + + assert(!op::not_equals(5.0, 5.0)); + assert(!op::not_equals(0.000, 0.000)); + assert(!op::not_equals(-5.0, -5.0)); + assert(!op::not_equals(3.400f, 3.4f)); + assert(!op::not_equals((float) 99999.0, (float) 99999.0)); + assert(!op::not_equals(12345.999f, 12345.999f)); + assert(!op::not_equals((double) 99999.999, (double) 99999.999)); + assert(!op::not_equals(low, low)); + assert(!op::not_equals(&low, &low)); + assert(!op::not_equals(low, low_too)); + assert(!op::not_equals(&low, &low_too)); + assert(!op::not_equals(high, high)); + assert(!op::not_equals(&high, &high)); + assert(!op::not_equals(high, high_too)); + assert(!op::not_equals(&high, &high_too)); + } + + // test other + { + char* a = nullptr; + assert(op::not_equals((char*) "a", a)); - // there are some understandable difficulties with comparing floats directly. These should be equal - assert(!op::equals((float) 99999.999, (double) 99999.999)); + assert(!op::not_equals(a, a)); } +} + +void test_less_than() { + assert(op::less_than(5, 6)); + assert(op::less_than(1, 10)); + assert(op::less_than(0, 1)); + assert(op::less_than(-1, 1)); + assert(op::less_than(-1, 0)); + assert(op::less_than(5.0, 6.665)); + assert(op::less_than(6.664, 6.665)); + assert(op::less_than(1.199999, 1.2)); + assert(op::less_than(0xfe, 0xff)); + assert(op::less_than(std::string("hello"), std::string("hi"))); + assert(op::less_than("a", "b")); + assert(op::less_than("A", "C")); + assert(op::less_than("Q", "Z")); + assert(op::less_than(std::string("a"), std::string("abc"))); + + assert(!op::less_than(0, -1)); + assert(!op::less_than(0, -1000)); + assert(!op::less_than(-1, -1)); + assert(!op::less_than(0, 0)); + assert(!op::less_than(999999, 999999)); + assert(!op::less_than(0xff, 0xff)); + assert(!op::less_than("hello", "hello")); + assert(!op::less_than("a", "a")); + assert(!op::less_than("z", "a")); + assert(!op::less_than("E", "B")); + assert(!op::less_than(std::string("abc"), std::string("a"))); + assert(!op::less_than(std::string("hi"), std::string("hello"))); +} + +void test_greater_than() { + assert(op::greater_than(0, -1)); + assert(op::greater_than(0, -1000)); + assert(op::greater_than("z", "a")); + assert(op::greater_than("E", "B")); + assert(op::greater_than(std::string("abc"), std::string("a"))); + assert(op::greater_than(std::string("hi"), std::string("hello"))); + + assert(!op::greater_than(5, 6)); + assert(!op::greater_than(1, 10)); + assert(!op::greater_than(0, 1)); + assert(!op::greater_than(-1, 1)); + assert(!op::greater_than(-1, 0)); + assert(!op::greater_than(-1, -1)); + assert(!op::greater_than(0, 0)); + assert(!op::greater_than(999999, 999999)); + assert(!op::greater_than(0xff, 0xff)); + assert(!op::greater_than("hello", "hello")); + assert(!op::greater_than("a", "a")); + assert(!op::greater_than(5.0, 6.665)); + assert(!op::greater_than(6.664, 6.665)); + assert(!op::greater_than(1.199999, 1.2)); + assert(!op::greater_than(0xfe, 0xff)); + assert(!op::greater_than(std::string("hello"), std::string("hi"))); + assert(!op::greater_than("a", "b")); + assert(!op::greater_than("A", "C")); + assert(!op::greater_than("Q", "Z")); + assert(!op::greater_than(std::string("a"), std::string("abc"))); } \ No newline at end of file