Source: ../../policy/common/dispatcher.hh
|
|
|
|
// vim:set sts=4 ts=8:
// Copyright (c) 2001-2005 International Computer Science Institute
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software")
// to deal in the Software without restriction, subject to the conditions
// listed in the XORP LICENSE file. These conditions include: you must
// preserve this copyright notice, and you cannot mention the copyright
// holders in advertising related to the Software without their permission.
// The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
// notice is a summary of the XORP LICENSE file; the license in that file is
// legally binding.
// $XORP: xorp/policy/common/dispatcher.hh,v 1.2 2005/03/25 02:54:15 pavlin Exp $
#ifndef __POLICY_COMMON_DISPATCHER_HH__
#define __POLICY_COMMON_DISPATCHER_HH__
#include <string>
#include <sstream>
#include <map>
#include <vector>
#include <assert.h>
#include "element_base.hh"
#include "operator_base.hh"
#include "register_operations.hh"
#include "policy_exception.hh"
/**
* @short Link between elements and operations. Executes operations on elments.
*
* Implementation of multimethods.
* Insipred/copied from Alexandrescu [Modern C++ Design].
*
* By taking base element arguments and an operation, it will execute the
* correct operation based on the concrete type of the arguments.
*
* Similar to an ElementFactory.
*/
class Dispatcher {
public:
typedef vector<const Element*> ArgList;
Dispatcher();
/**
* @short Exception thrown if no operation is found for given arguments.
*
* If there is no combination for the given operation and element types.
*/
class OpNotFound : public PolicyException {
public:
OpNotFound(const string& err) : PolicyException(err) {}
};
/**
* Method to register a binary operation callback with dispatcher.
*
* @param L concrete class of first argument
* @param R concrete class of second argument
* @param funct function to be called to perform operation.
* @param op cinary operation to be registered.
*/
template<class L, class R, Element* (*funct)(const L&,const R&)>
void
add(const BinOper& op) {
// XXX: do it in a better way
L arg1;
R arg2;
ArgList args;
args.push_back(&arg1);
args.push_back(&arg2);
Key key = makeKey(op,args);
struct Local {
static Element* Trampoline(const Element& left, const Element& right) {
return funct(dynamic_cast<const L&>(left),
dynamic_cast<const R&>(right));
}
};
_map[key].bin = &Local::Trampoline;
}
/**
* Method to register a unary operation callback with dispatcher.
*
* @param T concrete class of argument
* @param funct function to be called to perform operation.
* @param op unary operation to be registered.
*/
template<class T, Element* (*funct)(const T&)>
void add(const UnOper& op) {
// XXX: ugly
T arg;
ArgList args;
args.push_back(&arg);
Key key = makeKey(op,args);
struct Local {
static Element* Trampoline(const Element& arg) {
return funct(dynamic_cast<const T&>(arg));
}
};
_map[key].un = &Local::Trampoline;
}
/**
* Execute an n-ary operation.
*
* Throws an exception on failure.
*
* @return result of operation.
* @param op operation to dispatch.
* @param args arguments of operation.
*/
Element* run(const Oper& op, const ArgList& args) const;
/**
* Execute an unary operation.
*
* @return Result of operation. Caller is responsible for delete.
* @param op Operation to perform.
* @param arg Argument of operation.
*/
Element* run(const UnOper& op, const Element& arg) const ;
/**
* Execute a binary operation.
*
* @return result of operation. Caller is responsible for delete.
* @param op Operation to perform.
* @param left first argument.
* @param right second argument.
*/
Element* run(const BinOper& op,
const Element& left,
const Element& right) const;
private:
// Callback for binary operation
typedef Element* (*CB_bin)(const Element&, const Element&);
// Callback for unary operation
typedef Element* (*CB_un)(const Element&);
// Key which relates to a callback
typedef string Key;
// A key relates to either a binary (x)or unary operation.
typedef union {
CB_un un;
CB_bin bin;
} Value;
// Hashtable would be better
typedef map<Key,Value> Map;
/**
* Create a key for the callback table based on operation and arguments.
*
* @return key used for callback lookup.
* @param op requested operation.
* @param args the arguments for the operation.
*/
Key makeKey(const Oper& op, const ArgList& args) const;
// XXX: definition moved in header file to allow compilation on 2.95.x
/**
* Lookup a callback for the requested operation and elements.
* Throws exception if none is found.
*
* @return callback which will perform requested operation.
* @param op operation to perform.
* @param args the arguments of the operation.
*/
Value lookup(const Oper& op, const ArgList& args) const {
assert(op.arity() == args.size());
// find callback
Key key = makeKey(op,args);
Map::iterator i = _map.find(key);
// none found
if(i == _map.end()) {
ostringstream oss;
oss << "No operation registered for OP: " << op.str()
<< " Arity: " << op.arity() << " args:";
for(ArgList::const_iterator i = args.begin();
i != args.end(); ++i) {
const Element* arg = *i;
oss << " " << arg->type();
}
throw OpNotFound(oss.str());
}
return (*i).second;
}
// Only one global map. Creating multiple dispatcher is thus harmless.
// However, we may not have different dispatchers.
static Map _map;
// Do initial registration of callbacks.
static RegisterOperations _regops;
};
#endif // __POLICY_COMMON_DISPATCHER_HH__
Generated by: pavlin on possum.icir.org on Wed Apr 13 21:53:12 2005, using kdoc $.