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