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
As you can imagine, this example code can be expanded to fit a variety of use cases and struct/class type structures. 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.
81
+
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.
84
82
85
83
## Creating Expression Trees
86
84
87
-
The `expression_tree` class is a templated, RAII container class that takes ownership of user-defined expressions. The `expression_tree`class can be moved and/or copied to different contexts while maintaining consistency and safety. The template parameter of `expression_tree`is the type of object that the `expression_tree`can evaluate. Assuming there is a user-defined class 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`.
85
+
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`.
88
86
89
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.
90
88
91
-
// TODO document the thre make_expr functions
92
-
93
-
Here are some examples of how you might handle the return value from one of the `make_expr` helper functions:
89
+
Here are some examples of how a user may safely handle the return value from one of the `make_expr` helper functions:
Please see the section below for more information about expression tree nodes.
140
138
141
139
## Types of Expression Tree Nodes
@@ -152,17 +150,32 @@ Expression tree op nodes contain a boolean operation (AND/OR) and have reference
152
150
153
151
## Logical Operators
154
152
155
-
There are several logical operator functions defined in the namespace `attwoodn::expression_tree::op`, which can be used to create individual expressions within the tree. The included operators are:
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:
156
154
* equals
157
155
* not_equals
158
156
* less_than
159
157
* greater_than
160
158
159
+
Each of the above logical operator functions are templated, and are overloaded to permit passing arguments of either a `const T&` type, or a `T*` type. This means that value types, references, and pointers are all permissible for comparison.
160
+
161
+
Note that there is a known limitation to comparing `T*` types, such as `char*`, using the above operator functions. With `T*` types, no iteration is performed, so comparison is performed only on the data located at the beginning of the pointer address. For example:
Should users wish to compare an iterable collection of elements using the provided operator functions, they should compare container types, such as `std::vector<T>`, instead of pointer types like `T*`.
170
+
161
171
Users of the library can also easily define their own logical operators and use them when creating expressions. Here is an example of how a user might create their own operator functions and use them in an expression:
162
172
163
173
```cpp
174
+
#include<attwoodn/expression_tree.hpp>
175
+
164
176
usingnamespaceattwoodn::expression_tree;
165
177
178
+
// imagine there are two user-defined types, like so:
166
179
struct packet_payload {
167
180
uint16_t error_code;
168
181
std::string data;
@@ -173,24 +186,28 @@ struct packet_payload {
173
186
}
174
187
};
175
188
189
+
// data packet contains an instance of packet_payload, which needs to be evaluated
176
190
classdata_packet {
177
191
public:
178
192
std::string sender_name;
179
193
packet_payload payload;
180
194
};
181
195
196
+
182
197
...
183
198
184
-
// user creates their own logical operator for evaluating incoming packet_payload objects
199
+
200
+
// user creates their own logical operator for evaluating incoming packet_payload objects.
201
+
// only the first function argument is used. The other is an "empty", ignored instance
0 commit comments