[llvm] r222644 - Support: Add *cast_or_null<> for pointer wrappers
David Blaikie
dblaikie at gmail.com
Wed Dec 3 14:19:47 PST 2014
On Wed, Dec 3, 2014 at 2:13 PM, Pete Cooper <peter_cooper at apple.com> wrote:
>
> On Dec 3, 2014, at 2:00 PM, David Blaikie <dblaikie at gmail.com> wrote:
>
>
>
> On Fri, Nov 28, 2014 at 6:14 PM, Duncan P. N. Exon Smith <
> dexonsmith at apple.com> wrote:
>
>>
>> > On 2014 Nov 24, at 09:01, David Blaikie <dblaikie at gmail.com> wrote:
>> >
>> >
>> >
>> > On Sun, Nov 23, 2014 at 7:13 PM, Duncan P. N. Exon Smith <
>> dexonsmith at apple.com> wrote:
>> > Author: dexonsmith
>> > Date: Sun Nov 23 21:13:02 2014
>> > New Revision: 222644
>> >
>> > URL: http://llvm.org/viewvc/llvm-project?rev=222644&view=rev
>> > Log:
>> > Support: Add *cast_or_null<> for pointer wrappers
>> >
>> > I'm assuming this is intended to work with unique_ptr? (is it worth
>> testing with unique_ptr itself, then? (I'm honestly not sure))
>>
>> Well, yes, but not only `unique_ptr<>`. My motivating use case is a
>> yet-to-be-committed pointer-wrapper for `Metadata` operands, similar
>> to `Use` for `Value`.
>>
>> I think testing a dumb pointer-wrapper directly matches better how
>> `simpify_type` is implemented. And it's a bit more flexible if at
>> some point we want to support a type that supports `simplify_type`
>> but doesn't have an `operator bool()`.
>>
>
> Hmm, OK. (we could use "== nullptr" as the boolean test, rather than
> operator bool, not sure either's better, so long as it can cope with
> explicit operator bool, which I see you tested)
>
>
>>
>> >
>> > In some cases, we actually want ownership transfer:
>> >
>> > unique_ptr<Base> b = ...;
>> > unique_ptr<Derived> d = dyn_cast<Derived>(b);
>> > assert(b ^ d);
>> >
>> > But I guess it's probably not the right thing to use the existing
>> names/templates for this task? (if we mostly /don't/ want to transfer
>> ownership, which I guess is probably the case(?)) Maybe we'll eventually
>> add some new names for this (*cast*_transfer(?))
>>
> cast*_move perhaps? Given that i’d write std::move to transfer ownership
> from one unique_ptr to another, would it be reasonable to overload that
> name here?
>
Quite possibly.
>
> Pete
>
>
>> I agree we would need different names, but I'm not sure it fits in
>> the same library -- these are meant to be lightweight RTTI
>> replacements. Ownership transfer seems perpendicular to RTTI.
>>
>
> Except it unfortunately isn't - see
> http://en.cppreference.com/w/cpp/memory/shared_ptr/pointer_cast - mostly
> because those shared_ptr is more finicky to transfer ownership while
> changing types, etc. So there aren't equivalents for unique_ptr - but like
> make_shared, there's some convenience in also having make_unique (& thus in
> having unique_casts).
>
>
>> Nevertheless, I wouldn't be against having convenient wrappers for
>> casting+transfer if we have enough use cases for it...
>>
>
> *nod* some day, perhaps
>
>
>>
>> >
>> >
>> > Fill in omission of `cast_or_null<>` and `dyn_cast_or_null<>` for types
>> > that wrap pointers (e.g., smart pointers).
>> >
>> > Type traits need to be slightly stricter than for `cast<>` and
>> > `dyn_cast<>` to resolve ambiguities with simple types.
>> >
>> > There didn't seem to be any unit tests for pointer wrappers, so I tested
>> > `isa<>`, `cast<>`, and `dyn_cast<>` while I was in there.
>> >
>> > This only supports pointer wrappers with a conversion to `bool` to check
>> > for null. If in the future it's useful to support wrappers without such
>> > a conversion, it should be a straightforward incremental step to use the
>> > `simplify_type` machinery for the null check. In that case, the unit
>> > tests should be updated to remove the `operator bool()` from the
>> > `pointer_wrappers::PTy`.
>> >
>> > Modified:
>> > llvm/trunk/include/llvm/Support/Casting.h
>> > llvm/trunk/unittests/Support/Casting.cpp
>> >
>> > Modified: llvm/trunk/include/llvm/Support/Casting.h
>> > URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/Casting.h?rev=222644&r1=222643&r2=222644&view=diff
>> >
>> ==============================================================================
>> > --- llvm/trunk/include/llvm/Support/Casting.h (original)
>> > +++ llvm/trunk/include/llvm/Support/Casting.h Sun Nov 23 21:13:02 2014
>> > @@ -243,6 +243,26 @@ inline typename cast_retty<X, Y *>::ret_
>> > // accepted.
>> > //
>> > template <class X, class Y>
>> > +LLVM_ATTRIBUTE_UNUSED_RESULT inline typename std::enable_if<
>> > + !is_simple_type<Y>::value, typename cast_retty<X, const
>> Y>::ret_type>::type
>> > +cast_or_null(const Y &Val) {
>> > + if (!Val)
>> > + return nullptr;
>> > + assert(isa<X>(Val) && "cast_or_null<Ty>() argument of incompatible
>> type!");
>> > + return cast<X>(Val);
>> > +}
>> > +
>> > +template <class X, class Y>
>> > +LLVM_ATTRIBUTE_UNUSED_RESULT inline typename std::enable_if<
>> > + !is_simple_type<Y>::value, typename cast_retty<X,
>> Y>::ret_type>::type
>> > +cast_or_null(Y &Val) {
>> > + if (!Val)
>> > + return nullptr;
>> > + assert(isa<X>(Val) && "cast_or_null<Ty>() argument of incompatible
>> type!");
>> > + return cast<X>(Val);
>> > +}
>> > +
>> > +template <class X, class Y>
>> > LLVM_ATTRIBUTE_UNUSED_RESULT inline typename cast_retty<X, Y
>> *>::ret_type
>> > cast_or_null(Y *Val) {
>> > if (!Val) return nullptr;
>> > @@ -282,6 +302,20 @@ dyn_cast(Y *Val) {
>> > // value is accepted.
>> > //
>> > template <class X, class Y>
>> > +LLVM_ATTRIBUTE_UNUSED_RESULT inline typename std::enable_if<
>> > + !is_simple_type<Y>::value, typename cast_retty<X, const
>> Y>::ret_type>::type
>> > +dyn_cast_or_null(const Y &Val) {
>> > + return (Val && isa<X>(Val)) ? cast<X>(Val) : nullptr;
>> > +}
>> > +
>> > +template <class X, class Y>
>> > +LLVM_ATTRIBUTE_UNUSED_RESULT inline typename std::enable_if<
>> > + !is_simple_type<Y>::value, typename cast_retty<X,
>> Y>::ret_type>::type
>> > +dyn_cast_or_null(Y &Val) {
>> > + return (Val && isa<X>(Val)) ? cast<X>(Val) : nullptr;
>> > +}
>> > +
>> > +template <class X, class Y>
>> > LLVM_ATTRIBUTE_UNUSED_RESULT inline typename cast_retty<X, Y
>> *>::ret_type
>> > dyn_cast_or_null(Y *Val) {
>> > return (Val && isa<X>(Val)) ? cast<X>(Val) : nullptr;
>> >
>> > Modified: llvm/trunk/unittests/Support/Casting.cpp
>> > URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/Casting.cpp?rev=222644&r1=222643&r2=222644&view=diff
>> >
>> ==============================================================================
>> > --- llvm/trunk/unittests/Support/Casting.cpp (original)
>> > +++ llvm/trunk/unittests/Support/Casting.cpp Sun Nov 23 21:13:02 2014
>> > @@ -232,3 +232,99 @@ namespace TemporaryCast {
>> > struct pod {};
>> > IllegalCast *testIllegalCast() { return cast<foo>(pod()); }
>> > }
>> > +
>> > +namespace {
>> > +namespace pointer_wrappers {
>> > +
>> > +struct Base {
>> > + bool IsDerived;
>> > + Base(bool IsDerived = false) : IsDerived(IsDerived) {}
>> > +};
>> > +
>> > +struct Derived : Base {
>> > + Derived() : Base(true) {}
>> > + static bool classof(const Base *B) { return B->IsDerived; }
>> > +};
>> > +
>> > +class PTy {
>> > + Base *B;
>> > +public:
>> > + PTy(Base *B) : B(B) {}
>> > + LLVM_EXPLICIT operator bool() const { return get(); }
>> > + Base *get() const { return B; }
>> > +};
>> > +
>> > +} // end namespace pointer_wrappers
>> > +} // end namespace
>> > +
>> > +namespace llvm {
>> > +
>> > +template <> struct simplify_type<pointer_wrappers::PTy> {
>> > + typedef pointer_wrappers::Base *SimpleType;
>> > + static SimpleType getSimplifiedValue(pointer_wrappers::PTy &P) {
>> > + return P.get();
>> > + }
>> > +};
>> > +template <> struct simplify_type<const pointer_wrappers::PTy> {
>> > + typedef pointer_wrappers::Base *SimpleType;
>> > + static SimpleType getSimplifiedValue(const pointer_wrappers::PTy &P)
>> {
>> > + return P.get();
>> > + }
>> > +};
>> > +
>> > +} // end namespace llvm
>> > +
>> > +namespace {
>> > +namespace pointer_wrappers {
>> > +
>> > +// Some objects.
>> > +pointer_wrappers::Base B;
>> > +pointer_wrappers::Derived D;
>> > +
>> > +// Mutable "smart" pointers.
>> > +pointer_wrappers::PTy MN(nullptr);
>> > +pointer_wrappers::PTy MB(&B);
>> > +pointer_wrappers::PTy MD(&D);
>> > +
>> > +// Const "smart" pointers.
>> > +const pointer_wrappers::PTy CN(nullptr);
>> > +const pointer_wrappers::PTy CB(&B);
>> > +const pointer_wrappers::PTy CD(&D);
>> > +
>> > +TEST(CastingTest, smart_isa) {
>> > + EXPECT_TRUE(!isa<pointer_wrappers::Derived>(MB));
>> > + EXPECT_TRUE(!isa<pointer_wrappers::Derived>(CB));
>> > + EXPECT_TRUE(isa<pointer_wrappers::Derived>(MD));
>> > + EXPECT_TRUE(isa<pointer_wrappers::Derived>(CD));
>> > +}
>> > +
>> > +TEST(CastingTest, smart_cast) {
>> > + EXPECT_TRUE(cast<pointer_wrappers::Derived>(MD) == &D);
>> > + EXPECT_TRUE(cast<pointer_wrappers::Derived>(CD) == &D);
>> > +}
>> > +
>> > +TEST(CastingTest, smart_cast_or_null) {
>> > + EXPECT_TRUE(cast_or_null<pointer_wrappers::Derived>(MN) == nullptr);
>> > + EXPECT_TRUE(cast_or_null<pointer_wrappers::Derived>(CN) == nullptr);
>> > + EXPECT_TRUE(cast_or_null<pointer_wrappers::Derived>(MD) == &D);
>> > + EXPECT_TRUE(cast_or_null<pointer_wrappers::Derived>(CD) == &D);
>> > +}
>> > +
>> > +TEST(CastingTest, smart_dyn_cast) {
>> > + EXPECT_TRUE(dyn_cast<pointer_wrappers::Derived>(MB) == nullptr);
>> > + EXPECT_TRUE(dyn_cast<pointer_wrappers::Derived>(CB) == nullptr);
>> > + EXPECT_TRUE(dyn_cast<pointer_wrappers::Derived>(MD) == &D);
>> > + EXPECT_TRUE(dyn_cast<pointer_wrappers::Derived>(CD) == &D);
>> > +}
>> > +
>> > +TEST(CastingTest, smart_dyn_cast_or_null) {
>> > + EXPECT_TRUE(dyn_cast_or_null<pointer_wrappers::Derived>(MN) ==
>> nullptr);
>> > + EXPECT_TRUE(dyn_cast_or_null<pointer_wrappers::Derived>(CN) ==
>> nullptr);
>> > + EXPECT_TRUE(dyn_cast_or_null<pointer_wrappers::Derived>(MB) ==
>> nullptr);
>> > + EXPECT_TRUE(dyn_cast_or_null<pointer_wrappers::Derived>(CB) ==
>> nullptr);
>> > + EXPECT_TRUE(dyn_cast_or_null<pointer_wrappers::Derived>(MD) == &D);
>> > + EXPECT_TRUE(dyn_cast_or_null<pointer_wrappers::Derived>(CD) == &D);
>> > +}
>> > +
>> > +} // end namespace pointer_wrappers
>> > +} // end namespace
>> >
>> >
>> > _______________________________________________
>> > llvm-commits mailing list
>> > llvm-commits at cs.uiuc.edu
>> > http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>> >
>>
>>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20141203/5c9de508/attachment.html>
More information about the llvm-commits
mailing list