ALib C++ Library
Library Version: 2402 R1
Documentation generated by doxygen
Loading...
Searching...
No Matches
calculus.hpp
Go to the documentation of this file.
1/** ************************************************************************************************
2 * \file
3 * This header file is part of module \alib_expressions of the \aliblong.
4 *
5 * \emoji :copyright: 2013-2024 A-Worx GmbH, Germany.
6 * Published under \ref mainpage_license "Boost Software License".
7 **************************************************************************************************/
8#ifndef HPP_ALIB_EXPRESSIONS_PLUGINS_CALCULUS
9#define HPP_ALIB_EXPRESSIONS_PLUGINS_CALCULUS
10
11#ifndef HPP_ALIB_EXPRESSIONS_COMPILERPLUGIN
13#endif
14
15
16namespace alib { namespace expressions {
17
18/**
19 * This inner namespace of module \alib_expressions_nl contains the implementations
20 * of built-in compiler plug-ins.
21 *
22 * In addition, helper class \b %Calculus is defined here, which is the foundation for most of
23 * the built-in functionality.
24 *
25 * It is strongly recommended to use this helper class for the creation of custom compiler plug-ins
26 * instead of deriving such from class \alib{expressions;CompilerPlugin} directly.
27 *
28 * \note Sibling \alib module \alib_files, provides a compiler plug-in dedicated to file and
29 * directory trees.
30 */
31namespace plugins {
32
33#if ALIB_DEBUG
34 #define CALCULUS_CALLBACK(func) func, ALIB_NSTRINGIFY(func)
35 #define CALCULUS_DEFAULT_AUTOCAST nullptr, nullptr
36#else
37 #define CALCULUS_CALLBACK(func) func
38 #define CALCULUS_DEFAULT_AUTOCAST nullptr
39#endif
40
41#define CALCULUS_SIGNATURE(BoxPointerArray) BoxPointerArray, std::extent<decltype(BoxPointerArray)>::value
42
43
44/** ************************************************************************************************
45 * ## 1. Introduction ##
46 * This struct specializes \b %CompilerPlugin and provides generic approaches and implementation
47 * of variants of method \b %TryCompilation.
48 * Consequently, this is the base type of most built-in compiler plug-ins, and is strongly
49 * recommended to consider this struct as the preferred base when implementing custom plug-ins.
50 *
51 * The class implements virtual, overloaded methods
52 * - \alib{expressions::CompilerPlugin;TryCompilation(CIFunction&)},
53 * - \alib{expressions::CompilerPlugin;TryCompilation(CIUnaryOp&)},
54 * - \alib{expressions::CompilerPlugin;TryCompilation(CIBinaryOp&)} and
55 * - \alib{expressions::CompilerPlugin;TryCompilation(CIAutoCast&)}.
56 *
57 * For each <em>AST</em> node type to compile, this class holds a vector or a hash map to store
58 * all information needed for compilation.
59 *
60 * The simple schema of using this class is:
61 * 1. Derive a custom type from this class.
62 * 2. Create constant value objects and C++ native callback functions.
63 * 3. Create constant (\c constexpr) tables with all compilation information.
64 * 4. In the constructor of the derived class, feed the tables into to this struct, using the
65 * corresponding helper methods.
66 *
67 * \note
68 * Sample code and detailed explanations are given with user manual section
69 * \ref alib_expressions_cpcc_calculus "5.4 Class Calculus"
70 * and tutorial section
71 * \ref alib_expressions_tut_ffext "6. Extending The File Filter Sample"
72 *
73 * <p>
74 * \note
75 * The name "Calculus" seems a little overstated, we admit.
76 *
77 * ## 2. Choose Anonymous Namespaces ##
78 *
79 * A good design pattern is to put the callback functions, constant values and compilation information
80 * tables into an anonymous namespace at the start of the compilation unit (.cc or .cpp file) of
81 * your custom plug-in. This way, the linker is not bothered with the function and object names,
82 * which solely are referenced by their address and never need to get linked to other units.
83 *
84 * Just after this anonymous namespace, the implementation of the constructor of the custom
85 * plug-in, should be placed. As explained above, its duty is to fills in the vector/hash map using
86 * the right combination of operator or function argument types, as well as providing a proper
87 * \ref alib_expressions_prereq_sb "sample box" that corresponds to the type of the
88 * output parameter of the native function.
89 *
90 * When implementing a custom plug-in, it may be helpful to have a look at the source code of
91 * the built-in plug-ins provided with module \alib_expressions.
92 * You will see that these implementations are quite straight forward and use some 'handy' local
93 * preprocessor macros that may be copied and used for custom implementations.
94 *
95 * ## 3. Implementing Identifiers and Functions ##
96 * While parent class \b %CompilerPlugin does not make any direct distinction between functions
97 * that are always returning a constant value and those that don't, this class does.
98 * Arguably such functions are always parameterless, hence identifiers. Samples for such constants
99 * are \b "PI" or \b "True".<br>
100 * Such constant identifiers are supported by populating table #ConstantIdentifiers which is a
101 * \c std::vector of elements of type \b %ConstantIdentifiersEntry.
102 * For details on each "table column", refer to the documentation of the fields of
103 * \alib{expressions::plugins::Calculus;ConstantIdentifierEntry}.
104 *
105 * Non-constant identifiers and functions are supported by populating table
106 * #Functions, which is a \c std::vector of elements of type \b %FunctionEntry.
107 * For details on each "table column", refer to the documentation of the fields of
108 * \alib{expressions::plugins::Calculus;FunctionEntry}.
109 *
110 * Some notes:
111 * - It can be specified if function names are case sensitive and whether they might be abbreviated.
112 * - The list of arguments (their types) accepted by a function is to be provided as a
113 * \c std::vector of \ref alib_expressions_prereq_sb "sample boxes". It is
114 * recommended to define such vectors once per unique function "signature" in the anonymous
115 * namespace section of the compilation unit and fill its contents once in the constructor of the
116 * custom plug-in. Such vectors can then be reused for each function that shares the same
117 * signature.
118 * - Variadic functions are supported by adding a final \e nulled \b %Box to the argument list.
119 * All sample argument types before this box are mandatory, but an arbitrary amount of arguments
120 * of likewise arbitrary type may be followed. It is also allowed to add just that one \e nulled
121 * \b %Box to the signature vector, which leads to functions that accept just any number of any
122 * type of argument, including zero arguments.
123 * - With debug builds, besides the callback function pointer, the C++ name of the callback
124 * function is to be provided. For this, macro \ref CALCULUS_CALLBACK is defined.
125 * The macro creates a stringified version of the given function pointer, separated by a comma.
126 * - Flag \doxlinkproblem{structalib_1_1expressions_1_1plugins_1_1Calculus_1_1FunctionEntry.html;a6bdb2157e6bb046c17b9d8ef7dd5969a;FunctionEntry::IsCTInvokable}
127 is a boolean value
128 * that denotes whether a function can be evaluated at compile-time in the case that all of the
129 * parameters given in the expression are constant.
130 * If so, this struct will do the invocation at compile-time and return the constant result value
131 * instead of the function call.<br>
132 * Most built-in functions are compile-time invokable. For example most mathematical functions
133 * like \c log(Float) or \c sin(Float) can be evaluated at compile-time (again, only in the case
134 * that the given parameters are constant). The reason is, that
135 * these functions are independent from custom scope data.
136 * In contrast to this, custom functions, especially even parameterless identifiers usually are
137 * dependent on scope information and thus often can not be evaluated at compile-time.
138 *
139 * ## 4. Implementing Operators ##
140 *
141 * ### 4.1 Unary And Binary Operators ###
142 * Apart from some specialities for binary operators documented in the next section, this class
143 * treats unary and binary the same.
144 * Wherever a second operator argument's type is requested, in case of unary operators static
145 * type specifier \alib{expressions;Types::Void} is to be given.
146 *
147 * The compilation of unary and binary operators is supported by populating hash map #Operators.
148 * For feeding the map with entries, the following convenience types and methods are provided:
149 * - #AddOperator<br>
150 * This function adds compilation information for a single operator to field #Operators.
151 *
152 * - #OperatorTableEntry<br>
153 * This is a type definition that allows to define tables with compilation information on
154 * operators. It is recommended to create such tables as \c constexpr data in an anonymous
155 * namespace of the compilation unit.
156 *
157 * - #AddOperators<br>
158 * This is a pair of overloaded functions. One of them is templated and just used to deduce
159 * the length of the given table of static data. This table is then fed as a pointer, together
160 * with the table's size to the second method, which in turn feeds the table entries into
161 * field #Operators.
162 *
163 * In other words: Method #AddOperator defines a single operator, while #AddOperators defines
164 * "bulk" data on operators which is defined in a static table.
165 * For details of the functions and types, consult the corresponding documentation.
166 *
167 * As documented in user manual section
168 * \ref alib_expressions_operators_aliases "9.4 Type-Specific Operator Aliases",
169 * module \alib_expressions_nl supports the use of alias operators.
170 * This is reflected by this class with:
171 *
172 * - #OperatorAliases<br>
173 * A hash map that collects information about unary and binary operator aliases.
174 *
175 * - #AddOperatorAlias<br>
176 * This function adds information about an operator alias to field #OperatorAliases.
177 *
178 * - #OperatorAliasTableEntry
179 * A type definition that allows to define tables with information about operator aliases.
180 * It is recommended to create such tables as \c constexpr data in an anonymous
181 * namespace of the compilation unit.
182 *
183 * - AddOperatorAliases<br>
184 * This is a pair of overloaded functions. One of them is templated and just used to deduce
185 * the length of the given table of static data. This table is then fed as a pointer, together
186 * with the table size to the second method, which in turn feeds the table entries into
187 * field #OperatorAliases.
188 *
189 *
190 * ### 4.2 Specifics For Binary Operators ###
191 *
192 * #### Aliasing '==' With '=': ####
193 * With the use of this class it is \e not necessary to define alias <c>'='</c> for binary
194 * operator <c>'=='</c>, because this alias replacement is internally always made for any
195 * combination of argument types, when compilation flag
196 * \alib{expressions;Compilation::AliasEqualsOperatorWithAssignOperator} is set in field
197 * \alib{expressions;Compiler::CfgCompilation}.
198 *
199 * #### Aliasing Bitwise Boolean Operators: ####
200 * In contrast to the above, compilation flag \alib{expressions;Compilation::AllowBitwiseBooleanOperators}
201 * affects only built-in type \e boolean - just as the flag's name suggests.
202 * The flag is therefore tested only in derived plug-in \alib{expressions;plugins::Arithmetics}.
203 * In other words: to allow for example operator <c>'&'</c> to be used as an alias for operator
204 * <c>'&&'</c> defined on custom types, this has to be explicitly added as a set alias definitions
205 * for each combination of types in question.
206 *
207 * #### Support For Compile-Time Optimization: ####
208 * For binary operators, this class provides a mechanism to provide information on possible
209 * compile-time optimizations.
210 * Samples of possible binary operator optimizations are given in documentation of struct
211 * \alib{expressions;CompilerPlugin::CIBinaryOp}.
212 *
213 * The following fields and methods are provided:
214 *
215 * - #BinaryOperatorOptimizations<br>
216 * A hash-map that collects information about possible optimizations of binary operators
217 * when either of the operands are a specific constant value.
218 *
219 * - #BinaryOpOptimizationsTableEntry<br>
220 * A type definition that allows to feed tables (arrays of this type) with information about
221 * binary operator optimizations.
222 * It is recommended to create such tables as \c constexpr data in an anonymous
223 * namespace of the compilation unit.
224 *
225 * - #AddBinaryOpOptimizations<br>
226 * A pair of overloaded functions. One of them is templated and just used to deduce
227 * the length of the given table of static data. This table is then fed as a pointer, together
228 * with the table size to the second method, which in turn feeds the table entries into
229 * hash map #BinaryOperatorOptimizations.
230 *
231 * # Reference Documentation #
232 **************************************************************************************************/
234{
235 /**
236 * Boolean to denote if a callback function allows compile-time invocation.
237 * If \c true, on constant function input (either from expression string literals or sub-expressions
238 * that have been optimized to constant input) the program can be optimized by invoking the
239 * \alib{expressions;CallbackDecl} already at compile-time.
240 *
241 * This flag is set for most built-in functions, e.g. arithmetic calculations, but usually
242 * can not be set custom callbacks, as those usually rely on custom scope objects which are
243 * available only at evaluation-time.
244 *
245 * \note
246 * This type is used with helper class \alib{expressions;plugins::Calculus} but exposed
247 * as a namespace type for convenience, together with constants #CTI and
248 * #ETI
249 *
250 */
251 using CTInvokable= bool;
252
253
254 /**
255 * Used for values of #CTInvokable flags.<br>
256 * The use of this constant makes code more readable.
257 */
258 static constexpr CTInvokable CTI = true;
259
260 /**
261 * Used for values of #CTInvokable flags to denote that a callback function
262 * is only invokable at evaluation-time.<br>
263 * The use of this constant makes code more readable.
264 */
265 static constexpr CTInvokable ETI = false;
266
267 /**
268 * This class uses monotonic allocation, which is well supported by the common way how this
269 * type is used.
270 */
272
273 /** ********************************************************************************************
274 * Constructor.
275 * @param name Assigned to field \alib{expressions;CompilerPlugin::Name}.
276 * @param compiler The compiler we will get attached to
277 **********************************************************************************************/
278 Calculus( const NString& name, Compiler& compiler )
279 : CompilerPlugin( name, compiler )
280 , allocator ( 4 * 1024 )
281 , Operators ( &allocator )
284 {
285 #if ALIB_DEBUG_MONOMEM
286 allocator.LogDomain= "MA/EXPR/CLCLS";
287 #endif
288 }
289
290 /** ********************************************************************************************
291 * Virtual destructor.
292 **********************************************************************************************/
293 virtual ~Calculus() override
294 {}
295
296
297 // #############################################################################################
298 // Constant Identifiers, Identifiers and Functions
299 // #############################################################################################
300
301 /**
302 * An entry of field #ConstantIdentifiers. Describes how the identifier is recognized and
303 * the constant value to return for it.
304 */
306 {
307 /** The name, minimum length and letter case sensitivity of the function to recognize. */
309
310 /** The constant result. */
312 };
313
314 /** List of identifiers that return constant values to be compiled by this plug-in. */
315 std::vector<ConstantIdentifierEntry> ConstantIdentifiers;
316
317 /**
318 * An entry of field #Functions. Describes how the function is recognized and
319 * the callback function and return type for it.
320 */
322 {
323 /** The name, minimum length and letter case sensitivity of the function to recognize. */
325
326 /**
327 * A pointer to list of pointers to sample boxes that describe the function signature.
328 * If \c nullptr, then the function does not accept parameters (aka is an identifier).
329 *
330 * To denote variadic parameters (similar to C/C++ ellipsis operator \c "..." ), either
331 * \c nullptr or a \ref alib_boxing_more_void_void "void box" may be given as the last
332 * array element. All prior provided boxes represent mandatory arguments, while the
333 * function accepts an arbitrary amount of arguments of arbitrary type in addition.
334 *
335 * The length of this list is given with field #SignatureLength.
336 *
337 * \see Macro \ref CALCULUS_SIGNATURE which is recommended to be used to pass both
338 * fields (this and #SignatureLength). The macro accepts a C++ array of \b Box* and
339 * deducts the array's length from the declaration type of the given array.
340 */
342
343 /**
344 * See #Signature for more information.
345 */
347
348 /** Callback function to add to the program. If \c nullptr, field #ResultType is
349 * used as both: a constant value added to the program and the result type! */
351
352
353 #if ALIB_DEBUG
354 /**
355 * The C++ name of the callback function (only available with debug builds of the
356 * library. Use preprocessor macro \ref CALCULUS_CALLBACK to provide this field
357 * together with field #Callback. The macro selects to prune the name string
358 * in release compilations. */
359 const char* DbgCallbackName;
360 #endif
361
362 /**
363 * The result type given as a pointer to a \ref alib_expressions_prereq_sb "sample box".
364 *
365 * \note
366 * If #Callback is \c nullptr, this box changes its meaning from being just a sample that
367 * provides the return type of the callback function, to being the 'real' constant
368 * result value that the function represents. However, it is preferable, to
369 * implement such constant functions using field
370 * \alib{expressions::plugins;Calculus::ConstantIdentifiers}
371 */
373
374 /**
375 * Denotes, if the callback function is allowed to be invoked on the
376 * \alib{expressions;Scope} object used at compile-time.
377 * This scope object is of the same (eventually custom) type as the one for evaluation,
378 * however the evaluation-specific data is not set.
379 * If allowed, such invocation is performed, if all function arguments are constant and
380 * instead of the function, the result is returned.
381 */
383 };
384
385 /** List of functions to be compiled by this plug-in. */
386 std::vector<FunctionEntry> Functions;
387
388 /** ********************************************************************************************
389 * Searches in vectors #Functions and #ConstantIdentifiers for an entry matching \p{name} and,
390 * if found, adds either a constant value or a callback function to \p{ciFunction}.
391 *
392 * This plug-in corrects abbreviated and letter case differences in functions within
393 * in/out parameter \alib{expressions::CompilerPlugin;CIFunction::Name}.
394 *
395 * @param[in,out] ciFunction The compilation result.
396 * @return \c true if an entry was found in #Functions and a corresponding command
397 * was added to \p{ciFunction}. \c false otherwise.
398 **********************************************************************************************/
400 virtual bool TryCompilation( CIFunction& ciFunction ) override;
401
402 // #############################################################################################
403 // Operators
404 // #############################################################################################
405 protected:
406
407 /** Key type for operator hash maps #Operators and OperatorAliases. */
409 {
410 const String op; ///< A string defining the operator.
411 const std::type_info& lhs; ///< Left-hand side type.
412 const std::type_info& rhs; ///< Right-hand side type. For unary operators
413 ///< equals to <c>typeid(void)</c>.
414
415 /** Hash functor for operator hash map. */
416 struct Hash
417 {
418 /** Calculates a hash code for objects of type \b OperatorKey.
419 * @param src The node to hash.
420 * @return The hash code. */
421 std::size_t operator()(const OperatorKey& src) const
422 {
423 return src.op.Hashcode()
424 + 4026031ul * src.lhs.hash_code()
425 + 8175383ul * src.rhs.hash_code();
426 }
427
428 };
429
430 /** Equality functor for operator hash map. */
431 struct EqualTo
432 {
433 /** Compares two objects of type \b OperatorKey.
434 * @param left The left-hand side object.
435 * @param right The left-hand side object.
436 * @return The result of the comparison. */
437 bool operator()(const OperatorKey& left, const OperatorKey& right ) const
438 {
439 return left.op == right.op
440 && left.lhs == right.lhs
441 && left.rhs == right.rhs;
442 }
443 };
444 };
445
446
447 public:
448
449 /**
450 * Hash map assigning combinations of (unary and binary) operators and its argument types to a
451 * tuple providing information about a callback function.
452 *
453 * The tuple stored, contains the function pointer and the functions' return type.
454 * A third member of type #CTInvokable indicates whether the callback function is allowed to be
455 * invoked on the \alib{expressions;Scope} object used at compile-time.
456 * This scope object is of the same (eventually custom) type as the one for evaluation, however
457 * the evaluation-specific data is not set. In other words, the third tuple member denotes
458 * if during program compilation the function might be invoked when the operator's argument(s)
459 * are constant.
460 *
461 * A fourth tuple member of type \alib{strings;TString;String} is available only with debug builds
462 * and receives the name of the callback function.
463 *
464 * \note
465 * This map, similar to map #OperatorAliases is best to be filled using corresponding
466 * \e add-methods #AddOperator and #AddOperators.<br>
467 * Usually this is done once in the constructor of derived classes.
468 */
469 HashMap<OperatorKey,
470 std::tuple<CallbackDecl, Box, CTInvokable ALIB_DBG( , const char* ) >,
471 OperatorKey::Hash,
473
474 /**
475 * Hash map assigning combinations of alias versions of operators and their argument types to
476 * the original operator.
477 *
478 * \note
479 * This map, similar to map #Operators is best to be filled using corresponding
480 * \e add-methods #AddOperatorAlias and #AddOperatorAliases.<br>
481 * Usually this is done once in the constructor of derived classes.
482 */
484 String,
487
488
489 /**
490 * Entry of input tables (arrays) used with methods #AddOperators to perform bulk-loading of
491 * compile definition data into map #Operators.<br>
492 * The tuple elements are:
493 * - The operator to compile.
494 * - The type of the first argument of the operator.
495 * - The type of the right-hand side argument of the operator.
496 * For unary operators, value \alib{expressions;Types::Void} is to be provided.
497 * - The callback function. Set to \c nullptr if operator evaluates constant.
498 * - The C++ name of the callback function. (This tuple element is only available in debug
499 * compilations of the library.)
500 * - The result type sample box, respectively, if \b callback is \c nullptr, the constant result
501 * value.
502 * - Flag to denote if the callback function allows compile-time invocation and thus on constant
503 * input the program can be optimized. This is true e.g. for arithmetic functions, but usually
504 * not for custom operators that rely on scope objects available only at evaluation time.
505 */
506 using OperatorTableEntry= const std::tuple< String, Type, Type,
508 ALIB_DBG(const char* ,)
510
511 /**
512 * Entry of input tables (arrays) used with method #AddOperatorAliases to perform bulk-loading
513 * of operator alias definition data into map #OperatorAliases.<br>
514 * The tuple elements are:
515 * - The alias operator.
516 * - The type of first argument of the operator.
517 * - The type of the right-hand side argument of the operator.
518 * For unary operators, value \alib{expressions;Types::Void} is to be provided.
519 * - The operator that gets aliased.
520 */
521 using OperatorAliasTableEntry= const std::tuple<String, Type, Type, String>;
522
523
524
525 #if defined(ALIB_DOX)
526 /** ********************************************************************************************
527 * Adds an entry to the operator definition map #Operators.
528 *
529 * \see
530 * If multiple operators are to be defined, consider the use of #AddOperators, which is a
531 * variant of this method that allows effective bulk loading.
532 *
533 * @param op The operator.
534 * @param lhsType The type of the first argument that the operator is defined for.
535 * @param rhsType The type of the right-hand side argument that the operator is defined
536 * for.
537 * For unary operators, value \alib{expressions;Types::Void} is to be
538 * provided.
539 * @param callback The callback function to execute.
540 * @param dbgCallbackName The name of the C++ name of the callback function.
541 * \note This parameter is available only in debug version of the
542 * library.
543 * @param cti See #CTInvokable for the meaning of this flag.
544 * @param resultType The result type of the callback function.
545 **********************************************************************************************/
546 void AddOperator ( const String& op, Type lhsType, Type rhsType, CallbackDecl callback,
547 #if ALIB_DEBUG
548 const char* dbgCallbackName,
549 #endif
550 Type resultType,
551 CTInvokable cti );
552 #else // clang would complain about the doxing of parameter dbgCallbackName
554 void AddOperator ( const String& op, Type lhsType, Type rhsType, CallbackDecl callback,
555 #if ALIB_DEBUG
556 const char* dbgCallbackName,
557 #endif
558 Type resultType,
559 CTInvokable cti );
560 #endif
561
562
563 /** ********************************************************************************************
564 * Templated helper method. Deduces the array size of the given table and passes it
565 * to \ref AddOperators(OperatorTableEntry* table, size_t length).
566 *
567 * @tparam TCapacity Implicitly deferred size of the array provided.
568 * @param table The table containing operator compilation information.
569 **********************************************************************************************/
570 template<size_t TCapacity>
571 void AddOperators ( OperatorTableEntry (&table) [TCapacity] )
572 {
573 AddOperators( &table[0], TCapacity );
574 }
575
576 /** ********************************************************************************************
577 * Loads all entries of the given table into hash map #Operators.
578 *
579 * Note, that usually, the given table is a constexpr array located in an anonymous namespace
580 * of a compilation unit.<br>
581 * It can be passed as a reference to templated helper method, which defers the length of the
582 * table implicitly.
583 *
584 * @param table The table containing operator compilation information.
585 * @param length The table containing operator compilation information.
586 **********************************************************************************************/
588 void AddOperators ( OperatorTableEntry* table, size_t length );
589
590 /** ********************************************************************************************
591 * Adds an alias operator to hash table #OperatorAliases.
592 *
593 * \see
594 * If multiple alias operators are to be defined, consider the use of #AddOperatorAliases,
595 * which is a variant of this method that allows effective bulk loading.
596 *
597 * @param alias The alias for operator \p{op}.
598 * @param lhsType The left-hand side argument type that the operator is defined for.
599 * @param rhsType The right-hand side argument type that the operator is defined for.
600 * @param op The operator aliased by \p{alias}.
601 **********************************************************************************************/
602 void AddOperatorAlias ( const String& alias, Type lhsType, Type rhsType, const String& op );
603
604 /** ********************************************************************************************
605 * Templated helper method. Deduces the array size of the given table and passes it
606 * to \ref AddOperatorAliases(OperatorAliasTableEntry* table, size_t length).
607 *
608 * @tparam TCapacity Implicitly deferred size of the array provided.
609 * @param table The table containing operator compilation information.
610 **********************************************************************************************/
611 template<size_t TCapacity>
612 void AddOperatorAliases( OperatorAliasTableEntry (&table) [TCapacity] )
613 {
614 AddOperatorAliases( &table[0], TCapacity );
615 }
616
617 /** ********************************************************************************************
618 * Loads all entries of the given table into hash map #OperatorAliases.
619 *
620 * Note, that usually, the given table is a constexpr array located in an anonymous namespace
621 * of a compilation unit.<br>
622 * It can be passed as a reference to templated helper method, which defers the length of the
623 * table implicitly.
624 *
625 * @param table The table containing operator compilation information.
626 * @param length The table containing operator compilation information.
627 **********************************************************************************************/
628 void AddOperatorAliases( OperatorAliasTableEntry* table, size_t length );
629
630
631 // #############################################################################################
632 // Binary operator optimizations
633 // #############################################################################################
634 protected:
635
636 /** Key type for operator hash maps #Operators and OperatorAliases. */
638 {
639 const String op; ///< The operator to optimize.
640 lang::Side constSide; ///< Denotes a left- or right-hand side optimization.
641 const Box constVal; ///< The type and value of the constant argument.
642 const std::type_info& other; ///< The type of the non-constant argument.
643
644 /** Hash functor for operator hash map. */
645 struct Hash
646 {
647 /** Calculates a hash code for objects of type \b OperatorKey.
648 * @param src The node to hash.
649 * @return The hash code. */
650 std::size_t operator()(const BinOpOptKey& src) const
651 {
652 return ( std::hash<String>()(src.op)
653 + 6949ul * std::hash<Box>()(src.constVal)
654 + 14033ul * src.other.hash_code()
655 ) ^ ( src.constSide == lang::Side::Left ? static_cast<size_t>( 0)
656 : static_cast<size_t>(-1) );
657 }
658 };
659
660 /** Equality functor for operator hash map. */
661 struct EqualTo
662 {
663 /** Compares two objects of type \b OperatorKey.
664 * @param lhs The left-hand side object.
665 * @param rhs The left-hand side object.
666 * @return The result of the comparison. */
667 bool operator()(const BinOpOptKey& lhs, const BinOpOptKey& rhs ) const
668 {
669 return lhs.op == rhs.op
670 && lhs.constSide== rhs.constSide
671 && lhs.constVal == rhs.constVal
672 && lhs.other == rhs.other;
673 }
674 };
675 };
676
677 public:
678 /**
679 * Hash map storing optimization information for binary operators where either argument is
680 * constant.<br>
681 * This map may be filled with #AddBinaryOpOptimizations, which is usually done in the.
682 * constructor of derived classes.
683 *
684 * The stored element of type \b Box may contain either, a constant result value that replaces
685 * the binary operator (as in <c> x || true</c>) or be a \e nulled box, which indicates that
686 * the result equals the non-constant argument (as in <c>x && true</c>).
687 */
688 HashMap <BinOpOptKey, Box,
689 BinOpOptKey::Hash,
691
692 /**
693 * Entry of arrays used with methods #AddBinaryOpOptimizations to perform bulk-loading of
694 * optimization data to hash map #BinaryOperatorOptimizations.<br>
695 * The tuple element's meanings are:
696 * - The operator to optimize.
697 * - Denotes if an optimization applies if the left-hand side or right-hand side argument
698 * is constant.
699 * - The type and value of the constant argument.
700 * - The type of the non-constant argument.
701 * - Either, a constant result value that replaces the binary operator
702 * (as in <c> x || true</c>) or a \e nulled box, which indicates that the result equals the
703 * non-constant argument (as in <c>x && true</c>).
704 */
705 using BinaryOpOptimizationsTableEntry= const std::tuple<String, lang::Side, Type, const Box&, const Box&>;
706
707
708 /** ********************************************************************************************
709 * Templated helper method. Deduces the array size of the given table and passes it
710 * to \ref AddBinaryOpOptimizations(BinaryOpOptimizationsTableEntry*, size_t).
711 *
712 * @tparam TCapacity Implicitly deferred size of the array provided.
713 * @param table The table containing operator compilation information.
714 **********************************************************************************************/
715 template<size_t TCapacity>
717 {
718 AddBinaryOpOptimizations( &table[0], TCapacity );
719 }
720
721 /** ********************************************************************************************
722 * Loads all entries of the given table into hash map #BinaryOperatorOptimizations.
723 *
724 * Note, that usually, the given table is a constexpr array located in an anonymous namespace
725 * of a compilation unit.<br>
726 * It can be passed as a reference to templated helper method, which defers the length of the
727 * table implicitly.
728 *
729 * @param table The table containing operator compilation information.
730 * @param length The table containing operator compilation information.
731 **********************************************************************************************/
733 void AddBinaryOpOptimizations( BinaryOpOptimizationsTableEntry* table, size_t length );
734
735 /** ********************************************************************************************
736 * Searches in #Operators for an entry matching the combination of
737 * \doxlinkproblem{structalib_1_1expressions_1_1CompilerPlugin_1_1CIUnaryOp.html;a2eba8729cc1606107496dbd797966b5c;CIUnaryOp::Operator}
738 * and the argument type of operand found with iterator
739 * \doxlinkproblem{structalib_1_1expressions_1_1CompilerPlugin_1_1CompilationInfo.html;afbf28a2c7a1396f91fa6a120a4f65d06;CompilationInfo::ArgsBegin}.
740 * (The second argument type of the key of the hash map #Operators is set to
741 * \alib{expressions;Types::Void}).
742 * If found, the corresponding callback function and result type are added the \p{CIUnaryOp}.
743 *
744 * Before the search, it is checked whether the given operator is an alias for another
745 * operator. Operator aliases might be defined by filling map #OperatorAliases in the
746 * constructor of the derived types.
747 * If so, the corrected operator is returned with in/out parameter
748 * \doxlinkproblem{structalib_1_1expressions_1_1CompilerPlugin_1_1CIUnaryOp.html;a2eba8729cc1606107496dbd797966b5c;CIUnaryOp::Operator}.
749 *
750 * @param ciUnaryOp The compilation result.
751 * @return \c true if an entry was found in #Operators and a corresponding command was added to
752 * \p{ciUnaryOp}. \c false otherwise.
753 **********************************************************************************************/
755 virtual bool TryCompilation( CIUnaryOp& ciUnaryOp ) override;
756
757
758 /** ********************************************************************************************
759 * Searches in #Operators for an entry matching the combination of
760 * \doxlinkproblem{structalib_1_1expressions_1_1CompilerPlugin_1_1CIBinaryOp.html;a2eba8729cc1606107496dbd797966b5c;CIBinaryOp::Operator}
761 * and the argument types of operands found with argument iterators
762 * \doxlinkproblem{structalib_1_1expressions_1_1CompilerPlugin_1_1CompilationInfo.html;afbf28a2c7a1396f91fa6a120a4f65d06;CompilationInfo::ArgsBegin}
763 * and
764 * \doxlinkproblem{structalib_1_1expressions_1_1CompilerPlugin_1_1CompilationInfo.html;a28ed4e83d13c904617e09c519bee73df;CompilationInfo::ArgsBegin}.
765 * If found, the corresponding callback function and result type are added the \p{CIBinaryOp}.
766 *
767 * Before the search, it is checked whether the given operator is an alias for another
768 * operator. Operator aliases might be defined by filling map #OperatorAliases in the
769 * constructor of the derived types.
770 * If so, the corrected operator is returned with in/out parameter
771 * \doxlinkproblem{structalib_1_1expressions_1_1CompilerPlugin_1_1CIBinaryOp.html;a2eba8729cc1606107496dbd797966b5c;CIBinaryOp::Operator}.
772 *
773 * @param ciBinaryOp The compilation info struct.
774 * @return \c true if an entry was found in #Operators and a corresponding command was added
775 * to \p{ciBinaryOp}. \c false otherwise.
776 **********************************************************************************************/
778 virtual bool TryCompilation( CIBinaryOp& ciBinaryOp ) override;
779
780
781 // #############################################################################################
782 // Auto-Casts
783 // #############################################################################################
784
785 /**
786 * An entry of field #AutoCasts. Defines auto-casts for custom types.
787 */
789 {
790 /** The type that is to be automatically casted.*/
792
793 /**
794 * List of operators that the auto-cast accepts.
795 * If \e nulled, then just any operator that is not in #OperatorsDeclined is accepted.
796 */
797 std::vector<String>* OperatorsAccepted;
798
799 /**
800 * List of operators that the auto-cast does not accept. An operator should not appear
801 * in both lists, this one and list #OperatorsAccepted. However, it is does, then the
802 * operator is not accepted.
803 *
804 * A value of \c nullptr is allowed to indicate no declined operators.
805 */
806 std::vector<String>* OperatorsDeclined;
807
808 /**
809 * Callback function to add to the program that performs the auto-cast.
810 *
811 * If \c nullptr is given, then an internal, predefined callback is used, which
812 * returns a value of type \alib{expressions;Types::Integer} which is generated by
813 * taking the \alib{boxing;Box::Data;raw value} of the argument box. This is
814 * especially useful for any boxed enum type that is to be made compatible
815 * with bitwise boolean operators (and other integral calculations and functions).
816 */
818
819
820 #if ALIB_DEBUG
821 /**
822 * The C++ name of the callback function (only available with debug builds of the
823 * library. Use preprocessor macro \ref CALCULUS_CALLBACK to provide this field
824 * together with field #Callback. The macro selects to prune the name string
825 * in release compilations.
826 *
827 * If #Callback is set to nullptr, the name of the internal function (\e "any2int")
828 * is inserted automatically. Instead of aforementioned macro \ref CALCULUS_CALLBACK
829 * use macro \ref CALCULUS_DEFAULT_AUTOCAST instead.
830 */
831 const char* DbgCallbackName;
832 #endif
833
834 /**
835 * The result type given a \ref alib_expressions_prereq_sb "sample box".
836 *
837 * If field #Callback is \c nullptr to specify the use of the internal, default cast
838 * function, this field will be ignored and \alib{expressions;Types::Integer}, will
839 * be set instead. Hence, in this case, this field can be specified as \c nullptr.
840 */
842
843 /**
844 * This is the name of the function that reverses the cast. The function is used when an
845 * expression with an auto-cast functions is \e decompiled to generate compilable,
846 * optimized expression strings.
847 *
848 * \note
849 * This method is needed only if "normalized, optimized expression strings" are
850 * to be generated. For more information on this topic consult manual section
851 * \ref alib_expressions_details_optimizations_norm.
852 *
853 * \note
854 * Note that, if the aforementioned feature is used, then this function name has to be
855 * provided together with the implementation of the expression function itself,
856 * even if the internal default cast implementation (activated by setting field
857 * #Callback to \c nullptr) is used. The rationale is, that this library can not
858 * automatically convert integral types back to a custom type. This is even true
859 * for simple enumeration types.
860 */
862 };
863
864 /** List of auto-casts to be compiled by this plug-in. */
865 std::vector<AutoCastEntry> AutoCasts;
866
867
868 /** ********************************************************************************************
869 * Searches in #AutoCasts for an entry matching the combination of
870 * \doxlinkproblem{structalib_1_1expressions_1_1CompilerPlugin_1_1CIAutoCast.html;a2eba8729cc1606107496dbd797966b5c;CIAutoCast::Operator} and the type(s) that might be auto-casted.
871 *
872 * An entry in #AutoCasts might also be defined to work on just all operators.
873 *
874 * For the very frequent use case of auto-casting custom enum types to integral types, only
875 * fields
876 * \doxlinkproblem{structalib_1_1expressions_1_1plugins_1_1Calculus_1_1AutoCastEntry.html;ac127c6ab57163304f334a48751db6897;AutoCastEntry::Type}
877 * and
878 * \doxlinkproblem{structalib_1_1expressions_1_1plugins_1_1Calculus_1_1AutoCastEntry.html;a1b78ad7a906e7c8e0f3d5b471ecb8fbf;AutoCastEntry::ReverseCastFunctionName}
879 * have to be provided.
880 *
881 * \note
882 * This method of this helper class is not applicable if one of the following conditions apply
883 * to a use case:
884 * - Different auto-casts are to be applied for the first and second arguments of binary
885 * operators.
886 * - The custom auto-cast method is not compile-time invokable.
887 *
888 * \note
889 * In this case, a custom implementation of this method has to be provided to fetch
890 * these cases. The custom method might then invoke this base implementation.
891 *
892 * @param autoCast The compilation info struct.
893 * @return \c true if a matching entry was found in #AutoCasts and a corresponding command
894 * was added to \p{autoCast}. \c false otherwise.
895 **********************************************************************************************/
897 virtual bool TryCompilation(CIAutoCast& autoCast) override;
898};
899
900}} // namespace alib[::expressions::plugin]
901
902/// Type alias in namespace \b alib.
904
905} // namespace [alib]
906
907
908
909
910#endif // HPP_ALIB_EXPRESSIONS_PLUGINS_CALCULUS
std::size_t Hashcode() const
#define ALIB_API
Definition alib.hpp:538
#define ALIB_DBG(...)
Definition alib.hpp:457
#define ALIB_DEBUG
Definition prepro.dox:21
Box(*)(Scope &scope, ArgIterator argsBegin, ArgIterator argsEnd) CallbackDecl
const alib::boxing::Box & Type
Definition alib.cpp:57
strings::TString< character > String
Type alias in namespace alib.
boxing::Box Box
Type alias in namespace alib.
bool operator()(const BinOpOptKey &lhs, const BinOpOptKey &rhs) const
Definition calculus.hpp:667
std::size_t operator()(const BinOpOptKey &src) const
Definition calculus.hpp:650
const std::type_info & other
The type of the non-constant argument.
Definition calculus.hpp:642
const String op
The operator to optimize.
Definition calculus.hpp:639
const Box constVal
The type and value of the constant argument.
Definition calculus.hpp:641
lang::Side constSide
Denotes a left- or right-hand side optimization.
Definition calculus.hpp:640
bool operator()(const OperatorKey &left, const OperatorKey &right) const
Definition calculus.hpp:437
std::size_t operator()(const OperatorKey &src) const
Definition calculus.hpp:421
const String op
A string defining the operator.
Definition calculus.hpp:410
const std::type_info & lhs
Left-hand side type.
Definition calculus.hpp:411
void AddOperatorAliases(OperatorAliasTableEntry(&table)[TCapacity])
Definition calculus.hpp:612
virtual ALIB_API bool TryCompilation(CIFunction &ciFunction) override
Definition calculus.cpp:351
std::vector< ConstantIdentifierEntry > ConstantIdentifiers
Definition calculus.hpp:315
HashMap< OperatorKey, String, OperatorKey::Hash, OperatorKey::EqualTo > OperatorAliases
Definition calculus.hpp:486
HashMap< BinOpOptKey, Box, BinOpOptKey::Hash, BinOpOptKey::EqualTo > BinaryOperatorOptimizations
Definition calculus.hpp:690
void AddOperators(OperatorTableEntry(&table)[TCapacity])
Definition calculus.hpp:571
void AddBinaryOpOptimizations(BinaryOpOptimizationsTableEntry(&table)[TCapacity])
Definition calculus.hpp:716
const std::tuple< String, Type, Type, CallbackDecl, Type, CTInvokable > OperatorTableEntry
Definition calculus.hpp:506
std::vector< FunctionEntry > Functions
Definition calculus.hpp:386
HashMap< OperatorKey, std::tuple< CallbackDecl, Box, CTInvokable ALIB_DBG(, const char *) >, OperatorKey::Hash, OperatorKey::EqualTo > Operators
Definition calculus.hpp:472
void AddOperator(const String &op, Type lhsType, Type rhsType, CallbackDecl callback, const char *dbgCallbackName, Type resultType, CTInvokable cti)
Definition calculus.cpp:26
static constexpr CTInvokable ETI
Definition calculus.hpp:265
Calculus(const NString &name, Compiler &compiler)
Definition calculus.hpp:278
std::vector< AutoCastEntry > AutoCasts
Definition calculus.hpp:865
static constexpr CTInvokable CTI
Definition calculus.hpp:258
const std::tuple< String, lang::Side, Type, const Box &, const Box & > BinaryOpOptimizationsTableEntry
Definition calculus.hpp:705
const std::tuple< String, Type, Type, String > OperatorAliasTableEntry
Definition calculus.hpp:521
void AddOperatorAlias(const String &alias, Type lhsType, Type rhsType, const String &op)
Definition calculus.cpp:102