Tutorial 4: Two stores and conversionΒΆ
We are now describing an example in which we use two store elements, one for strings and for for integers, and we add the possibility to convert an element from the integer store into an element from the string store.
We start by defining two stores and also add methods to print the store entries
using print
. Using the macro ALICE_DESCRIBE_STORE
we can return
a short description string that is used to summarize a store element when
showing the store content with store
.
#include <alice/alice.hpp>
#include <fmt/format.h>
#include <string>
#include <vector>
namespace alice
{
ALICE_ADD_STORE( std::string, "str", "s", "string", "strings" )
ALICE_ADD_STORE( int, "number", "d", "number", "numbers" )
ALICE_DESCRIBE_STORE( std::string, element )
{
return fmt::format( "{} characters", element.size() );
}
ALICE_PRINT_STORE( std::string, os, element )
{
os << element << std::endl;
}
ALICE_DESCRIBE_STORE( int, element )
{
return element < 10 ? "small number" : "large number";
}
ALICE_PRINT_STORE( int, os, element )
{
os << element << std::endl;
}
Using the macro ALICE_CONVERT
we can enable conversion from entry to
another, which is performed by the convert command. We plan to write a
conversion routine from integers (flag name "number"
) to strings (flag name
"string"
). By implementing the following macro, we will add a flag
--number_to_string
to the convert
command.
ALICE_CONVERT( int, element, std::string )
{
if ( element >= 0 && element < 10 )
{
return std::vector<std::string>{"zero", "one", "two", "three",
"four", "five", "six", "seven",
"eight", "nine"}[element];
}
else
{
return "many";
}
}
The macro ALICE_CONVERT
expects three arguments. The first argument
is the store type that we wish to convert from, followed by an identifier that
we use to access the current element from that store in the implementation of
the macro. The third argument is the store type that we wish to convert to.
The code will convert all numbers between 0 and 9 to respective strings, and
otherwise to "many"
.
Next, we implement a command number
to load a number into the store. We
wish to specify the number using a command option --load
. Since we need to
initialize command arguments in the constructor, we cannot use the
ALICE_COMMAND
macro but need to implement our own class by deriving
from the alice::command
base class. Make sure to use the _command
suffix when giving a name to the new command. We can add the command using the
ALICE_ADD_COMMAND
after defining the command. The second argument to
this macro is a category that is used by the help
command.
class number_command : public command
{
public:
explicit number_command( const environment::ptr& env )
: command( env, "reads a number" )
{
opts.add_option( "--load,load", number, "number to load to the store" )->required();
}
protected:
void execute()
{
env->store<int>().extend() = number;
}
private:
int number{};
};
ALICE_ADD_COMMAND( number, "Generation" )
}
Finally, we call the main macro for alice.
ALICE_MAIN( tutorial4 )