mirror of
https://github.com/dlang/phobos.git
synced 2025-04-28 14:10:30 +03:00
Add isSameSymbol and isSameType to v3 traits and indexOf to v3 meta. (#8960)
indexOf is phobos.sys.meta's version of std.meta's staticIndexOf. The name was changed to better match our naming scheme. Because the result of the template is a value and not a type or AliasSeq, it is correct for it to be camelCased, but we don't normally prepend templates with static, making it inconsistent to do so in the case of indexOf. This might result in some symbol conflicts with indexOf from the algorithm modules (assuming that we retain that function and its name for Phobos v3), but a quick test showed that importing both phobos.sys.meta and std.algorithm didn't result in a symbol conflict when using the one from phobos.sys.meta. And even if we do get symbol conflicts in some situations, the module system is designed to allow us to deal with that. As for the implementation, I've both made indexOf more flexible and more straightforward. staticIndexOf looks for an element in the AliasSeq which is "the same" as the first argument, and that results in a big mess, since what "the same" is varies considerably depending on what the elements are, and staticIndexOf makes it even more complicated by evaluating some symbols at CTFE if it can (e.g. evaluating a no-arg function that returns an int to try to compare it to an integer literal) while not evaluating them in other cases. Not only did trying to document the current behavior make it clear that it's just way too confusing, but even trying to come up with a sane simplification of how the comparison works was just too messy, because it's trying to be able to compare just about anything which you can stick in an AliasSeq. So, I punted on it by taking the comparison out of the equation entirely. indexOf now takes a template predicate. So, rather than looking for an element which is the same, it looks for an element which matches the predicate. This allows indexOf to be used in more cases than staticIndexOf can be, _and_ it allows the programmer using it to decide how the comparison works by choosing a predicate that matches what they want. So, in conjuction with that I added isSameSymbol and isSameType to phobos.sys.traits, since those should correspond to the most common searches that someone would be trying to do with staticIndexOf, but since those traits are very specific in what they search for rather than searching for an element which is "the same" in some nebulous sense, the code should end up being much clearer and cleaner. And if someone wants to do something completely different like indexOf!(isInteger, Types), then they can, unlike with staticIndexOf.
This commit is contained in:
parent
a613e8f714
commit
ec0857574c
2 changed files with 209 additions and 1 deletions
|
@ -63,6 +63,7 @@
|
|||
$(TR $(TD Alias sequence searching) $(TD
|
||||
$(LREF all)
|
||||
$(LREF any)
|
||||
$(LREF indexOf)
|
||||
))
|
||||
)
|
||||
|
||||
|
@ -393,3 +394,81 @@ else
|
|||
|
||||
static assert(!any!isInteger);
|
||||
}
|
||||
|
||||
/++
|
||||
Returns the index of the first element where $(D Pred!(Args[i])) is
|
||||
$(D true).
|
||||
|
||||
If $(D Pred!(Args[i])) is not $(D true) for any elements, then the result
|
||||
is $(D -1).
|
||||
|
||||
Evaluation is $(I not) short-circuited if a $(D true) result is
|
||||
encountered; the template predicate must be instantiable with all the
|
||||
elements.
|
||||
+/
|
||||
template indexOf(alias Pred, Args...)
|
||||
{
|
||||
enum ptrdiff_t indexOf =
|
||||
{
|
||||
static foreach (i; 0 .. Args.length)
|
||||
{
|
||||
static if (Pred!(Args[i]))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}();
|
||||
}
|
||||
|
||||
///
|
||||
@safe unittest
|
||||
{
|
||||
import phobos.sys.traits : isInteger, isSameSymbol, isSameType;
|
||||
|
||||
alias Types1 = AliasSeq!(string, int, long, char[], ubyte, int);
|
||||
alias Types2 = AliasSeq!(float, double, int[], char[], void);
|
||||
|
||||
static assert(indexOf!(isInteger, Types1) == 1);
|
||||
static assert(indexOf!(isInteger, Types2) == -1);
|
||||
|
||||
static assert(indexOf!(isSameType!ubyte, Types1) == 4);
|
||||
static assert(indexOf!(isSameType!ubyte, Types2) == -1);
|
||||
|
||||
int i;
|
||||
int j;
|
||||
string s;
|
||||
int foo() { return 0; }
|
||||
alias Symbols = AliasSeq!(i, j, foo);
|
||||
static assert(indexOf!(isSameSymbol!j, Symbols) == 1);
|
||||
static assert(indexOf!(isSameSymbol!s, Symbols) == -1);
|
||||
|
||||
// Empty AliasSeq.
|
||||
static assert(indexOf!isInteger == -1);
|
||||
|
||||
// The predicate does not compile with all of the arguments,
|
||||
// so indexOf does not compile.
|
||||
static assert(!__traits(compiles, indexOf!(isSameType!int, long, int, 42)));
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
import phobos.sys.traits : isSameType;
|
||||
|
||||
static assert(indexOf!(isSameType!int, short, int, long) >= 0);
|
||||
static assert(indexOf!(isSameType!string, short, int, long) < 0);
|
||||
|
||||
// This is to verify that we don't accidentally end up with the type of
|
||||
// the result differing based on whether it's -1 or not. Not specifying the
|
||||
// type at all in indexOf results in -1 being int on all systems and the
|
||||
// other results being whatever size_t is (ulong on most systems at this
|
||||
// point), which does generally work, but being explicit with the type
|
||||
// avoids any subtle issues that might come from the type of the result
|
||||
// varying based on whether the item is found or not.
|
||||
static assert(is(typeof(indexOf!(isSameType!int, short, int, long)) ==
|
||||
typeof(indexOf!(isSameType!string, short, int, long))));
|
||||
|
||||
static assert(indexOf!(isSameType!string, string, string, string, string) == 0);
|
||||
static assert(indexOf!(isSameType!string, int, string, string, string) == 1);
|
||||
static assert(indexOf!(isSameType!string, int, int, string, string) == 2);
|
||||
static assert(indexOf!(isSameType!string, int, int, int, string) == 3);
|
||||
static assert(indexOf!(isSameType!string, int, int, int, int) == -1);
|
||||
}
|
||||
|
|
|
@ -51,7 +51,6 @@
|
|||
$(BOOKTABLE ,
|
||||
$(TR $(TH Category) $(TH Templates))
|
||||
$(TR $(TD Categories of types) $(TD
|
||||
$(TR $(TD Traits for removing type qualfiers) $(TD
|
||||
$(LREF isDynamicArray)
|
||||
$(LREF isFloatingPoint)
|
||||
$(LREF isInteger)
|
||||
|
@ -65,6 +64,10 @@
|
|||
$(LREF isImplicitlyConvertible)
|
||||
$(LREF isQualifierConvertible)
|
||||
))
|
||||
$(TR $(TD Traits for comparisons) $(TD
|
||||
$(LREF isSameSymbol)
|
||||
$(LREF isSameType)
|
||||
))
|
||||
$(TR $(TD Traits for removing type qualfiers) $(TD
|
||||
$(LREF Unconst)
|
||||
$(LREF Unshared)
|
||||
|
@ -1702,6 +1705,132 @@ enum isQualifierConvertible(From, To) = is(immutable From == immutable To) && is
|
|||
}
|
||||
}
|
||||
|
||||
/++
|
||||
Whether the given symbols are the same symbol.
|
||||
|
||||
All this does is $(D __traits(isSame, lhs, rhs)), so most code shouldn't
|
||||
use it. It's intended to be used in conjunction with templates that take a
|
||||
template predicate - such as those in phobos.sys.meta.
|
||||
|
||||
The single-argument overload makes it so that it can be partially
|
||||
instantiated with the first argument, which will often be necessary with
|
||||
template predicates.
|
||||
|
||||
See_Also:
|
||||
$(DDSUBLINK spec/traits, isSame, $(D __traits(isSame, lhs, rhs)))
|
||||
$(LREF isSameType)
|
||||
+/
|
||||
enum isSameSymbol(alias lhs, alias rhs) = __traits(isSame, lhs, rhs);
|
||||
|
||||
/++ Ditto +/
|
||||
template isSameSymbol(alias lhs)
|
||||
{
|
||||
enum isSameSymbol(alias rhs) = __traits(isSame, lhs, rhs);
|
||||
}
|
||||
|
||||
///
|
||||
@safe unittest
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
real r;
|
||||
|
||||
static assert( isSameSymbol!(i, i));
|
||||
static assert(!isSameSymbol!(i, j));
|
||||
static assert(!isSameSymbol!(i, r));
|
||||
|
||||
static assert(!isSameSymbol!(j, i));
|
||||
static assert( isSameSymbol!(j, j));
|
||||
static assert(!isSameSymbol!(j, r));
|
||||
|
||||
static assert(!isSameSymbol!(r, i));
|
||||
static assert(!isSameSymbol!(r, j));
|
||||
static assert( isSameSymbol!(r, r));
|
||||
|
||||
auto foo() { return 0; }
|
||||
auto bar() { return 0; }
|
||||
|
||||
static assert( isSameSymbol!(foo, foo));
|
||||
static assert(!isSameSymbol!(foo, bar));
|
||||
static assert(!isSameSymbol!(foo, i));
|
||||
|
||||
static assert(!isSameSymbol!(bar, foo));
|
||||
static assert( isSameSymbol!(bar, bar));
|
||||
static assert(!isSameSymbol!(bar, i));
|
||||
|
||||
// Types are symbols too. However, in most cases, they should be compared
|
||||
// as types, not symbols (be it with is expressions or with isSameType),
|
||||
// because the results aren't consistent between scalar types and
|
||||
// user-defined types with regards to type qualifiers when they're compared
|
||||
// as symbols.
|
||||
static assert( isSameSymbol!(double, double));
|
||||
static assert(!isSameSymbol!(double, const double));
|
||||
static assert(!isSameSymbol!(double, int));
|
||||
static assert( isSameSymbol!(Object, Object));
|
||||
static assert( isSameSymbol!(Object, const Object));
|
||||
|
||||
static assert(!isSameSymbol!(i, int));
|
||||
static assert( isSameSymbol!(typeof(i), int));
|
||||
|
||||
// Lambdas can be compared with __traits(isSame, ...),
|
||||
// so they can be compared with isSameSymbol.
|
||||
static assert( isSameSymbol!(a => a + 42, a => a + 42));
|
||||
static assert(!isSameSymbol!(a => a + 42, a => a + 99));
|
||||
|
||||
// Partial instantiation allows it to be used with templates that expect
|
||||
// a predicate that takes only a single argument.
|
||||
import phobos.sys.meta : AliasSeq, indexOf;
|
||||
alias Types = AliasSeq!(i, j, r, int, long, foo);
|
||||
static assert(indexOf!(isSameSymbol!j, Types) == 1);
|
||||
static assert(indexOf!(isSameSymbol!int, Types) == 3);
|
||||
static assert(indexOf!(isSameSymbol!bar, Types) == -1);
|
||||
}
|
||||
|
||||
/++
|
||||
Whether the given types are the same type.
|
||||
|
||||
All this does is $(D is(T == U)), so most code shouldn't use it. It's
|
||||
intended to be used in conjunction with templates that take a template
|
||||
predicate - such as those in phobos.sys.meta.
|
||||
|
||||
The single-argument overload makes it so that it can be partially
|
||||
instantiated with the first argument, which will often be necessary with
|
||||
template predicates.
|
||||
|
||||
See_Also:
|
||||
$(LREF isSameSymbol)
|
||||
+/
|
||||
enum isSameType(T, U) = is(T == U);
|
||||
|
||||
/++ Ditto +/
|
||||
template isSameType(T)
|
||||
{
|
||||
enum isSameType(U) = is(T == U);
|
||||
}
|
||||
|
||||
///
|
||||
@safe unittest
|
||||
{
|
||||
static assert( isSameType!(long, long));
|
||||
static assert(!isSameType!(long, const long));
|
||||
static assert(!isSameType!(long, string));
|
||||
static assert( isSameType!(string, string));
|
||||
|
||||
int i;
|
||||
real r;
|
||||
static assert( isSameType!(int, typeof(i)));
|
||||
static assert(!isSameType!(int, typeof(r)));
|
||||
|
||||
static assert(!isSameType!(real, typeof(i)));
|
||||
static assert( isSameType!(real, typeof(r)));
|
||||
|
||||
// Partial instantiation allows it to be used with templates that expect
|
||||
// a predicate that takes only a single argument.
|
||||
import phobos.sys.meta : AliasSeq, indexOf;
|
||||
alias Types = AliasSeq!(float, string, int, double);
|
||||
static assert(indexOf!(isSameType!int, Types) == 2);
|
||||
}
|
||||
|
||||
/++
|
||||
Removes the outer layer of $(D const), $(D inout), or $(D immutable)
|
||||
from type $(D T).
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue