Thread overview | |||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
June 11, 2007 Q: Populating a structure with RTTI | ||||
---|---|---|---|---|
| ||||
Hello. Is it possible to populate a struct using RTTI? Example: Say I have a struct as such: struct Example { int x; int y; char[] z; } and I want to create and populate the structure from a function: T populate(T) () { T t; t.field[0] = 1; t.field[1] = 2; t.field[2] = "testing"; return t; } void main() { auto x = populate!(Example)(); } Is this possible? If so, what is the syntax? Thanks ahead, Myron. |
June 11, 2007 Re: Q: Populating a structure with RTTI | ||||
---|---|---|---|---|
| ||||
Posted in reply to Myron Alexander | Myron Alexander wrote:
> Hello.
>
> Is it possible to populate a struct using RTTI?
>
> Example:
>
> Say I have a struct as such:
>
> struct Example {
> int x;
> int y;
> char[] z;
> }
>
> and I want to create and populate the structure from a function:
>
> T populate(T) () {
> T t;
> t.field[0] = 1;
> t.field[1] = 2;
> t.field[2] = "testing";
> return t;
> }
>
> void main() {
> auto x = populate!(Example)();
> }
>
> Is this possible? If so, what is the syntax?
>
> Thanks ahead,
>
> Myron.
T populate (T) () {
T t;
t.tupleof[0] = 1;
t.tupleof[1] = 2;
t.tupleof[2] = "testing";
return t;
}
Although its dangerous, but I'm sure you knew that already.
-- Chris Nicholson-Sauls
|
June 11, 2007 Re: Q: Populating a structure with RTTI | ||||
---|---|---|---|---|
| ||||
Posted in reply to Myron Alexander | Hi Myron,
I am also thinking about this problem for quit a while.
Maybe you can use the D Mixin feature and compile time manipulation of strings to create an database-table adequate structure :
template GenStruct(char[] Name, char[] M1)
{
const char[] GenStruct = "struct " ~ Name ~ "{ int " ~ M1 ~ "; }";
}
mixin(GenStruct!("Foo", "bar"));
Just an idea, Bjoern
Myron Alexander schrieb:
> Hello.
>
> Is it possible to populate a struct using RTTI?
>
> Example:
>
> Say I have a struct as such:
>
> struct Example {
> int x;
> int y;
> char[] z;
> }
>
> and I want to create and populate the structure from a function:
>
> T populate(T) () {
> T t;
> t.field[0] = 1;
> t.field[1] = 2;
> t.field[2] = "testing";
> return t;
> }
>
> void main() {
> auto x = populate!(Example)();
> }
>
> Is this possible? If so, what is the syntax?
>
> Thanks ahead,
>
> Myron.
|
June 11, 2007 Re: Q: Populating a structure with RTTI | ||||
---|---|---|---|---|
| ||||
Posted in reply to Myron Alexander | Hi Myron, I think my previous suggestion will not work; (compiletime issue) However, I guess your question is regarding the database row[][] problem, or how to create an adequate datatype for an database-table at compile time. I would like to suggest to have a look on this solution (runtime) pseudo code first : program startup connecttodb // create object collection , in C# I would choose Arraylist def tablerow as Arraylist // browse system tables foreach table in db addTableInformation // name f.i. foreach tablerow in table // create an object which is adequate to the row datatyp // to do this use the /factory pattern/, see link below // next transfer rowinformation into this object add this object to tablerow end end So now you have a chained list of objects, where each object represents one table-row (or table-field, if you like) In D I would choose an associative array containing the tablename as index and the Arraylist as value; factory pattern link : http://www.dofactory.com/Patterns/PatternAbstract.aspx probabaly you prefer the prototyp pattern; You will find information regarding this pattern on the same site. Regarding the Arraylist, Tango has to offer a lot of collection classes, I guess ArraySeq is what you need, but I am not sure, so you have to ask Sean. your row class can look like this class row private: string rowname string rowtype boolean primeryKey .... end your concrete row class may be class varcharRow inherits row // alias varchar char[] private: varchar value // the row value ... end // So if your database-table-row type is varchar, we will add an //instance of varcharRow to Arraylist. Just a quick hack but hopefully I was able to figure out the idea; Some feedback would be nice; Bjoern Myron Alexander schrieb: > Hello. > > Is it possible to populate a struct using RTTI? > > Example: > > Say I have a struct as such: > > struct Example { > int x; > int y; > char[] z; > } > > and I want to create and populate the structure from a function: > > T populate(T) () { > T t; > t.field[0] = 1; > t.field[1] = 2; > t.field[2] = "testing"; > return t; > } > > void main() { > auto x = populate!(Example)(); > } > > Is this possible? If so, what is the syntax? > > Thanks ahead, > > Myron. |
June 11, 2007 Re: Q: Populating a structure with RTTI | ||||
---|---|---|---|---|
| ||||
Posted in reply to Chris Nicholson-Sauls | Chris Nicholson-Sauls wrote: > T populate (T) () { > T t; > t.tupleof[0] = 1; > t.tupleof[1] = 2; > t.tupleof[2] = "testing"; > return t; > } > > Although its dangerous, but I'm sure you knew that already. > > -- Chris Nicholson-Sauls Thanks Chris. I do have another problem that you may be able to help me with. Here is an example of how I would use the above: > import std.stdio; > import std.traits; > > /* Example value object. > */ > struct ValueStruc { > char[] name; > int age; > char[] addr1; > char[] addr2; > char[] addr3; > double balance; > } > > /* Typesafe database row object. > */ > struct Row(T ...) { > T t; > bool[T.length] nullFlag; > } > > /* Simulate a typesafe fetch from the database. > */ > Row!(T) fetchOne(T ...) () { > Row!(T) r; > /+ Won't compile: > int i = 0; > r.t[i++] = "Myron"; > r.t[i++] = 10; > r.t[i++] = "addr1"; > r.t[i++] = "addr2"; > r.t[i++] = "addr3"; > r.t[i++] = 100001.10; > +/ > r.t[0] = "Myron"; > r.t[1] = 10; > r.t[2] = "addr1"; > r.t[3] = "addr2"; > r.t[4] = "addr3"; > r.t[5] = 100001.10; > r.nullFlag[0] = false; r.nullFlag[1] = true; r.nullFlag[2] = false; return r; > } > > /* Fetch a typesafe record from the database and populate the struct. > */ > T fetchStruc(T) () { > static if (is (T == struct)) { > auto r = fetchOne!(FieldTypeTuple!(T))(); > T t; > > /+ Won't compile: > for (int i = 0; i < T.tupleof.length; i++) { > t.tupleof[i] = r.t[i]; > } > +/ > > // My nasty hack to get it to work: > static if ( 0 < T.tupleof.length) t.tupleof[0] = r.t[0]; > static if ( 1 < T.tupleof.length) t.tupleof[1] = r.t[1]; > static if ( 2 < T.tupleof.length) t.tupleof[2] = r.t[2]; > static if ( 3 < T.tupleof.length) t.tupleof[3] = r.t[3]; > static if ( 4 < T.tupleof.length) t.tupleof[4] = r.t[4]; > static if ( 5 < T.tupleof.length) t.tupleof[5] = r.t[5]; > > return t; > } else { > static assert (0); > } > } > > void main () { > auto x = fetchStruc!(ValueStruc) (); > writefln ("%s, %s, %s, %s, %s, %#.2f", x.name, x.age, x.addr1, x.addr2, x.addr3, x.balance); > } I would like to implement the "Won't compile" blocks but have no clue if it is even possible. I'm thinking either a mixin, or a compile time function or something to that effect would allow me to build the functions so I don't have to use a whole whackload of static ifs as I have done in the fetchStruc. If I can get this right, would make my normal use-case much easier. Thanks, Myron. |
June 11, 2007 Re: Q: Populating a structure with RTTI | ||||
---|---|---|---|---|
| ||||
Posted in reply to BLS | BLS wrote:
> Hi Myron, I think my previous suggestion will not work; (compiletime issue)
Hello Bjoern.
Thanks for the suggestion.
I am hoping to build what I call a type-safe fetch mechanism so constructing the template at compile time is not a problem. For an example of what I am hoping to achieve, take a look at my response to Chris. If I can get that right, I will be extremely happy.
I currently have a "generic" mechanism using Box arrays and I am trying to keep my implementation as "simple" as possible so the use of DAO type factories does not fit into the theme.
All the best,
Myron.
|
June 11, 2007 Re: Q: Populating a structure with RTTI | ||||
---|---|---|---|---|
| ||||
Posted in reply to Myron Alexander | Myron Alexander wrote:
>> /+ Won't compile:
>> for (int i = 0; i < T.tupleof.length; i++) {
>> t.tupleof[i] = r.t[i];
>> }
>> +/
You can use foreach on tuples:
foreach(index, value; r.t)
t.tupleof[index] = value;
|
June 11, 2007 Re: Q: Populating a structure with RTTI | ||||
---|---|---|---|---|
| ||||
Posted in reply to Lutger | Lutger wrote:
> Myron Alexander wrote:
>>> /+ Won't compile:
>>> for (int i = 0; i < T.tupleof.length; i++) {
>>> t.tupleof[i] = r.t[i];
>>> }
>>> +/
>
> You can use foreach on tuples:
>
> foreach(index, value; r.t)
> t.tupleof[index] = value;
I missed the other one, this could be done in a similar fashion, for example:
/+ Won't compile:
int i = 0;
r.t[i++] = "Myron";
r.t[i++] = 10;
r.t[i++] = "addr1";
r.t[i++] = "addr2";
r.t[i++] = "addr3";
r.t[i++] = 100001.10;
+/
with a helper function:
void populateRow(R, T...)(inout R r, T t)
{
static assert(is(typeof(r.t) == T));
foreach(index, value; t)
r.t[index] = value;
}
inside fetchOne:
populateRow(r, "Myron"[], 10, "addr1"[], "addr2"[], "addr3"[], 100001.10);
|
June 11, 2007 Re: Q: Populating a structure with RTTI | ||||
---|---|---|---|---|
| ||||
Posted in reply to Lutger | Lutger wrote: > Myron Alexander wrote: >>> /+ Won't compile: >>> for (int i = 0; i < T.tupleof.length; i++) { >>> t.tupleof[i] = r.t[i]; >>> } >>> +/ > > You can use foreach on tuples: > > foreach(index, value; r.t) > t.tupleof[index] = value; Thanks Lutger. One down, one to go. Regards, Myron. P.S. Here is an example using 2 structs: > import std.stdio; > import std.traits; > > /* Example value object. > */ > struct ValueStruc { > char[] name; > int age; > char[] addr1; > char[] addr2; > char[] addr3; > double balance; > } > > struct OtherValue { > int type; > char[] dirname; > char[] filename; > } > > struct ValueStrucWNull { > char[] name; > int age; > char[] addr1; > char[] addr2; > char[] addr3; > double balance; > > bool[6] nullFlag; > } > > struct OtherValueWNull { > int type; > char[] dirname; > char[] filename; > bool[3] nullFlag; > } > > /* Typesafe database row object. > */ > struct Row(T ...) { > T t; > bool[T.length] nullFlag; > } > > /* Simulate a typesafe fetch from the database. > */ > Row!(T) fetchone(T ...) () { > Row!(T) r; > /+ --- Won't compile -------------------------------------------------- > int i = 0; > r.t[i++] = "Myron"; > r.t[i++] = 10; > r.t[i++] = "addr1"; > r.t[i++] = "addr2"; > r.t[i++] = "addr3"; > r.t[i++] = 100001.10; > ----------------------------------------------------------------------- > +/ > static if (T.length == 6) { > r.t[0] = "Myron"; > r.t[1] = 10; > r.t[2] = "addr1"; > r.t[3] = "addr2"; > r.t[4] = "addr3"; > r.t[5] = 100001.10; > r.nullFlag[0] = true; r.nullFlag[1] = false; r.nullFlag[2] = false; r.nullFlag[3] = true; r.nullFlag[4] = false; r.nullFlag[5] = false; } > > static if (T.length == 3) { > r.t [0] = 34; > r.t [1] = r"c:\dir1\dir2\dir2\"; > r.t [2] = "filename"; > r.nullFlag[0] = false; r.nullFlag[1] = true; r.nullFlag[2] = false; } > > return r; > } > > /* Fetch a typesafe record from the database and populate the struct. > */ > T fetchstruc(T) () { > static if (is (T == struct)) { > auto r = fetchone!(FieldTypeTuple!(T))(); > T t; > foreach (i, v; r.t) { > t.tupleof[i] = v; > } > return t; > > } else { > static assert (0); > } > } > > /* Fetch a typesafe record from the database, populate the struct and set > * null field flags. > */ > T fetchnullstruc(T) () { > static if (is (T == struct)) { > auto r = fetchone!(FieldTypeTuple!(T)[0..length-1])(); > T t; > foreach (i, v; r.t) { > t.tupleof[i] = v; > } > foreach (i, nullFlagValue; r.nullFlag) { > t.nullFlag[i] = nullFlagValue; > } > return t; > > } else { > static assert (0); > } > } > > > void main () { > auto x = fetchstruc!(ValueStruc) (); > writefln ("%s, %s, %s, %s, %s, %#.2f", x.name, x.age, x.addr1, x.addr2, x.addr3, x.balance); > > auto y = fetchstruc!(OtherValue) (); > writefln ("%s, %s, %s", y.type, y.dirname, y.filename); > auto a = fetchnullstruc!(ValueStrucWNull) (); > writefln ("%s, %s, %s, %s, %s, %#.2f, %s", a.name, a.age, a.addr1, a.addr2, a.addr3, a.balance, a.nullFlag); > > auto b = fetchnullstruc!(OtherValueWNull) (); > writefln ("%s, %s, %s, %s", b.type, b.dirname, b.filename, b.nullFlag); > } |
June 11, 2007 Re: Q: Populating a structure with RTTI | ||||
---|---|---|---|---|
| ||||
Posted in reply to Lutger | Lutger wrote:
> I missed the other one, this could be done in a similar fashion, for example:
>
> /+ Won't compile:
> int i = 0;
> r.t[i++] = "Myron";
> r.t[i++] = 10;
> r.t[i++] = "addr1";
> r.t[i++] = "addr2";
> r.t[i++] = "addr3";
> r.t[i++] = 100001.10;
> +/
>
>
> with a helper function:
>
> void populateRow(R, T...)(inout R r, T t)
> {
> static assert(is(typeof(r.t) == T));
> foreach(index, value; t)
> r.t[index] = value;
> }
>
>
> inside fetchOne:
>
> populateRow(r, "Myron"[], 10, "addr1"[], "addr2"[], "addr3"[], 100001.10);
Thanks. I can't make use of that as the fetch is a generic fetch from a database so it does not know the number of parameters upfront.
This is an example of what I would like to do:
for (int i = 0; i < r.t.length; i++) {
getByType (i, r.t[i]);
}
Where getByType is a method on the statement object that get's the i'th column and sets r.t[i].
getByType (int i, ref int value);
getByType (int i, ref long value);
getByType (int i, ref char[] value);
...
That is just a paradigm example, it could also be written using:
for (int i = 0; i < r.t.length; i++) {
if (r.t[i].type = typeid (int) {
r.t[i] = getInt (i);
} else if ...
}
Any ideas?
Thanks,
Myron.
|
Copyright © 1999-2021 by the D Language Foundation