emperor: (Default)
posted by [personal profile] emperor at 11:37am on 30/05/2005
<Diziet> Why not have a virtual method table ?
<Emperor> How would that work, then?
<Diziet> struct GeneralMatrix { const GeneralMatrixVtable *vtable; /*other stuff goes here for each particular representation*/ };
<Diziet> struct GeneralMatrixVtable { int (*test)(GeneralMatrix*, ... etc.
<Diziet> #define MAT_TEST(m,a,x) ((m)->vtable->test((m),(a),(x)))
<Diziet> static const struct GeneralMatrixVtable vtable_for_byte_matrix= { bytematrix_test, ... }
<Emperor> Hm, yes, I can see that would work.
<Diziet> int bytematrix_test() { actual code; }
<Diziet> Modulo actual syntax and stuff :-).
<Diziet> This is actually OOP, of course, but it sounds like what you want is exactly OOP.
<Diziet> You can do it in C++ with a virtual base class and a bunch of concrete implementations of it but C++ is pretty nasty. In C it's not too hard; you just need a cast in each method to take the general pointer and turn it into the specific one for the kind of type, but it's not really error-prone.
<Diziet> There are a couple of examples of this kind of thing floating about. liboop is one, although it doesn't have the vtable in a separate struct.
<Diziet> (You do want the vtable in a separate struct so that you don't have to have a copy of it for each matrix.)
emperor: (Default)
posted by [personal profile] emperor at 02:45pm on 30/05/2005
<Diziet> You can use a union, but either that wastes memory by allocating enough memory for large representations when you have a small one, or it's a lie because it's not really a union, just the head of one.
<Diziet> So struct ByteArrayMatrix { GeneralMatrix general; actual stuff goes here; }
<Diziet> And then when you write bytematrix_test you cast the incoming GeneralMatrix* to a ByteArrayMatrix*.
<Diziet> The caller never allocates one. They just call GeneralMatrix *bytematrix_create(....)
<Diziet> Then they have GeneralMatrix *matrix which they can do matrix->vtable->test(matrix, ...) (via a macro if you want to do it lots).
<Diziet> s/which/with &/
<Diziet> bytematrix_create has a ByteArrayMatrix *bam= malloc(sizeof(*bam)) and returns &bam->general.
<Diziet> You should put a comment near GeneralMatrix general; in each SpecificKindOfMatrix saying not to move it from being the first member.
<Diziet> (C guarantees that the address of the first member is the same as the address of the whole struct, modulo type conversions.)
<Diziet> (If you need it to not be the first member, eg because something has already nabbed that trick, you can use offsetof but it's quite tedious.)
<ewx> if you have to use offsetof then hide the offsetofery behind a macro rather than typing it out lots of times
<Diziet> Oh, and of course you shouldn't call these things Matrix because they're not matrices.
 
posted by [identity profile] deliberateblank.livejournal.com at 02:48pm on 30/05/2005
One issue with converting from macros to functions is that these operations (essentially single bit testing and manipulation) are fairly trivial, such that the function call overhead can be many times higher than the cost of the operation itself. If you end up calling them a *lot* (like at the bottom of a nested loop) this overhead can become crippling to performance. Of course whether this is an issue for you or not depends on what exactly the client code is doing - ie you need to test it on some real world problems to find out.

Personally I'd go with the function name decoration with macros to choose a default set with undecorated versions of the names, but make the functions inlineable. If you put a key value in each matrix structure, higher level functions can choose the right low level implementation without needing to be duplicated for each one (or requiring an extra type parameter).
 
posted by [identity profile] womble2.livejournal.com at 08:19pm on 30/05/2005
Those of us who actually know C++ know that virtual function calls are rather more expensive than ordinary function calls, since they generally can't benefit from inlining or branch prediction. The same goes for any indirect branching mechanism.

October

SunMonTueWedThuFriSat
      1
 
2
 
3
 
4
 
5
 
6
 
7
 
8
 
9
 
10
 
11
 
12
 
13
 
14
 
15
 
16
 
17
 
18
 
19
 
20
 
21
 
22
 
23
 
24
 
25
26
 
27
 
28
 
29
 
30
 
31