Computer Chess Club Archives


Search

Terms

Messages

Subject: modifying data structures with policy based class design

Author: Steffen Jakob

Date: 06:15:28 07/22/02

Go up one level in this thread


On July 22, 2002 at 04:01:23, Steffen Jakob wrote:

>On July 21, 2002 at 21:36:53, Miguel A. Ballicora wrote:
>>
>>>1)How do I add a code with compiler switch?
>>>
>>you define a variable like this:
>>
>>#define HASH_PRUNE
>>
>>and then you do
>>
>>
>>#if defined(HASH_PRUNE)
>>    code_1();
>>#else
>>    code_2();
>>#endif
>>
>>code_1() is compiled and NOT code_2(). Also valid options are
>>
>>#ifdef HASH_PRUNE
>>    code_1();
>>#else
>>    code_2();
>>#endif
>>
>>or
>>
>>#if defined(HASH_PRUNE)
>>     optional_code();
>>#endif
>
>The problem with that approach is that you actually have two different programs.
>If you work for a long time with a switch enabled its likely that your code wont
>compile if you disable the switch. A better solution in many cases is to use a
>const boolean expression. You favourite compiler will skip the code if the
>expression is false.
>
>Example:
>
>const bool HASH_PRUNE = true;
>
>if (HASH_PRUNE) {
>    code_1();
>} else {
>    code_2();
>}
>
>This doesnt work of course if you want to modify structs depending on such a
>const.

Here is a small example of a design technique in C++ if you want to modify data
structures depending on a switch. It's called "policy-based class design". You
can find more about this in Andrei Alexandrescu's great book "Modern C++
Design". Lets assume you have a class HashEntry which models entries of your
transposition table. Sometimes you want to debug your hashtable code by adding
more information into each entry. E.g. it might be useful to know the search
node when the entry was written into the table. The preprocessor solution is to
define a macro and to define additional class member depending on that macro
with #ifdefs in your HashEntry struct.
A policy-based solution might look like the following example. Here you also
have a few preprocessor defines but this time they are all defined at the top of
your code. No ugly #ifdefs within your class definitions or somewhere else. You
only have to comment/uncomment the DEBUG_HASH macro if you want to
disable/enable the debug code.

-----------------------------------------------------------------------
#include <iostream>

// Uncomment this line to enable hash debugging code.
// #define DEBUG_HASH

#ifdef DEBUG_HASH
#define DEBUG_HASH_POLICY DebugHash
#else
#define DEBUG_HASH_POLICY NoDebug
#endif

typedef unsigned long Node;
Node globalNode = 0; // In a real example this would be a member of a
                     // search related class instance.

/**
 * Hashtable template class where the debugging behavior can be
 * defined by implementing the policy class D.
 */
template <typename D>
class THashEntry : public D {
public:
    // ... details skipped ...
};


/**
 * Policy class for debugging the hash table.
 */
class DebugHash {
public:
    /**
     * Default constructor which remembers the global node counter.
     */
    DebugHash() : node(globalNode) { }
    /** Print some debug information. */
    void printDebugInfo(std::ostream &os) const {
        os << "hash entry from node " << node << std::endl;
    }
private:
    Node node;
};

/**
 * If we dont want to debug the hashtable we simply use a struct which
 * only defines an empty member function printDebugInfo(). Because the
 * implicitely generated default constructor and the function
 * printDebugInfo() are empty and defined inline inheriting from
 * NoDebug is for free. The compiler will optimzed those calls away.
 */
struct NoDebug {
    void printDebugInfo(std::ostream &os) const {
        // do nothing
    }
};


/**
 * Our hashtable entry uses the policy class which is defined as a
 * preprocessor macro.
 */
typedef THashEntry<DEBUG_HASH_POLICY> HashEntry;


/** Simple demonstration. */
int main(int argc, char **argv) {
    // Do something which modifies the node counter
    globalNode = 42;
    // Create a hash entry and assume that this one will be inserted
    // in to the hash table.
    HashEntry entry;

    // Print some information about this entry which is usefull
    // for debugging.
    entry.printDebugInfo(std::cout);

    return 0;
}
-------------------------------------------------------------------------

Greetings,
Steffen.



This page took 0.23 seconds to execute

Last modified: Thu, 07 Jul 11 08:48:38 -0700

Current Computer Chess Club Forums at Talkchess. This site by Sean Mintz.