[aspectc-user] Template metaprograms to process function arguments
Mike Mortensen
mmo at fc.hp.com
Thu Feb 1 01:47:43 CET 2007
I'm looking at converting some Design-by-contract type of checks for functions
into an aspect or set of aspects. A simple case of this is checking for NULL
pointers for a given Framework API. For example, suppose I have some classes to
represent electrical circuit objects, such as:
bcmCell, bcmNet, and bcmInstance
An application might build it's own functions using these objects and
might pass pointers to the various 'bcm' classes, like this:
float GetNetCap(bcmNet *net)
void GetInstInfo(string& info, bcmInstance* i)
void GetCellInfo(int a, int b, int c, bcmCell* cellPtr, string header)
A very simple contract is to assume that any bcmNet*, bcmInstance*,or bcmCell* is
not NULL, so that we don't have method calls on a NULL pointer. As you can see,
in this example, the argument that is one of these pointer types could be anywhere
in the argument list.
What I'm trying to do is 'leverage' the code in the article "On Typesafe Aspect
Implementations in C++" by Lohmann and Spinczyk. The article is very good! And it
has an aspect that processes an argument list for MS Windows error handling (page 9)
and 'streams' them out so that they can be part of an error message.
I thought I'd start by creating an aspect that just uses stream operators to print out
the arguments, and then (once this is working) I could overload the stream operators
for bcmNet*, bcmInstance*, and so forth to have the NULL checking...
Although I've used templates (such as template classes and functions) and I've created
various types of aspects before, I must confess I'm not an expert at template metaprograms,
so please forgive me if leveraging this code in this way is a bad or wrong idea. :-)
My example 'program' consists of main.cc and api.h, and my aspect is in DBC.ah. The program
compiles and runs w/o aspects.
I use 'whole program analysis' mode on a Linux system with ac++ and g++-3.x, and the
weave completes without any complaints. However, when I compile the woven code I get
errors:
In file included from src.out/main.cc:229:
src.out/DBC.ah:58: error: duplicate nested type `struct ArgChecker::ArgChecker'
src.out/DBC.ah: In static member function `static ArgChecker*
ArgChecker::aspectof()':
src.out/DBC.ah:49: error: aggregate `ArgChecker::ArgChecker __instance' has
incomplete type and cannot be defined
src.out/DBC.ah: In static member function `static void
ArgChecker::stream_params<TJP, N>::process(std::ostream&, TJP*)':
src.out/DBC.ah:63: error: parse error before `;' token
src.out/DBC.ah: In static member function `static void
ArgChecker::stream_params<TJP, 1>::process(std::ostream&, TJP*)':
src.out/DBC.ah:72: error: parse error before `;' token
The key issue seems to be that the generated (woven) DBC.ah file contains ArgChecker (the aspect)
within itself. Here's part of the woven DBC.ah file with line numbers shown:
46 class ArgChecker {
47 public:
48 static ArgChecker *aspectof () {
49 static ArgChecker __instance;
50 return &__instance;
51 }
52 static ArgChecker *aspectOf () {
53 return aspectof ();
54 }
55 private:
56
57
58 class ArgChecker;
59 template< class TJP, int N >
60 struct stream_params { friend class ::ArgChecker;
61
62 static void process (ostream& os, TJP* tjp ) {
63 os << *tjp->arg<TJP::ARGS-N>() << ", ";
64 stream_params< TJP, N - 1 >::process( os, tjp);
65 }
66 };
67 class ArgChecker;
I'll also attach it as DBC.ah.out. Has anyone seen a similar problem before?
Is the error in DBC.ah a problem with how the weaver processed the template metaprogram?
Is there an error in my template definitions for this context?
More generally, if another approach was possible in which the aspect processed the arguments
at runtime, that would be fine too. However, I need to know the type of the argument so that I
ignore arguments with datatype such as int and string and only consider (and check for NULL) the bcmNet*
and other API arguments. I'm not sure how to do this with arguments.
With the result() JoinPoint call we can use the JoinPoint::Result type to get
the actual type (instead of a void*), but for arguments, the arg(int) call
returns a void* and I haven't been able to use argtype(int) as an actual type.
It is defined as a AC::Type rather than an actual C++ type I think....
Does anyone have either suggestions on fixing my template code above or some other general approach for
processing the argument list to check arguments that have some specific, user-defined (i.e. not-built in)
datatype?
Thanks!
-Mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: main.cc
Type: text/x-c++src
Size: 1318 bytes
Desc: not available
Url : http://p15111082.pureserver.info/pipermail/aspectc-user/attachments/20070131/30a49544/main.bin
-------------- next part --------------
A non-text attachment was scrubbed...
Name: api.h
Type: text/x-chdr
Size: 912 bytes
Desc: not available
Url : http://p15111082.pureserver.info/pipermail/aspectc-user/attachments/20070131/30a49544/api.bin
-------------- next part --------------
#ifndef __ac_FIRST__net_hpsvmmo_home_mmo_AOP_AOP_Builds_Dbc_simple_src__
#define __ac_FIRST__net_hpsvmmo_home_mmo_AOP_AOP_Builds_Dbc_simple_src__
#define __ac_FIRST_FILE__net_hpsvmmo_home_mmo_AOP_AOP_Builds_Dbc_simple_src_DBC_ah__
#ifndef __ac_h_
#define __ac_h_
namespace AC {
typedef const char* Type;
enum JPType { CALL = 0x0004, EXECUTION = 0x0008, CONSTRUCTION = 0x0010, DESTRUCTION = 0x0020 };
struct Action {
void **_args; void *_result; void *_target; void *_that; void *_fptr;
void (*_wrapper)(Action &);
inline void trigger () { _wrapper (*this); }
};
struct AnyResultBuffer {};
template <typename T> struct ResultBuffer : public AnyResultBuffer {
char _data[sizeof (T)];
~ResultBuffer () { ((T*)_data)->T::~T(); }
operator T& () const { return *(T*)_data; }
};
template <class Aspect, int Index>
struct CFlow {
static int &instance () {
static int counter = 0;
return counter;
}
CFlow () { instance ()++; }
~CFlow () { instance ()--; }
static bool active () { return instance () > 0; }
};
}
inline void * operator new (unsigned int, AC::AnyResultBuffer *p) { return p; }
inline void operator delete (void *, AC::AnyResultBuffer *) { } // for VC++
#endif // __ac_h_
#endif // __ac_FIRST__net_hpsvmmo_home_mmo_AOP_AOP_Builds_Dbc_simple_src__
#ifndef DBC_AH
#define DBC_AH
#include <iostream>
#include <errno.h>
using namespace std;
#include "api.h"
class ArgChecker {
public:
static ArgChecker *aspectof () {
static ArgChecker __instance;
return &__instance;
}
static ArgChecker *aspectOf () {
return aspectof ();
}
private:
class ArgChecker;
template< class TJP, int N >
struct stream_params { friend class ::ArgChecker;
static void process (ostream& os, TJP* tjp ) {
os << *tjp->arg<TJP::ARGS-N>() << ", ";
stream_params< TJP, N - 1 >::process( os, tjp);
}
};
class ArgChecker;
template< class TJP >
struct stream_params < TJP, 1 > { friend class ::ArgChecker;
static void process(ostream& os, TJP* tjp) {
os << *tjp->arg< TJP::ARGS - 1>();
os << endl;
}
};
public: template<class JoinPoint> void __a0_around (JoinPoint *tjp) {
typedef typename JoinPoint::That __JP_That;
typedef typename JoinPoint::Target __JP_Target;
typedef typename JoinPoint::Result __JP_Result;
cerr << "AC: Inside ArgChecker for: " << JoinPoint::signature() << endl;
stream_params< JoinPoint, JoinPoint::ARGS >::process(cerr, tjp );
tjp->proceed();
cerr << "AC: Done executing around " << JoinPoint::signature() << endl;
}
private:
};
namespace AC {
template <class JoinPoint>
inline void invoke_ArgChecker_ArgChecker_a0_around (JoinPoint *tjp) {
::ArgChecker::aspectof()->__a0_around (tjp);
}
}
#endif
#ifdef __ac_FIRST_FILE__net_hpsvmmo_home_mmo_AOP_AOP_Builds_Dbc_simple_src_DBC_ah__
/*** begin of aspect includes ***/
#if !defined(__ac_have__net_hpsvmmo_home_mmo_AOP_AOP_Builds_Dbc_simple_src_DBC_ah__) && defined(__ac_need__net_hpsvmmo_home_mmo_AOP_AOP_Builds_Dbc_simple_src_DBC_ah__)
#define __ac_have__net_hpsvmmo_home_mmo_AOP_AOP_Builds_Dbc_simple_src_DBC_ah__
#include "DBC.ah"
#endif
/*** end of aspect includes ***/
#undef __ac_FIRST__net_hpsvmmo_home_mmo_AOP_AOP_Builds_Dbc_simple_src__
#undef __ac_FIRST_FILE__net_hpsvmmo_home_mmo_AOP_AOP_Builds_Dbc_simple_src_DBC_ah__
#endif // __ac_FIRST_FILE__net_hpsvmmo_home_mmo_AOP_AOP_Builds_Dbc_simple_src_DBC_ah__
More information about the aspectc-user
mailing list