Skip to content

Commit f4eb882

Browse files
committed
Expressions: Added transformedByDynamicCast
1 parent eafe032 commit f4eb882

File tree

4 files changed

+114
-1
lines changed

4 files changed

+114
-1
lines changed
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
==============================================================================
3+
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
5+
Copyright 2025 by sonible GmbH.
6+
7+
This file is part of VCTR - Versatile Container Templates Reconceptualized.
8+
9+
VCTR is free software: you can redistribute it and/or modify
10+
it under the terms of the GNU Lesser General Public License version 3
11+
only, as published by the Free Software Foundation.
12+
13+
VCTR is distributed in the hope that it will be useful,
14+
but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
GNU Lesser General Public License version 3 for more details.
17+
18+
You should have received a copy of the GNU Lesser General Public License
19+
version 3 along with VCTR. If not, see <https://www.gnu.org/licenses/>.
20+
==============================================================================
21+
*/
22+
23+
namespace vctr::expressions
24+
{
25+
26+
template <class T>
27+
concept isRefOrPtr = is::lvalueReference<T> || is::pointer<T>;
28+
29+
template <size_t extent, class SrcType, isRefOrPtr DstValueType, is::constant ExpectCastToSucceed>
30+
class TransformedByDynamicCast : public ExpressionTemplateBase
31+
{
32+
public:
33+
using value_type = DstValueType;
34+
35+
VCTR_COMMON_UNARY_EXPRESSION_MEMBERS (TransformedByDynamicCast, src)
36+
37+
VCTR_FORCEDINLINE constexpr DstValueType operator[] (size_t i) const
38+
{
39+
DstValueType casted = dynamic_cast<DstValueType> (src[i]);
40+
41+
if constexpr (is::pointer<ValueType<SrcType>> && ExpectCastToSucceed::value)
42+
VCTR_ASSERT (casted != nullptr);
43+
44+
return casted;
45+
}
46+
};
47+
48+
} // namespace vctr::expressions
49+
50+
namespace vctr
51+
{
52+
/** Transforms all source elements to DstValueType by applying a dynamic_cast<DstValueType> to them.
53+
54+
If expectCastToSucceed is true, then a VCTR_ASSERT will be inserted to ensure the dynamic cast
55+
did not result in nullptr when casting pointers.
56+
57+
@ingroup Expressions
58+
*/
59+
template <class DstType, bool expectCastToSucceed = true>
60+
constexpr inline ExpressionChainBuilder<expressions::TransformedByDynamicCast, DstType, Constant<expectCastToSucceed>> transformedByDynamicCastTo;
61+
62+
} // namespace vctr
63+

include/vctr/TypeTraitsAndConcepts/GenericConcepts.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ concept triviallyCopyable = std::is_trivially_copyable_v<T>;
8787
template <class T>
8888
concept nonConst = ! std::is_const_v<T>;
8989

90-
/** Constrains a type to be a pointer of a reference to a pointer */
90+
/** Constrains a type to be a pointer or a reference to a pointer */
9191
template <class T>
9292
concept pointer = std::is_pointer_v<std::remove_cvref_t<T>>;
9393

@@ -99,6 +99,10 @@ concept noPointer = ! std::is_pointer_v<std::remove_cvref_t<T>>;
9999
template <class T>
100100
concept uniquePtr = detail::IsStdUniquePtr<T>::value;
101101

102+
/** Constrains a type to be an lvalue reference */
103+
template <class T>
104+
concept lvalueReference = std::is_lvalue_reference_v<T>;
105+
102106
/** Constrains the type to be any instance of std::tuple */
103107
template <class T>
104108
concept stdTuple = detail::IsStdTuple<T>::value;

include/vctr/vctr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ VCTR_END_IGNORE_WARNING_MSVC
158158

159159
#include "Expressions/Generic/Map.h"
160160
#include "Expressions/Generic/TransformedBy.h"
161+
#include "Expressions/Generic/TransformedByDynamicCast.h"
161162
#include "Expressions/Generic/TransformedByStaticCast.h"
162163

163164
#include "Expressions/BasicMath/Abs.h"

test/TestCases/Expressions/Transformation.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,51 @@ double toDoublePlus1 (T in) { return static_cast<double> (in + T (1)); }
3131
template <vctr::is::realNumber T>
3232
std::string toStringPlus1 (T in) { return std::to_string (in + T (1)); }
3333

34+
TEST_CASE ("TransformedByDynamicCast", "[VCTR][transformation]")
35+
{
36+
struct A
37+
{
38+
virtual ~A() = default;
39+
int a;
40+
};
41+
42+
struct B
43+
{
44+
virtual ~B() = default;
45+
int b;
46+
};
47+
48+
struct C : A, B
49+
{
50+
C (int x, int y)
51+
{
52+
a = x;
53+
b = y;
54+
}
55+
56+
~C() override = default;
57+
};
58+
59+
vctr::Array<B*, 2> bs { new C (1, 2), new C (3, 4) };
60+
61+
vctr::Array aPtrs = vctr::transformedByDynamicCastTo<A*> << bs;
62+
vctr::Array aVals = vctr::transformedByStaticCastTo<A> << vctr::transformedByDynamicCastTo<A&> << vctr::transformedBy ([] (B* b)-> B& { return *b; }) << bs;
63+
64+
// The cast should have succeeded for all
65+
REQUIRE (aPtrs.all ([] (A* a) { return a != nullptr; }));
66+
67+
REQUIRE (aPtrs[0]->a == 1);
68+
REQUIRE (aPtrs[1]->a == 3);
69+
REQUIRE (aVals[0].a == 1);
70+
REQUIRE (aVals[1].a == 3);
71+
72+
// This cast should fail. Suppress assertion outputs for that case
73+
vctr::Array invalid = vctr::transformedByDynamicCastTo<std::string*, false> << bs;
74+
REQUIRE (invalid.allElementsEqual (nullptr));
75+
76+
bs.forEach ([] (B* b) { delete b; });
77+
}
78+
3479
TEMPLATE_PRODUCT_TEST_CASE ("TransformedByStaticCast", "[VCTR][transformation]", (PlatformVectorOps, VCTR_NATIVE_SIMD), (float, double, int16_t, int32_t, int64_t))
3580
{
3681
VCTR_TEST_DEFINES (10)

0 commit comments

Comments
 (0)