-
-
Notifications
You must be signed in to change notification settings - Fork 755
Add std.traits.{isNested,hasNested}.
#948
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1675,22 +1675,125 @@ unittest | |
| // Aggregate Types | ||
| //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// | ||
|
|
||
| /** | ||
| Determines whether $(D T) has its own context pointer. | ||
| $(D T) must be either $(D class), $(D struct), or $(D union). | ||
| */ | ||
| template isNested(T) | ||
| if(is(T == class) || is(T == struct) || is(T == union)) | ||
| { | ||
| enum isNested = __traits(isNested, T); | ||
| } | ||
|
|
||
| /** | ||
| Determines whether $(D T) or any of its representation types | ||
| have a context pointer. | ||
| */ | ||
| template hasNested(T) | ||
| { | ||
| static if(isStaticArray!T && T.length) | ||
| enum hasNested = hasNested!(typeof(T.init[0])); | ||
| else static if(is(T == class) || is(T == struct) || is(T == union)) | ||
| enum hasNested = isNested!T || | ||
| anySatisfy!(.hasNested, FieldTypeTuple!T); | ||
| else | ||
| enum hasNested = false; | ||
| } | ||
|
|
||
| unittest | ||
| { | ||
| static assert(!__traits(compiles, isNested!int)); | ||
| static assert(!hasNested!int); | ||
|
|
||
| static struct StaticStruct { } | ||
| static assert(!isNested!StaticStruct); | ||
| static assert(!hasNested!StaticStruct); | ||
|
|
||
| int i; | ||
| struct NestedStruct { void f() { ++i; } } | ||
| static assert( isNested!NestedStruct); | ||
| static assert( hasNested!NestedStruct); | ||
| static assert( isNested!(immutable NestedStruct)); | ||
| static assert( hasNested!(immutable NestedStruct)); | ||
|
|
||
| static assert(!__traits(compiles, isNested!(NestedStruct[1]))); | ||
| static assert( hasNested!(NestedStruct[1])); | ||
| static assert(!hasNested!(NestedStruct[0])); | ||
|
|
||
| struct S1 { NestedStruct nested; } | ||
| static assert(!isNested!S1); | ||
| static assert( hasNested!S1); | ||
|
|
||
| static struct S2 { NestedStruct nested; } | ||
| static assert(!isNested!S2); | ||
| static assert( hasNested!S2); | ||
|
|
||
| static struct S3 { NestedStruct[0] nested; } | ||
| static assert(!isNested!S3); | ||
| static assert(!hasNested!S3); | ||
|
|
||
| static union U { NestedStruct nested; } | ||
| static assert(!isNested!U); | ||
| static assert( hasNested!U); | ||
|
|
||
| static class StaticClass { } | ||
| static assert(!isNested!StaticClass); | ||
| static assert(!hasNested!StaticClass); | ||
|
|
||
| class NestedClass { void f() { ++i; } } | ||
| static assert( isNested!NestedClass); | ||
| static assert( hasNested!NestedClass); | ||
| static assert( isNested!(immutable NestedClass)); | ||
| static assert( hasNested!(immutable NestedClass)); | ||
|
|
||
| static assert(!__traits(compiles, isNested!(NestedClass[1]))); | ||
| static assert( hasNested!(NestedClass[1])); | ||
| static assert(!hasNested!(NestedClass[0])); | ||
| } | ||
|
|
||
|
|
||
| /*** | ||
| * Get the types of the fields of a struct or class. | ||
| * Get as a typetuple the types of the fields of a struct, class, or union. | ||
| * This consists of the fields that take up memory space, | ||
| * excluding the hidden fields like the virtual function | ||
| * table pointer. | ||
| * table pointer or a context pointer for nested types. | ||
| * If $(D T) isn't a struct, class, or union returns typetuple | ||
| * with one element $(D T). | ||
| */ | ||
|
|
||
| template FieldTypeTuple(S) | ||
| template FieldTypeTuple(T) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @andralex: Shouldn't we try to constraint this template to only aggregate types? I don't see the use case for
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, not worth the potential breakage imho.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. May help some recursion in client code. Having this closure property is nice I think. |
||
| { | ||
| static if (is(S == struct) || is(S == class) || is(S == union)) | ||
| alias typeof(S.tupleof) FieldTypeTuple; | ||
| static if (is(T == struct) || is(T == union)) | ||
| alias typeof(T.tupleof[0 .. $ - isNested!T]) FieldTypeTuple; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yay, boolean to integer promotion rules… There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One thing though: Is it guaranteed the context pointer is always the last field? Is this defined in the spec anywhere?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not sure if it is defined somewhere (I couldn't find anything either when I looked for a spec on the ABI side of this). This is, however, as far as I can see currently the only sane implementation of the trait, and the unit test will blow up if that behavior ever changes. |
||
| else static if (is(T == class)) | ||
| alias typeof(T.tupleof) FieldTypeTuple; | ||
| else | ||
| alias TypeTuple!S FieldTypeTuple; | ||
| //static assert(0, "argument is not struct or class"); | ||
| alias TypeTuple!T FieldTypeTuple; | ||
| } | ||
|
|
||
| unittest | ||
| { | ||
| static assert(is(FieldTypeTuple!int == TypeTuple!int)); | ||
|
|
||
| static struct StaticStruct1 { } | ||
| static assert(is(FieldTypeTuple!StaticStruct1 == TypeTuple!())); | ||
|
|
||
| static struct StaticStruct2 { int a, b; } | ||
| static assert(is(FieldTypeTuple!StaticStruct2 == TypeTuple!(int, int))); | ||
|
|
||
| int i; | ||
|
|
||
| struct NestedStruct1 { void f() { ++i; } } | ||
| static assert(is(FieldTypeTuple!NestedStruct1 == TypeTuple!())); | ||
|
|
||
| struct NestedStruct2 { int a; void f() { ++i; } } | ||
| static assert(is(FieldTypeTuple!NestedStruct2 == TypeTuple!int)); | ||
|
|
||
| class NestedClass { int a; void f() { ++i; } } | ||
| static assert(is(FieldTypeTuple!NestedClass == TypeTuple!int)); | ||
| } | ||
|
|
||
|
|
||
| // // FieldOffsetsTuple | ||
| // private template FieldOffsetsTupleImpl(size_t n, T...) | ||
| // { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isNestedcauses compile error for non struct/union types? Rather simply returnsfalsefor them is better IMO.Do you have any strong argument about that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By restricting types
isNestedcan accept we reduce a potential to use it incorrectly as usingisNestednot insidestatic if(is(T == struct) ...)is dangerous. I.e. we unsureisNestedwill be used only if a user has astructorunionhe'd like to test andhasNestedwill be used otherwise.I hope in the future we will be able to check if a
classis nested. Probably you can help with this by adding a new__trait. AndisNestedwill also be able to check classes. For now if it will accept class it will silently work incorrect. And, illustrating my point in the first paragraph, we will have to carefully rewritehasNestedto not make a mistake.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on the current compiler's implementation, some hacky code might work for the nested class.
(This is rough code, and does not consider filed alignments).