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 )