Wednesday, December 13, 2006

Counted Method Chaining

I built a fun set of classes using C++ template meta-programming technique to count the number of times a member method of a class is invoked in a chain. These template classes implement a meta-programming technique called Counted Method Chaining. It counts the number of times a member function is called at compile-time and does not let programmer invoke it more than a used defiend limit. The limit is passed as a integer template parameter to the class to which to method belongs. It gives a compile time error only when method chaining is used. Otherwise it throws and exception. These set of classes use the C++ technique of co-variant return types.

/// @brief A genereral case of the template where add function
/// is public and therefore, it can be invoked.
template <unsigned int C>
class Base : public Base <C-1>
{
public:
virtual Base <C-1> & add (void const *, size_t length) = 0;
};

/// @brief The special case of the template when C (count) becomes zero.
/// The add member function is private and therefore, can't be
/// invoked by the client of the class resulting in a compile time error.
template <>
class Base <0>
{
public:
virtual ~Base () {}
private:
virtual Base <0> & add (void const *, size_t length) = 0;
};

template <unsigned int SIZE>
class IOV_Helper : public Base <SIZE-1>
{
public:
/// @brief Constructor: Makes a IOV_Helper object.
IOV_Helper () : count_(0) {}

/// @brief Adds a buffer pointer and its size to be sent over network later
/// using gather write technique.
Base <SIZE-1> & add (void const *ptr, size_t length)
{
if (0 == length)
return *this;

if (count_ >= SIZE)
throw count_ + 1;

iov_[count_].iov_base = const_cast <void *> (ptr);
iov_[count_].iov_len = length;
++count_;

return *this;
}

/// @brief Returns the number of I/O vectors populated currently
unsigned int size () { return count_; }

/// @brief Sends the data in the I/O vectors out to a remote peer.
int send (ACE_SOCK_Stream &out)
{
return out.sendv_n (iov_, count_);
}

private:
iovec iov_[SIZE]; /// @brief I/O vectors array.
unsigned int count_; /// @brief count of the number vectors added.
};

int main (void)
{
IOV_Helper <2> sender; /// Here 2 is the maximum limit of method chaining.
char * data = new char[20];
sender.add(data, 20).add(data, 20); /// OK
sender.add(data, 20).add(data, 20).add(data, 20); /// Compile-time Error
return 0;
}