Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Ignore:
Timestamp:
Nov 1, 2008, 7:04:09 PM (16 years ago)
Author:
landauf
Message:

merged objecthierarchy branch back to trunk

Location:
code/trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • code/trunk

  • code/trunk/src/core/CommandLine.h

    r1764 r2087  
    3535#include "util/Debug.h"
    3636#include "util/Exception.h"
     37#include "util/MultiType.h"
    3738
    3839#define SetCommandLineArgument(name, defaultValue) \
    39     BaseCommandLineArgument& CmdArgumentDummyBoolVar##name \
     40    CommandLineArgument& CmdArgumentDummyBoolVar##name \
    4041    = orxonox::CommandLine::addArgument(#name, defaultValue)
    4142#define SetCommandLineSwitch(name) \
    42     BaseCommandLineArgument& CmdArgumentDummyBoolVar##name \
     43    CommandLineArgument& CmdArgumentDummyBoolVar##name \
    4344    = orxonox::CommandLine::addArgument(#name, false)
    4445
     
    4849    /**
    4950    @brief
    50         Template struct which creates a distinct type for every integer constant.
    51     @note
    52         This allows to select a different function depending on a boolean value
    53         when creating a new CommandLineArgument.
    54         From 'Modern C++ Design' (Alexandrescu 2001).
     51        Container class for a command line argument of any type supported by MultiType.
     52
     53        Whenever you want to have an option specified by a command line switch,
     54        you need to first define it with SetCommandLineArgument(name, defaultValue).
     55        It is then added to a map and possibly changed when the command line is being parsed.
     56        If the option was not given, you can detect this by asking hasDefaultValue().
     57
     58        There is a possibility to define a short cut so you can write "-p 20" instead of "--port 20".
     59        Note the difference between "-" and "--"!
     60        Also, there is no restriction to the number of strings you add after --name.
     61        So "--startVector (2, 4, 5)" is perfectly legal.
     62
     63        Retrieving an argument is possible with the getCommandLineArgument function of the
     64        CommandLine class. It is a Singleton, but the public interface is static.
    5565    */
    56     template <int v>
    57     struct Int2Type
    58     {
    59         enum { value = v };
    60     };
    61 
    62     /**
    63     @brief
    64         Base class for CommandLineArguments.
    65     */
    66     class _CoreExport BaseCommandLineArgument
     66    class _CoreExport CommandLineArgument
    6767    {
    6868        friend class CommandLine;
     
    7878        const std::string& getShortcut() const { return shortcut_; }
    7979        //! Sets the shortcut for the argument
    80         BaseCommandLineArgument& setShortcut(const std::string& shortcut)
     80        CommandLineArgument& shortcut(const std::string& shortcut)
    8181        { this->shortcut_ = shortcut; return *this; }
    8282
     
    8484        const std::string& getInformation() const { return this->usageInformation_; }
    8585        //! Sets the option information when displaying orxonox usage.
    86         BaseCommandLineArgument& setInformation(const std::string& usage)
     86        CommandLineArgument& information(const std::string& usage)
    8787        { this->usageInformation_ = usage; return *this; }
    8888
    89     protected:
    90         BaseCommandLineArgument(const std::string& name)
     89        //! Returns the actual value of the argument. Can be equal to default value.
     90        MultiType getValue() const { return value_; }
     91        //! Returns the given default value as type T.
     92        MultiType getDefaultValue() const { return defaultValue_; }
     93
     94    private:
     95        //! Constructor initialises both value_ and defaultValue_ with defaultValue.
     96        CommandLineArgument(const std::string& name, const MultiType& defaultValue)
    9197            : bHasDefaultValue_(true)
    9298            , name_(name)
     99            , value_(defaultValue)
     100            , defaultValue_(defaultValue)
    93101        { }
    94102
    95103        //! Undefined copy constructor
    96         BaseCommandLineArgument(const BaseCommandLineArgument& instance);
    97         virtual ~BaseCommandLineArgument() { }
     104        CommandLineArgument(const CommandLineArgument& instance);
     105        ~CommandLineArgument() { }
    98106
    99107        //! Parses the value string of a command line argument.
    100         virtual void parse(const std::string& value) = 0;
     108        void parse(const std::string& value);
    101109
    102110        //! Tells whether the value has been changed by the command line.
     
    107115        std::string shortcut_;         //!< Shortcut of the argument. @see getShortcut().
    108116        std::string usageInformation_; //!< Tells about the usage of this parameter
     117
     118        MultiType value_;            //!< The actual value
     119        MultiType defaultValue_;     //!< Default value. Should not be changed.
    109120    };
    110 
    111 
    112     /**
    113     @brief
    114         Container class for a command line argument of type T.
    115        
    116         Whenever you want to have an option specified by a command line switch,
    117         you need to first define it with SetCommandLineArgument(name, defaultValue).
    118         It is then added to a map and possibly changed when the command line is being parsed.
    119         If the option was not given, you can detect this by asking hasDefaultValue().
    120        
    121         There is a possibility to define a short cut so you can write "-p 20" instead of "--port 20".
    122         Note the difference between "-" and "--"!
    123         Also, there is no restriction to the number of strings you add after --name.
    124         So "--startVector (2, 4, 5)" is perfectly legal.
    125 
    126         Retrieving an argument is possible with the getCommandLineArgument function of the
    127         CommandLine class. It is a Singleton, but the public interface is static.
    128     */
    129     template <class T>
    130     class CommandLineArgument : public BaseCommandLineArgument
    131     {
    132         // Only let CommandLine change the value.
    133         friend class CommandLine;
    134 
    135     public:
    136         //! Returns the actual value of the argument. Can be equal to default value.
    137         T getValue() const { return value_; }
    138         //! Returns the given default value as type T.
    139         T getDefaultValue() const { return defaultValue_; }
    140 
    141     private:
    142         //! Constructor initialises both value_ and defaultValue_ with defaultValue.
    143         CommandLineArgument(const std::string& name, const T& defaultValue)
    144             : BaseCommandLineArgument(name)
    145             , value_(defaultValue)
    146             , defaultValue_(defaultValue)
    147         { }
    148 
    149         virtual void parse(const std::string& value);
    150 
    151         T value_;            //!< The actual value
    152         T defaultValue_;     //!< Default value. Should not be changed.
    153     };
    154 
    155     /**
    156     @brief
    157         Parses a value string for a command line argument.
    158         It simply uses convertValue(Output, Input) to do that.
    159     */
    160     template <class T>
    161     void CommandLineArgument<T>::parse(const std::string& value)
    162     {
    163         if (convertValue(&this->value_, value))
    164         {
    165             this->bHasDefaultValue_ = false;
    166         }
    167         else
    168         {
    169             ThrowException(Argument, "Could not read command line argument '" + getName() + "'.");
    170         }
    171     }
    172 
    173     /**
    174     @brief
    175         Parses a value string for a command line argument.
    176         It simply uses convertValue(Output, Input) to do that.
    177         This is a template specialisation for bool type. That is necessary
    178         so that you can have simple command line switches.
    179     */
    180     template <>
    181     inline void CommandLineArgument<bool>::parse(const std::string& value)
    182     {
    183         if (convertValue(&this->value_, value))
    184         {
    185             this->bHasDefaultValue_ = false;
    186         }
    187         else if (value == "")
    188         {
    189             this->bHasDefaultValue_ = false;
    190             this->value_ = true;
    191         }
    192         else
    193         {
    194             ThrowException(Argument, "Could not read command line argument '" + getName() + "'.");
    195         }
    196     }
    197121
    198122
     
    215139        static std::string getUsageInformation();
    216140
    217         template <class T>
    218         static const CommandLineArgument<T>* getArgument(const std::string& name);
     141        static const CommandLineArgument* getArgument(const std::string& name);
    219142        //! Writes the argument value in the given parameter.
    220143        template <class T>
    221144        static void getValue(const std::string& name, T* value)
    222         { *value = getArgument<T>(name)->getValue(); }
     145        { *value = (T)(getArgument(name)->getValue()); }
     146        static MultiType getValue(const std::string& name)
     147        { return getArgument(name)->getValue(); }
    223148        template <class T>
    224         static BaseCommandLineArgument& addArgument(const std::string& name, T defaultValue);
     149        static CommandLineArgument& addArgument(const std::string& name, T defaultValue);
     150
     151        static bool existsArgument(const std::string& name)
     152        {
     153            std::map<std::string, CommandLineArgument*>::const_iterator it = _getInstance().cmdLineArgs_.find(name);
     154            return !(it == _getInstance().cmdLineArgs_.end());
     155        }
     156
    225157
    226158    private:
     
    237169        void checkShortcut(const std::string& shortcut, const std::string& value);
    238170
    239         template <class T>
    240         BaseCommandLineArgument* createArg(const std::string& name, T defaultValue, Int2Type<0> isString);
    241         template <class T>
    242         BaseCommandLineArgument* createArg(const std::string& name, T defaultValue, Int2Type<1> isString);
    243 
    244171        /**
    245             Tells whether we parse the first expression. The CommmandLineArguments are added before main().
     172            Tells whether we parsed for the first time. The CommmandLineArguments are added before main().
    246173            So when we call parse() the first time, we need to create a map with all shortcuts since these
    247174            get added after addCommandLineArgument().
     
    250177
    251178        //! Holds all pointers to the arguments and serves as a search map by name.
    252         std::map<std::string, BaseCommandLineArgument*> cmdLineArgs_;
     179        std::map<std::string, CommandLineArgument*> cmdLineArgs_;
    253180        //! Search map by chortcut for the arguments.
    254         std::map<std::string, BaseCommandLineArgument*> cmdLineArgsShortcut_;
     181        std::map<std::string, CommandLineArgument*> cmdLineArgsShortcut_;
    255182    };
    256183
    257 
    258     /**
    259     @brief
    260         Retrieves a CommandLineArgument.
    261         The method throws an exception if 'name' was not found or the value could not be converted.
    262     @note
    263         You shold of course not call this method before the command line has been parsed.
    264     */
    265     template <class T>
    266     const CommandLineArgument<T>* CommandLine::getArgument(const std::string& name)
    267     {
    268         std::map<std::string, BaseCommandLineArgument*>::const_iterator it = _getInstance().cmdLineArgs_.find(name);
    269         if (it == _getInstance().cmdLineArgs_.end())
    270         {
    271             ThrowException(Argument, "Could find command line argument '" + name + "'.");
    272         }
    273         else
    274         {
    275             CommandLineArgument<T>* arg = dynamic_cast<CommandLineArgument<T>* >(it->second);
    276             if (arg == 0)
    277             {
    278                 ThrowException(Argument, "Could not convert command line argument value to requested type. " \
    279                     "You should use exactly the same type as predefined.");
    280             }
    281             else
    282             {
    283                 return arg;
    284             }
    285         }
     184    template <>
     185    inline void CommandLine::getValue<std::string>(const std::string& name, std::string* value)
     186    {
     187        *value = (std::string)(getArgument(name)->getValue().getString());
    286188    }
    287189
     
    294196    @param defaultValue
    295197        Default value that is used when argument was not given.
    296     @note
    297         In order to store char* strings as std::string too, there's
    298         little bit of template programming involved:
    299         StaticConversions::exists determines whether T converts to std::string.
    300         Int2Type<int> is then used to call the right function. One returns
    301         a CommandLineArgument<T> and the other CommandLineArgument<std::string>.
    302198    */
    303199    template <class T>
    304     BaseCommandLineArgument& CommandLine::addArgument(const std::string& name, T defaultValue)
    305     {
    306         std::map<std::string, BaseCommandLineArgument*>::const_iterator it = _getInstance().cmdLineArgs_.find(name);
    307         OrxAssert(it == _getInstance().cmdLineArgs_.end(),
     200    CommandLineArgument& CommandLine::addArgument(const std::string& name, T defaultValue)
     201    {
     202        OrxAssert(!_getInstance().existsArgument(name),
    308203            "Cannot add a command line argument with name '" + name + "' twice.");
    309204
    310         return *(_getInstance().cmdLineArgs_[name] =
    311             _getInstance().createArg(name, defaultValue, Int2Type<StaticConversion<T, std::string>::exists>()));
    312     }
    313 
    314     /**
    315         Returns a new CommandLineArgument<T>.
    316     */
    317     template <class T>
    318     BaseCommandLineArgument* CommandLine::createArg(const std::string& name, T defaultValue, Int2Type<0> isPrime)
    319     {
    320         return new CommandLineArgument<T>(name, defaultValue);
    321     }
    322 
    323     /**
    324         Returns a new CommandLineArgument<std::string>.
    325     */
    326     template <class T>
    327     BaseCommandLineArgument* CommandLine::createArg(const std::string& name, T defaultValue, Int2Type<1> isPrime)
    328     {
    329         return new CommandLineArgument<std::string>(name, defaultValue);
     205        return *(_getInstance().cmdLineArgs_[name] = new CommandLineArgument(name, defaultValue));
    330206    }
    331207}
Note: See TracChangeset for help on using the changeset viewer.