ALib C++ Library
Library Version: 2402 R1
Documentation generated by doxygen
Loading...
Searching...
No Matches
FToLiteral Struct Reference

Description:

This struct constitutes a type declaration for a box-function. The function is used to create parsable expression "literals" from constant values of custom type stored in boxes.

The function is used by the library if all of the following occurs:

  • If custom identifiers, functions or operator callback functions return a custom type.
  • If such types can be constants and are announced to the compiler as such.
  • If method Expression::GetOptimizedString is called.
  • If such string is to be used as input to compiling expressions.

If the last condition is met, compilation of the "normalized optimized expression string " would fail. If it is not met, then without a proper implementation of this function, the only "damage" is that such string would show an integral value where a constant custom type was expected.

The challenge of implementing this box-function for a custom type, is to convert constants of custom types back into a normalized, human readable but also compilable expression string. As the expression syntax only defines the built-in literal types Integer , Float and String , the constants have to be created using either appropriate custom identifiers or "constructor functions" that have to be provided in addition along with the implementation of this box-function to make it compilable.

A sample for that situation is given in chapter 11.5.6 Normalized, Optimized Expression Strings of the Programmer's Manual.

The identifiers and constructor functions in turn need to be compile-time evaluatable to ensure that recompiling the optimized string results to constants so that the same optimized expression program is generated..

Sample:

So far, this probably sounded a little complicated. Let us look step by step at the sample given in the aforementioned manual section, that is solved internally by the library using this box-function declaration.

Compiler plug-in DateAndTime introduces ALib class TimePointBase::Duration to expressions. This is for example done by defining identifiers as follows:

{ *descriptor++, CALCULUS_SIGNATURE(Signatures::I ), CALCULUS_CALLBACK(nanosecondsInt ), &Types::Duration , CTI },

The "constructor functions" are declared to be compile-time invokable and return a constant value at compile-time in case their input parameter is constant. When the program - that may due to optimization not contain the identifiers any more - becomes de-compiled, these constants have to be written to the normalized expression string in a way that corresponding constant values of type Duration are expressed.

To perform this task, an implementation of the box-function that this struct declares has to be registered with boxes containing values of TimePointBase::Duration.
Registrations of box-functions have to be done in the bootstrap code of the library. In this case it is done in static method plugins::DateAndTime::Bootstrap . The function name that is used for the implementation is FToLiteral_Duration. Here is the line of code that registers the function with the boxed type:

// register ToLiteral interface for class DateTime::Duration with boxing
boxing::BootstrapRegister<FToLiteral, boxing::TMappedTo<time::DateTime::Duration>>( FToLiteral_Duration );

The implementation is given in an anonymous namespace of the compilation unit of compiler plug-in DateAndTime. The function's signature has to meet the one given with type definition Signature of this struct. Besides the first parameter that passes the box that the function is invoked on (the one containing the constant value of custom type), second parameter expressionString provides the AString that the function is requested to write the "generation expression" to.
The implementation code looks as follows:

void FToLiteral_Duration( const Box& constantValue, AString& expressionString )
{
// Unbox the time span and convert to nanoseconds
auto value= constantValue.Unbox<DateTime::Duration>().InNanoseconds();
// Find the best matching magnitude
NString result;
if( value == 0 )
result= "Milliseconds";
else
{
result= "Nanoseconds";
if( (value % 1000) == 0 )
{
value/= 1000;
result= "Microseconds";
if( (value % 1000) == 0 )
{
value/= 1000;
result= "Milliseconds";
if( (value % 1000) == 0 )
{
value/= 1000;
result= "Seconds";
if( (value % 60) == 0 )
{
value/= 60;
result= "Minutes";
if( (value % 60) == 0 )
{
value/= 60;
result= "Hours";
if( (value % 24) == 0 )
{
value/= 24;
result= "Days";
}
}
}
}
}
}
}
// wWite the function argument
expressionString << result << '(' << value << ')' ;
}

As it can be understood from the code, the interface implementation tries to find the best matching "constructor function" for teh time span given, writes its name and the constant parameter enclosed by brackets "()".

Only with such interface implementation in place - one that covers all possible constants - this library is able to create parsable, normalized, optimized expression strings. To finalize this example, we check what the result for three sample expressions looks like:

Input: Milliseconds(1)
Normalized: MilliSeconds( 1 )
Optimized: Milliseconds(1)
Program Length: 1
Input: Milliseconds(1) * 1000
Normalized: MilliSeconds( 1 ) * 1000
Optimized: Seconds(1)
Program Length: 1
Input: Minutes(18) + Seconds(23)
Normalized: Minutes( 18 ) + Seconds( 23 )
Optimized: Seconds(1103)
Program Length: 1
Note
When integrating module ALib Expressions into a software, a decision has to be taken: "Should optimized expression strings be presented to the end-user?"
While it is obvious, that sample two demonstrates that to be useful, sample three probably demonstrates the opposite!
It is important to understand, that the decision depends on the custom use case, where for example the technical understanding of a typical end-user may be taken into account.
If the decision is taken, not to present optimized expression strings to the end-user, this has absolutely no influence on the evaluation performance: The compilation of all three expression strings, namely
  • the original input,
  • the normalized output and
  • the optimized, normalized output,
are leading to the very same (optimized) internal program when compiled!
Of-course, if no optimization strings are presented to the end-user and hence are not recompiled (or copy/pasted by such users), then the implementation of this box-function is not needed for your custom type, as it is only invoked with method Expression::GetOptimizedString !

Definition at line 1268 of file expressions.hpp.

#include <expressions.hpp>

Public Type Index:

using Signature = void (*) ( const Box& constantValue, AString& expressionString )
 

Type Definition Details:

◆ Signature

using Signature = void (*) ( const Box& constantValue, AString& expressionString )

Signature of the invokable function.

Parameters
constantValueThe constant program value that is about to be written into expressionString .
expressionStringThe expression string that is currently generated.

Definition at line 1277 of file expressions.hpp.


The documentation for this struct was generated from the following file: