...does what it says on the tin. Nargery : comments.
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
|
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
|
via #chiark
<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.)
more IRC discussion
<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.
Re: via #chiark
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).
Re: via #chiark