Opinions on iterating a struct to absorb the decoding of a CSV?
cc
cc at nevernet.com
Mon Apr 1 04:54:46 UTC 2024
On Thursday, 28 March 2024 at 17:23:39 UTC, Andy Valencia wrote:
> I wanted a lightweight and simpler CSV decoder. I won't post
> the whole thing, but basically you instantiate one as:
That's pretty much the best way to do it. While `.tupleof` does
look kind of hacky, and you could instead iterate using
`___traits(allMembers, T)` and `__traits(getMember, T,
"symbolname")` which looks more self-documenting, this ends up
being more of a pain, because it's going to iterate through
everything in the type, including functions,
constructors/destructors, aliases, enums, static members,
inherited members in classes, etc etc, and it's a plate of
spaghetti to sort them all out, plus there are issues with
aliasing on top of that. Sometimes you might want to do that of
course, but for simple situations like this, `.tupleof` just
works.
```d
struct Foo {
int x = 1;
float f = 3.14;
string abc = "abc";
string[] xyz;
immutable int i;
const int c;
this(int x) { this.x = x; i = 7; c = 8; }
this(float f) { this.f = f; }
bool speak() { return false; }
bool speak(bool b) { return b; }
void toString(scope void delegate(const(char)[]) writer) {
/*...*/ }
alias X = int;
enum E = 3;
static enum F = 4;
static int y = 5;
}
void main() {
Foo foo;
dumpInfo(foo);
}
void dumpInfo(T)(T t) {
import std.traits;
static foreach (idx, field; T.tupleof) {{
alias TYPE = typeof(field);
enum NAME = field.stringof;
writefln("[%s] %s => %s", TYPE.stringof, NAME, t.tupleof[idx]);
}}
writeln;
static foreach (sym; __traits(allMembers, T)) {{
enum bool ISSTATIC = hasStaticMember!(T, sym);
static if (ISSTATIC)
alias SYM = __traits(getMember, T, sym);
else
alias SYM = __traits(getMember, t, sym);
enum NAME = sym;
static if (isType!SYM) { // aliases
writefln("(TYPE) %s : %s", NAME, SYM.stringof);
} else static if (isFunction!SYM) {
alias OVERLOADS = __traits(getOverloads, T, sym);
static foreach (idx, FUNC; OVERLOADS) {
writefln("(FUNC) %s<%s> : %s", NAME, idx,
typeof(FUNC).stringof);
writefln("\t%s %s %s", ReturnType!FUNC.stringof,
Parameters!FUNC.stringof,
ParameterIdentifierTuple!FUNC.stringof); // Useful
}
} else {
alias TYPE = typeof(SYM);
// where is isEnum or isManifestConstant?
enum bool ISASSIGNABLE = __traits(compiles,
{__traits(getMember, t, sym) = __traits(getMember, t, sym);});
enum bool ISASSIGNABLE_IN_CTOR = __traits(compiles,
{cast()__traits(getMember, t, sym) = cast()__traits(getMember, t,
sym);});
static if (!ISASSIGNABLE && !ISASSIGNABLE_IN_CTOR) {
// MAYBE it's an enum. Or something else unassignable.
writefln("(ENUM) [%s] %s => %s", TYPE.stringof, NAME, SYM);
} else static if (ISSTATIC) {
writefln("(STATIC) [%s] %s => %s", TYPE.stringof, NAME, SYM);
} else {
writefln("[%s] %s => %s", TYPE.stringof, NAME,
__traits(getMember, t, sym)); // SYM doesn't work here
}
}
}}
}
```
```
[int] x => 1
[float] f => 3.14
[string] abc => abc
[string[]] xyz => []
[immutable(int)] i => 0
[const(int)] c => 0
[int] x => 1
[float] f => 3.14
[string] abc => abc
[string[]] xyz => []
[immutable(int)] i => 0
[const(int)] c => 0
(FUNC) __ctor<0> : ref Foo(int x)
Foo (int) AliasSeq!("x")
(FUNC) __ctor<1> : ref Foo(float f)
Foo (float) AliasSeq!("f")
(FUNC) speak<0> : bool()
bool () ()
(FUNC) speak<1> : bool(bool b)
bool (bool) AliasSeq!("b")
(FUNC) toString<0> : void(scope void delegate(const(char)[])
writer)
void (scope void delegate(const(char)[])) AliasSeq!("writer")
(TYPE) X : int
(ENUM) [int] E => 3
(ENUM) [int] F => 4
(STATIC) [int] y => 5
```
I scoured [Traits](https://dlang.org/spec/traits.html) and
[std.traits](https://dlang.org/phobos/std_traits.html) looking
for a simple method to tell whether a member was declared as enum
but couldn't find one, so if anyone knows a proper way to do it
please let me know.
More information about the Digitalmars-d-learn
mailing list