Index   Main   Namespaces   Classes   Hierarchy   Annotated   Files   Compound   Global   Pages  

GtpEngine.h

Go to the documentation of this file.
00001 //----------------------------------------------------------------------------
00002 /** @file GtpEngine.h
00003     Basic implementation of the Go Text Protocol (GTP).
00004 
00005     Depends only on the standard C++ library for maximum reusability.
00006     If ponder or interrupt functionality is enabled by setting the macros
00007     GTPENGINE_PONDER and/or GTPENGINE_INTERRUPT to 1, the Boost.Thread library
00008     is also needed.
00009 
00010     GtpEngine implements a GTP engine with some basic commands. This class
00011     is typically used as a base class for other GTP engines.
00012     GtpEngine::Register allows to register additional commands.
00013     GtpEngine::MainLoop starts the main command loop.
00014     Command handlers implement the interface GtpCallbackBase.
00015     For class member functions, such a callback can be constructed with
00016     the GtpCallback template class.
00017     Each callback function is passed a GtpCommand argument, which can be
00018     queried for arguments and used for writing the response to.
00019     GTP error responses are created by throwing an instance of GtpFailure.
00020     All such exceptions are caught in the main loop and converted
00021     into a response with error status.
00022 */
00023 //----------------------------------------------------------------------------
00024 
00025 #ifndef GTPENGINE_H
00026 #define GTPENGINE_H
00027 
00028 #include <cstddef>
00029 #include <iostream>
00030 #include <map>
00031 #include <sstream>
00032 #include <string>
00033 #include <vector>
00034 
00035 #include "GtpInputStream.h"
00036 #include "GtpOutputStream.h"
00037 
00038 #ifndef GTPENGINE_PONDER
00039 /** Macro for enabling pondering.
00040     If this macro is enabled, GtpEngine has the additional functions
00041     Ponder(), InitPonder() and StopPonder(), which will be called while
00042     waiting for the next command. This can be used for thinking during the
00043     opponent's time.
00044     Enabling this macro adds a dependency on the Boost.Thread library.
00045     @see GtpEngine::Ponder()
00046 */
00047 #define GTPENGINE_PONDER 1
00048 #endif
00049 
00050 #ifndef GTPENGINE_INTERRUPT
00051 /** Macro for enabling interrupt ability.
00052     If this macro is enabled, GtpEngine has the additional function
00053     Interrupt() to interrupt a running command.
00054     Enabling this macro adds a dependency on the Boost.Thread library.
00055     @see GtpEngine::Interrupt()
00056 */
00057 #define GTPENGINE_INTERRUPT 1
00058 #endif
00059 
00060 //----------------------------------------------------------------------------
00061 
00062 /** GTP failure.
00063     Command handlers generate a GTP error response by throwing an instance
00064     of GtpFailure.
00065     It contains an internal string stream for building the reponse using
00066     stream output operators.
00067     To make formatting of responses with a temporary object more convenient,
00068     operator<< uses non-standard semantics, such that a new object is
00069     returned.
00070     Usage examples:
00071     @verbatim
00072     // OK. Construct with string
00073     throw GtpFailure("message");
00074 
00075     // OK. Use temporary object
00076     throw GtpFailure() << message << ...;
00077 
00078     // NOT OK. Object is not modified, the return value of << is ignored
00079     GtpFailure failure;
00080     failure << message << ...;
00081     throw failure;
00082 
00083     // OK. Use the internal string stream
00084     GtpFailure failure;
00085     failure.ResponseStream() << message << ...;
00086     throw failure;
00087     @endverbatim
00088 */
00089 class GtpFailure
00090 {
00091 public:
00092     /** Construct with no message. */
00093     GtpFailure();
00094 
00095     /** Construct with message. */
00096     GtpFailure(const std::string& response);
00097 
00098     /** Copy constructor.
00099         Needed for operator<<.
00100         Preserves the internal string stream format state.
00101     */
00102     GtpFailure(const GtpFailure& failure);
00103 
00104     /** Destructor. */
00105     ~GtpFailure() throw();
00106 
00107     /** Get the response.
00108         Returns a copy of the text in the internal string stream.
00109     */
00110     std::string Response() const;
00111 
00112     /** Get the internal string stream. */
00113     std::ostream& ResponseStream();
00114 
00115 private:
00116     std::ostringstream m_response;
00117 };
00118 
00119 /** @relates GtpFailure
00120     @note Returns a new object, see @ref GtpFailure
00121 */
00122 template<typename TYPE>
00123 GtpFailure operator<<(const GtpFailure& failure, const TYPE& type)
00124 {
00125     GtpFailure result(failure);
00126     result.ResponseStream() << type;
00127     return result;
00128 }
00129 
00130 /** @relates GtpFailure
00131     @note Returns a new object, see @ref GtpFailure
00132 */
00133 template<typename TYPE>
00134 GtpFailure operator<<(const GtpFailure& failure, TYPE& type)
00135 {
00136     GtpFailure result(failure);
00137     result.ResponseStream() << type;
00138     return result;
00139 }
00140 
00141 inline std::string GtpFailure::Response() const
00142 {
00143     return m_response.str();
00144 }
00145 
00146 inline std::ostream& GtpFailure::ResponseStream()
00147 {
00148     return m_response;
00149 }
00150 
00151 //----------------------------------------------------------------------------
00152 
00153 
00154 
00155 /** GTP command.
00156     GtpCommands are passed to command handlers.
00157     They can be queried for arguments and used for writing the response to.
00158 
00159     Arguments can contain spaces if they are double quoted, for instance:
00160     @verbatim loadsgf "My File.sgf" @endverbatim
00161     Double quotes in a quoted argument have to be escaped with '\'.
00162 
00163     The response message format does not have any special requirement,
00164     it will be sanitized by GtpEngine before writing to form a valid
00165     GTP response (see @ref GtpEngine::MainLoop).
00166 */
00167 
00168 class GtpCommand
00169 {
00170 public:
00171     /** Construct empty command.
00172         @warning An empty command cannot be used, before Init() was called.
00173         This constructor exists only to reuse instances.
00174     */
00175     GtpCommand();
00176 
00177     /** Construct with a command line.
00178         @see Init()
00179     */
00180     GtpCommand(const std::string& line);
00181 
00182     /** Conversion to output stream.
00183         Returns reference to response stream.
00184     */
00185     operator std::ostream&();
00186 
00187     /** Get argument.
00188         @param number Argument index starting with 0
00189         @return Argument value
00190         @throws GtpFailure If no such argument
00191     */
00192     const std::string& Arg(std::size_t number) const;
00193 
00194     /** Get single argument.
00195         @return Argument value
00196         @throws GtpFailure If no such argument or command has more than one
00197         arguments
00198     */
00199     const std::string& Arg() const;
00200 
00201     /** Get argument converted to lowercase.
00202         @param number Argument index starting with 0
00203         @return Copy of argument value converted to lowercase
00204         @throws GtpFailure If no such argument
00205     */
00206     std::string ArgToLower(std::size_t number) const;
00207 
00208     /** Get integer argument converted boolean.
00209         @param number Argument index starting with 0
00210         @return false, if argument is 0, true, if 1
00211         @throws GtpFailure If no such argument, or argument has other value
00212     */
00213     bool BoolArg(std::size_t number) const;
00214 
00215     /** Check that command has no arguments.
00216         @throws GtpFailure If command has arguments
00217     */
00218     void CheckArgNone() const;
00219 
00220     /** Check number of arguments.
00221         @param number Expected number of arguments
00222         @throws GtpFailure If command has a different number of arguments
00223     */
00224     void CheckNuArg(std::size_t number) const;
00225 
00226     /** Check maximum number of arguments.
00227         @param number Expected maximum number of arguments
00228         @throws GtpFailure If command has more arguments
00229     */
00230     void CheckNuArgLessEqual(std::size_t number) const;
00231 
00232     /** Get argument converted to double.
00233         @param number Argument index starting with 0
00234         @return Argument value
00235         @throws GtpFailure If no such argument, or argument is not a double
00236     */
00237     double FloatArg(std::size_t number) const;
00238 
00239     /** Get command ID.
00240         @return ID or empty string, if command has no ID
00241     */
00242     std::string ID() const;
00243 
00244     /** Initialize with a command line.
00245         The line should be not empty, not contain only whitespaces and not
00246         be a comment line.
00247         It will be split into the optional numeric command ID, the command
00248         name, and arguments.
00249     */
00250     void Init(const std::string& line);
00251 
00252     /** Get argument converted to integer.
00253         @param number Argument index starting with 0
00254         @return Argument value
00255         @throws GtpFailure If no such argument, or argument is not an integer
00256     */
00257     int IntArg(std::size_t number) const;
00258 
00259     /** Get argument converted to integer in a range with lower limit.
00260         @param number Argument index starting with 0
00261         @param min Minimum allowed value
00262         @return Argument value
00263         @throws GtpFailure If no such argument, argument is not an integer,
00264         or not in range
00265     */
00266     int IntArg(std::size_t number, int min) const;
00267 
00268     /** Get argument converted to integer in a range with lower and upper
00269         limit.
00270         @param number Argument index starting with 0
00271         @param min Minimum allowed value
00272         @param max Maximum allowed value
00273         @return Argument value
00274         @throws GtpFailure If no such argument, argument is not an integer,
00275         or not in range
00276     */
00277     int IntArg(std::size_t number, int min, int max) const;
00278 
00279     /** Get argument line.
00280         Get all arguments as a line.
00281         No modfications to the line were made apart from trimmimg leading
00282         and trailing white spaces.
00283     */
00284     std::string ArgLine() const;
00285 
00286     /** Get command line.
00287         Returns full command line as given to the constructor or
00288         GtpCommand::Init.
00289         No modfications to the line were made apart from trimmimg leading
00290         and trailing white spaces.
00291     */
00292     const std::string& Line() const;
00293 
00294     /** Get argument name. */
00295     const std::string& Name() const;
00296 
00297     /** Get number of arguments. */
00298     std::size_t NuArg() const;
00299 
00300     /** Return remaining line after argument.
00301         @param number Argument index starting with 0
00302         @return The remaining line after the given argument, unmodified apart
00303         from leading and trailing whitespaces, which are trimmed. Quotation
00304         marks are not handled.
00305         @throws GtpFailure If no such argument
00306     */
00307     std::string RemainingLine(std::size_t number) const;
00308 
00309     /** Get response.
00310         @return A copy of the internal response string stream
00311     */
00312     std::string Response() const;
00313 
00314     /** Get internal response string stream */
00315     std::ostringstream& ResponseStream();
00316 
00317     /** Set response. */
00318     void SetResponse(const std::string& response);
00319 
00320     /** Set response to "true" or "false". */
00321     void SetResponseBool(bool value);
00322 
00323     /** Get argument converted to std::size_t.
00324         @param number Argument index starting with 0
00325         @return Argument value
00326         @throws GtpFailure If no such argument, or argument is not a size_t
00327     */
00328     std::size_t SizeTypeArg(std::size_t number) const;
00329 
00330     /** Get argument converted to std::size_t with lower limit.
00331         @param number Argument index starting with 0
00332         @param min Minimum allowed value
00333         @return Argument value
00334         @throws GtpFailure If no such argument, or argument is not a size_t
00335     */
00336     std::size_t SizeTypeArg(std::size_t number, std::size_t min) const;
00337 
00338 private:
00339     /** Argument in command line. */
00340     struct Argument
00341     {
00342         /** Argument value.
00343             Enclosing quotes are removed if there were any and escape
00344             characters within enclosing quotes are removed.
00345         */
00346         std::string m_value;
00347 
00348         /** Position of first character in m_line after this argument. */
00349         std::size_t m_end;
00350 
00351         Argument(const std::string& value, std::size_t end);
00352     };
00353 
00354     /** Dummy stream for copying default formatting settings. */
00355     static std::ostringstream s_dummy;
00356 
00357     /** ID of command or empty string, if command has no ID */
00358     std::string m_id;
00359 
00360     /** Full command line. */
00361     std::string m_line;
00362 
00363     /** Response stream */
00364     std::ostringstream m_response;
00365 
00366     /** Arguments of command. */
00367     std::vector<Argument> m_arguments;
00368 
00369     void ParseCommandId();
00370 
00371     void SplitLine(const std::string& line);
00372 };
00373 
00374 /** @relates GtpCommand */
00375 template<typename TYPE>
00376 GtpCommand& operator<<(GtpCommand& cmd, const TYPE& type)
00377 {
00378     cmd.ResponseStream() << type;
00379     return cmd;
00380 }
00381 
00382 /** @relates GtpCommand */
00383 template<typename TYPE>
00384 GtpCommand& operator<<(GtpCommand& cmd, TYPE& type)
00385 {
00386     cmd.ResponseStream() << type;
00387     return cmd;
00388 }
00389 
00390 inline GtpCommand::GtpCommand()
00391 {
00392 }
00393 
00394 inline GtpCommand::GtpCommand(const std::string& line)
00395 {
00396     Init(line);
00397 }
00398 
00399 inline GtpCommand::operator std::ostream&()
00400 {
00401     return ResponseStream();
00402 }
00403 
00404 inline void GtpCommand::CheckArgNone() const
00405 {
00406     CheckNuArg(0);
00407 }
00408 
00409 inline std::string GtpCommand::ID() const
00410 {
00411     return m_id;
00412 }
00413 
00414 inline const std::string& GtpCommand::Line() const
00415 {
00416     return m_line;
00417 }
00418 
00419 inline const std::string& GtpCommand::Name() const
00420 {
00421     return m_arguments[0].m_value;
00422 }
00423 
00424 inline std::size_t GtpCommand::NuArg() const
00425 {
00426     return m_arguments.size() - 1;
00427 }
00428 
00429 inline std::string GtpCommand::Response() const
00430 {
00431     return m_response.str();
00432 }
00433 
00434 inline std::ostringstream& GtpCommand::ResponseStream()
00435 {
00436     return m_response;
00437 }
00438 
00439 //----------------------------------------------------------------------------
00440 
00441 /** Abstract base class for command handlers. */
00442 class GtpCallbackBase
00443 {
00444 public:
00445     virtual ~GtpCallbackBase() throw();
00446 
00447     virtual void operator()(GtpCommand&) = 0;
00448 };
00449 
00450 //----------------------------------------------------------------------------
00451 
00452 /** Member function command handlers.
00453     For registering member functions in GtpEngine::Register().
00454     @note Instances keep a pointer to the object containing the member
00455     function. If the object does is not a subclass of GtpEngine and registers
00456     only its own members, you have to make sure that the object's lifetime
00457     exceeds the lifetime of the GtpEngine.
00458 */
00459 template<class ENGINE>
00460 class GtpCallback
00461     : public GtpCallbackBase
00462 {
00463 public:
00464     /** Signature of the member function. */
00465     typedef void (ENGINE::*Method)(GtpCommand&);
00466 
00467     GtpCallback(ENGINE* instance,
00468                 typename GtpCallback<ENGINE>::Method method);
00469 
00470     ~GtpCallback() throw();
00471 
00472     /** Execute the member function. */
00473     void operator()(GtpCommand&);
00474 
00475 private:
00476     ENGINE* m_instance;
00477 
00478     Method m_method;
00479 };
00480 
00481 template<class ENGINE>
00482 GtpCallback<ENGINE>::GtpCallback(ENGINE* instance,
00483                                  typename GtpCallback<ENGINE>::Method method)
00484     : m_instance(instance),
00485       m_method(method)
00486 {
00487 }
00488 
00489 template<class ENGINE>
00490 GtpCallback<ENGINE>::~GtpCallback() throw()
00491 {
00492 #ifndef NDEBUG
00493     m_instance = 0;
00494 #endif
00495 }
00496 
00497 template<class ENGINE>
00498 void GtpCallback<ENGINE>::operator()(GtpCommand& cmd)
00499 {
00500     (m_instance->*m_method)(cmd);
00501 }
00502 
00503 //----------------------------------------------------------------------------
00504 
00505 /** @page gtpenginesimulatedelay Simulated Delays
00506     If the engine receives a special comment line
00507     <code># gtpengine-sleep n</code>, it will sleep for @c n seconds before
00508     reading the next line. This feature can be used for adding simulated
00509     delays in test GTP scripts (e.g. to test pondering functionality).
00510     Note that the start time for sleeping is at the start of the previous
00511     command, not when the response to the previous command is received,
00512     because GtpEngine continues reading the stream while the previous command
00513     is in progress. This functionality is only enabled, if GtpEngine was
00514     compiled with GTPENGINE_INTERRUPT.
00515 */
00516 
00517 /** Base class for GTP (Go Text Protocol) engines.
00518     Commands can be added with GtpEngine::Register().
00519     Existing commands can be overridden by registering a new handler for
00520     the command or by overriding the command handler member function
00521     in subclasses.
00522     @see @ref gtpenginecommands, @ref gtpenginesimulatedelay
00523 */
00524 class GtpEngine
00525 {
00526 public:
00527     /** @page gtpenginecommands GtpEngine Commands
00528         - @link CmdKnownCommand() @c known_command @endlink
00529         - @link CmdListCommands() @c list_commands @endlink
00530         - @link CmdName() @c name @endlink
00531         - @link CmdProtocolVersion() @c protocol_version @endlink
00532         - @link CmdQuit() @c quit @endlink
00533         - @link CmdVersion() @c version @endlink
00534     */
00535     /** @name Command Callbacks */
00536     // @{
00537     virtual void CmdKnownCommand(GtpCommand&);
00538     virtual void CmdListCommands(GtpCommand&);
00539     virtual void CmdName(GtpCommand&);
00540     virtual void CmdProtocolVersion(GtpCommand&);
00541     virtual void CmdQuit(GtpCommand&);
00542     virtual void CmdVersion(GtpCommand&);
00543     // @} // @name
00544 
00545     /** Constructor.
00546         @param in Input GTP stream
00547         @param out Output GTP stream
00548     */
00549     GtpEngine(GtpInputStream& in, GtpOutputStream& out);
00550 
00551     virtual ~GtpEngine();
00552 
00553     /** Execute commands from file.
00554         Aborts on the first command that fails.
00555         @param name The file name
00556         @param log Stream for logging the commands and responses to (default
00557         is std::cerr).
00558         @throw GtpFailure If a command fails
00559     */
00560     void ExecuteFile(const std::string& name, std::ostream& log = std::cerr);
00561 
00562     /** Execute a single command string.
00563         @param cmd The command line
00564         @param log Stream for logging the command and response to (default
00565         is std::cerr).
00566         @returns The command response
00567         @throw GtpFailure If the command fails
00568     */
00569     std::string ExecuteCommand(const std::string& cmd,
00570                                std::ostream& log = std::cerr);
00571 
00572     /** Run the main command loop.
00573         Reads lines from input stream, calls the corresponding command
00574         handler and writes the response to the output stream.
00575         Empty lines in the command responses will be replaced by a line
00576         containing a single space, because empty lines are not allowed
00577         in GTP responses.
00578     */
00579     void MainLoop();
00580 
00581     /** Register command handler.
00582         Takes ownership of callback.
00583         If a command was already registered with the same name,
00584         it will be replaced by the new command.
00585     */
00586     void Register(const std::string& name, GtpCallbackBase* callback);
00587 
00588     /** Register a member function as a command handler.
00589         If a command was already registered with the same name,
00590         it will be replaced by the new command.
00591     */
00592     template<class T>
00593     void Register(const std::string& command,
00594                   typename GtpCallback<T>::Method method, T* instance);
00595 
00596     /** Returns if command registered. */
00597     bool IsRegistered(const std::string& command) const;
00598 
00599     /** Set flag for quitting the main command loop.
00600         Currently, this function works only for the "quit" command, if the
00601         engine is compiled with interrupt functionality (GTENGINE_INTERRUPT).
00602         Therefore, it is not possible for other commands to decide to quit
00603         (which would be necessary for instance to implement a maximal game
00604         number if playing on KGS and deciding to quit on the kgs-game_over
00605         command, if the maximum number is reached).
00606 
00607         The reason is that the command  stream is then read from a different
00608         thread using a blocking, non-interruptible read function, which is
00609         entered before the command handler is invoked in the main thread.
00610         Because of the non-interruptible read function, the implementation of
00611         GtpEngine needs to know what commands will quit to avoid entering this
00612         read function after a quit.
00613 
00614         If a way is found to interrupt the read thread during the execution
00615         of the blocking std::getline (maybe in a future version of
00616         Boost.Thread), this function could also be called in other GTP
00617         commands.
00618         @see MainLoop()
00619     */
00620     void SetQuit();
00621 
00622     /** Did the last command set the quit flag? */
00623     bool IsQuitSet() const;
00624 
00625 #if GTPENGINE_PONDER
00626     /** Ponder.
00627         This function will be called in MainLoop() while the engine is waiting
00628         for the next command.
00629         It will be called after InitPonder() from a different thread than
00630         the command thread, but only while waiting for the next command, so
00631         no concurrent execution of this function and other engine functions
00632         is possible. The function should return immediately when StopPonder()
00633         is called. InitPonder() and StopPonder() are called from the
00634         command thread.
00635         In a typical implementation, InitPonder() will clear an abort flag and
00636         StopPonder() will set it. Ponder() will poll the abort flag and return
00637         when it is set (or it has nothing to do; or some maximum time limit
00638         for pondering was exceeded).
00639         The default implementation does nothing and returns immediately.
00640     */
00641     virtual void Ponder();
00642 
00643     /** Prepare for pondering.
00644         @see Ponder()
00645         The default implementation does nothing.
00646     */
00647     virtual void InitPonder();
00648 
00649     /** Stop pondering.
00650         @see Ponder()
00651         The default implementation does nothing.
00652     */
00653     virtual void StopPonder();
00654 #endif // GTPENGINE_PONDER
00655 
00656 #if GTPENGINE_INTERRUPT
00657     /** Interrupt the current command.
00658         This function implements interrupt functionality as used by
00659         <a href="http://gogui.sf.net">GoGui</a>. It will be called from a
00660         different thread that the command thread when the special command
00661         line <tt># interrupt</tt> is received.
00662         The default implementation does nothing.
00663     */
00664     virtual void Interrupt();
00665 #endif // GTPENGINE_INTERRUPT
00666 
00667 protected:
00668     /** Hook function to be executed before each command.
00669         Default implementation does nothing.
00670     */
00671     virtual void BeforeHandleCommand();
00672 
00673     /** Hook function to be executed before the response of a command is
00674         written.
00675         Default implementation does nothing.
00676     */
00677     virtual void BeforeWritingResponse();
00678 
00679 private:
00680     typedef std::map<std::string,GtpCallbackBase*> CallbackMap;
00681 
00682     bool m_quit;
00683 
00684     GtpInputStream& m_in;
00685 
00686     GtpOutputStream& m_out;
00687 
00688     CallbackMap m_callbacks;
00689 
00690     /** Not to be implemented. */
00691     GtpEngine(const GtpEngine& engine);
00692 
00693     /** Not to be implemented. */
00694     GtpEngine& operator=(const GtpEngine& engine) const;
00695 
00696     bool HandleCommand(GtpCommand& cmd, GtpOutputStream& out);
00697 };
00698 
00699 template<class T>
00700 void GtpEngine::Register(const std::string& command,
00701                          typename GtpCallback<T>::Method method, T* instance)
00702 {
00703     Register(command, new GtpCallback<T>(instance, method));
00704 }
00705 
00706 //----------------------------------------------------------------------------
00707 
00708 #endif // GTPENGINE_H
00709 


17 Jun 2010 Doxygen 1.4.7