You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+20-17Lines changed: 20 additions & 17 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,4 +1,3 @@
1
-
2
1
# Cpp Expression Tree
3
2
4
3
Cpp Expression Tree is a header-only, C++14 library for creating logical expression trees and using them to evaluate instances of user-defined data types.
@@ -8,6 +7,7 @@ Inspired by m-peko/booleval.
8
7
This project is under development and is subject to change. Project contributions and issue reports are welcome. The more the merrier!
9
8
( ... well, maybe not so much for bug reports)
10
9
10
+
11
11
## Table of Contents
12
12
13
13
*[A Quick Example](#a-quick-example)
@@ -18,9 +18,10 @@ This project is under development and is subject to change. Project contribution
18
18
*[Logical Operators](#logical-operators)
19
19
*[Boolean Operators](#boolean-operators)
20
20
*[Using this Library](#using-this-library)
21
-
*[Compilation](#compilation)
21
+
*[Compiling](#compiling)
22
22
*[Running the Unit Tests](#running-the-unit-tests)
23
23
24
+
24
25
## A Quick Example
25
26
26
27
```cpp
@@ -80,11 +81,12 @@ Below is a diagram showing the content of the `expression_tree<my_type>` created
80
81
81
82
As you can imagine, this example code can be expanded to fit a variety of use cases and user-defined types. More complex code examples are provided in the documentation below. Further, there are a number of unit tests located in the `tests` directory, which may be helpful for getting familiar with the library.
82
83
84
+
83
85
## Creating Expression Trees
84
86
85
87
The `expression_tree` class is a templated, RAII container class that takes ownership of user-defined expressions. Instances of `expression_tree` can be moved and/or copied to different contexts while maintaining consistency and memory safety. The template parameter of `expression_tree` defines the type of object that the `expression_tree` will evaluate. Assuming there is a user-defined struct named `my_type`, the templated `expression_tree` type would look like this: `expression_tree<my_type>`. The template argument of `expression_tree` cannot be a primitive type, like `int`, `char`, or `double`.
86
88
87
-
An `expression_tree` cannot be default constructed - it must be initialized with an expression. Users can easily and intuitively define expressions using one of the `make_expr` helper functions found in the namespace `attwoodn::expression_tree`. `make_expr` generates heap-allocated pointers to expression tree nodes and returns them. As such, the returned expression tree node pointers should be managed carefully. If the returned pointers are not wrapped in an `expression_tree` or a smart pointer, they will need to be explicitly `delete`d by the calling code.
89
+
An `expression_tree` cannot be default constructed - it must be initialized with an expression. Users can easily and intuitively define expressions using one of the `make_expr` helper functions found in the namespace `attwoodn::expression_tree`. `make_expr` generates heap-allocated pointers to expression tree nodes and returns them. As such, the returned expression tree node pointers should be managed carefully. If the returned pointers are not wrapped in an `expression_tree` or a smart pointer, they will need to be explicitly deleted by the calling code.
88
90
89
91
Here are some examples of how a user may safely handle the return value from one of the `make_expr` helper functions:
90
92
```cpp
@@ -136,6 +138,7 @@ delete expr_raw;
136
138
137
139
Please see the section below for more information about expression tree nodes.
138
140
141
+
139
142
## Types of Expression Tree Nodes
140
143
141
144
There are two types of expression tree nodes: leaf nodes and op nodes.
@@ -148,9 +151,10 @@ Expression tree leaf nodes contain individual, actionable expressions against wh
148
151
149
152
Expression tree op nodes contain a boolean operation (AND/OR) and have references to a left child node and a right child node. The child nodes may be expression tree leaf nodes, expression tree op nodes, or a permutation of the two. Expression tree op nodes are only ever found in the inner part of the tree. An expression tree op node is always a parent node and it always has two child nodes.
150
153
154
+
151
155
## Logical Operators
152
156
153
-
There are several logical operator functions defined in the namespace `attwoodn::expression_tree::op`, which can be used to create expression tree leaf nodes. The included operators are:
157
+
There are several logical operator functions defined in the namespace `attwoodn::expression_tree::op` that can be used to create expression tree leaf nodes. The included operators are:
assert(!expr.evaluate(incoming_packet)); // fails evaluation. No messages from Pam are accepted (sorry Pam)
231
+
assert(!expr.evaluate(incoming_packet)); // fails evaluation. No packets from Pam are accepted (sorry)
228
232
229
233
// Jim sends a packet with a bad checksum
230
234
incoming_packet.sender_name = "Jim";
231
235
incoming_packet.payload.checksum_ok = false;
232
-
assert(!expr.evaluate(incoming_packet)); // fails evaluation. The packet was from Jim, but checksum was bad
236
+
assert(!expr.evaluate(incoming_packet)); // fails evaluation. Packet was from Jim, but checksum failed
233
237
234
238
// Jim sends a packet whose payload is too big
235
239
incoming_packet.payload.checksum_ok = true;
236
240
incoming_packet.payload.data = "Boy do I have a long story for you - so I was talking to Pam ...";
237
-
assert(!expr.evaluate(incoming_packet)); // fails evaluation. The payload was too big. Give me the TLDR, Jim
241
+
assert(!expr.evaluate(incoming_packet)); // fails evaluation. Payload was too big. Give me the TLDR, Jim
238
242
239
243
// Jim sends a small, rude packet
240
244
incoming_packet.payload.data = "Dwight sux";
241
-
assert(expr.evaluate(incoming_packet)); // passes evaluation. The payload was the right size this time
245
+
assert(expr.evaluate(incoming_packet)); // passes evaluation. The payload was the right size this time
242
246
243
247
// Jim sends a packet has an error code
244
248
incoming_packet.payload.error_code = 404;
245
-
assert(!expr.evaluate(incoming_packet)); // fails evaluation. The payload had an error code
249
+
assert(!expr.evaluate(incoming_packet)); // fails evaluation. The payload had an error code
246
250
```
247
251
248
252
## Boolean Operators
249
253
250
254
Boolean operators are used to chain individual expression tree nodes together. There are two boolean operators that can be used: `AND` and `OR`. These boolean operators are accessible via function calls on the expression nodes. Calling these functions generates a new expression tree node which becomes the parent of the nodes on either side of the boolean operator
251
255
252
-
```cpp
253
-
// some code here
254
-
// shows how nodes are chained with AND and OR functions
255
-
```
256
-
257
256
A complex expression tree can be created by calling these functions to chain multiple expression tree nodes together.
258
257
258
+
259
259
## Using this Library
260
260
261
261
To include this library in your project, simply copy the content of the `include` directory into the `include` directory of your project. That's it! Now where did I put that Staples "Easy" button...?
262
262
263
+
263
264
## Compiling
264
265
265
266
This project uses the CMake build system. The minimum CMake version is set to 3.10.
@@ -274,12 +275,14 @@ make
274
275
275
276
### Running the Unit Tests
276
277
277
-
After cloning and compiling the project, navigate to the build directory that was created. Enable the `BUILD_TESTING` CMake flag if it is not already enabled. Finally, run:
278
+
After cloning and compiling the project, navigate to the build directory that was created. Enable the `BUILD_TESTING` CMake flag if it is not already enabled. My preferred tool for setting CMake flags via the command line is `ccmake`. Simply run `ccmake ..` in the build directory to get a command line UI for modifying CMake project flags. There, you can enable or disable the `BUILD_TESTING` flag, or set the build type from Release to Debug.
279
+
280
+
With the `BUILD_TESTING` flag enabled, run the following command in the build directory:
278
281
279
282
```
280
283
ctest .
281
284
```
282
285
283
286
CTest will execute the unit tests and provide a pass/fail indication for each one.
284
287
285
-
The address sanitizer is enabled on every unit test executable. A test will fail should memory leak during test execution.
288
+
The address sanitizer is enabled on every unit test executable. A test will fail should memory leak during test execution.
0 commit comments