Skip to content

Commit e0b96b3

Browse files
authored
Merge pull request #96 from ReflectCxx/develop
RObjectConverters - Heap clone fix.
2 parents d0aed6e + 5f52cc0 commit e0b96b3

5 files changed

Lines changed: 105 additions & 52 deletions

File tree

.codecov.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ comment:
1313

1414
ignore:
1515
- "demo/**"
16-
- "RTLBenchmarkApp/**"
16+
- "RTLBenchmarkApp/**"
17+
- "ReflectionTemplateLib/rtl/detail/src/RObjectConverters_string.cpp"

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,12 +170,12 @@ RTL provides the following callable entities, designed to be as lightweight and
170170

171171
These callable types are regular value types: they can be copied, moved, stored in standard containers, and passed around like any other lightweight object.
172172

173-
When invoked, only type-erased callables return an `rtl::error`, with results provided as `rtl::RObject` when both the return and target types are erased or as `std::optional<T>` when only the target type is erased, while fully type-aware callables return `T` directly with no error (by design).
173+
When invoked, only type-erased callables return an `rtl::error`, with results provided as `rtl::RObject` *(when both the return and target types are erased)* or as `std::optional<T>` *(when only the target type is erased)*, while fully type-aware callables return `T` directly with no error (by design).
174174

175175
### How to Build (Windows / Linux)
176176
```sh
177177
mkdir build && cd build
178-
cmake -G "<Generator>" # Use a C++20-compatible compiler
178+
cmake ../ -G "<Generator>" # Use a C++20-compatible compiler
179179
cmake --build .
180180
```
181181
Run the generated binaries from `bin/`:

RTLTestRunApp/src/RObjectTests/RObjectReflecting_strings.cpp

Lines changed: 37 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -337,43 +337,43 @@ namespace unit_test
337337
// Create an RObject that reflects a string value (init with 'std::string').
338338
RObject robj = rtl::reflect(STR_STD_STRING);
339339

340-
// Check if the value can be accessed as 'std::string'.
341-
ASSERT_TRUE(robj.canViewAs<std::string>());
342-
343-
// Try to obtain a view as 'std::string' and verify it is present.
344-
auto view0 = robj.view<std::string>();
345-
ASSERT_TRUE(view0.has_value());
346-
347-
// Validate the string content matches the original input.
348-
const std::string& str_cref0 = view0->get();
349-
ASSERT_EQ(str_cref0, STR_STD_STRING);
350-
351-
auto [err, robjcp] = robj.clone<rtl::alloc::Heap>();
352-
EXPECT_EQ(err, rtl::error::None);
353-
EXPECT_EQ(robj.getTypeId(), robjcp.getTypeId());
354-
355-
// Check if the value can be accessed as 'std::string'.
356-
ASSERT_TRUE(robj.canViewAs<std::string>());
357-
358-
// Try to obtain a view as 'std::string' and verify it is present.
359-
auto view1 = robj.view<std::string>();
360-
ASSERT_TRUE(view1.has_value());
361-
362-
// Validate the string content matches the original input.
363-
const std::string& str_cref1 = view1->get();
364-
ASSERT_EQ(str_cref1, STR_STD_STRING);
365-
ASSERT_TRUE(robjcp.canViewAs<char>());
366-
ASSERT_TRUE(robjcp.canViewAs<std::string>());
367-
368-
//TODO: Fix the crash here.
369-
370-
// Try to obtain a view as 'const char*' and verify it is present.
371-
//auto view2 = robjcp.view<char>();
372-
//ASSERT_TRUE(view2.has_value());
373-
374-
//// Validate the base address are different, since RObject is reflecting a copy.
375-
//const char& str_addr = view2->get();
376-
//ASSERT_NE(&str_addr, STR_STD_STRING.c_str());
340+
EXPECT_TRUE(robj.canViewAs<std::string>());
341+
EXPECT_TRUE(robj.canViewAs<char>());
342+
343+
auto testWithAlloc = [&]<typename rtl::alloc alloc_t>()
344+
{
345+
auto [err, robjcp] = robj.clone<alloc_t>();
346+
347+
EXPECT_EQ(err, rtl::error::None);
348+
EXPECT_EQ(robj.getTypeId(), robjcp.getTypeId());
349+
{
350+
// Check if the value can be accessed as 'std::string'.
351+
ASSERT_TRUE(robjcp.template canViewAs<std::string>());
352+
353+
// Try to obtain a view as 'std::string' and verify it is present.
354+
auto view = robjcp.template view<std::string>();
355+
ASSERT_TRUE(view.has_value());
356+
357+
// Validate the string content matches the original input.
358+
const std::string& str_cref = view->get();
359+
ASSERT_EQ(str_cref, STR_STD_STRING);
360+
} {
361+
ASSERT_TRUE(robjcp.template canViewAs<char>());
362+
363+
// Try to obtain a view as 'const char*' and verify it is present.
364+
auto view = robjcp.template view<char>();
365+
ASSERT_TRUE(view.has_value());
366+
367+
// Validate the base address are different, since RObject is reflecting a copy.
368+
const char& str_addr = view->get();
369+
ASSERT_NE(&str_addr, STR_STD_STRING.c_str());
370+
}
371+
};
372+
373+
// Should even std::string to 'char' conversion be allowed implicitly?
374+
// Need to re-think it. The implicit conversions are not used in core dispatch yet.
375+
testWithAlloc.operator()<rtl::alloc::Stack>();
376+
testWithAlloc.operator()<rtl::alloc::Heap>();
377377
}
378378

379379

ReflectionTemplateLib/rtl/detail/src/RObjectConverters_string.cpp

Lines changed: 64 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include <rtl/rtl_typeid.h>
1313
#include <detail/inc/ReflectCast.hpp>
14+
#include <detail/inc/RObjectUPtr.h>
1415

1516
namespace rtl::detail
1617
{
@@ -20,10 +21,27 @@ namespace rtl::detail
2021
{
2122
const auto& conversion = [](const std::any& pSrc, const EntityKind& pSrcEntityKind, EntityKind& pNewEntityKind)-> std::any
2223
{
23-
pNewEntityKind = EntityKind::Ptr;
24-
const auto& isPtr = (pSrcEntityKind == EntityKind::Ptr);
25-
const auto& srcObj = (isPtr ? *std::any_cast<const std::string*>(pSrc) : std::any_cast<const std::string&>(pSrc));
26-
return std::any(srcObj.c_str());
24+
try {
25+
pNewEntityKind = EntityKind::Ptr;
26+
const auto& isPtr = (pSrcEntityKind == EntityKind::Ptr);
27+
// GCOVR_EXCL_START
28+
if (pSrcEntityKind == EntityKind::Wrapper) {
29+
//TODO: Will fail for any other wrapper other than 'RObjectUPtr<>'.
30+
const auto& srcRUptr = std::any_cast<const RObjectUPtr<std::string>&>(pSrc);
31+
return std::any(srcRUptr.get()->c_str());
32+
}
33+
// GCOVR_EXCL_STOP
34+
else {
35+
const auto& srcObj = (isPtr ? *std::any_cast<const std::string*>(pSrc) : std::any_cast<const std::string&>(pSrc));
36+
return std::any(srcObj.c_str());
37+
}
38+
}
39+
// GCOVR_EXCL_START
40+
catch (const std::exception&) {
41+
pNewEntityKind = EntityKind::None;
42+
return std::any();
43+
}
44+
// GCOVR_EXCL_STOP
2745
};
2846
conversions().emplace_back(std::pair(traits::uid<char>::value, conversion));
2947
}
@@ -35,10 +53,27 @@ namespace rtl::detail
3553
{
3654
const auto& conversion = [](const std::any& pSrc, const EntityKind& pSrcEntityKind, EntityKind& pNewEntityKind)-> std::any
3755
{
38-
pNewEntityKind = EntityKind::Ptr;
39-
const auto& isPtr = (pSrcEntityKind == EntityKind::Ptr);
40-
const auto& srcObj = (isPtr ? *std::any_cast<const std::string_view*>(pSrc) : std::any_cast<const std::string_view&>(pSrc));
41-
return std::any(srcObj.data());
56+
try {
57+
pNewEntityKind = EntityKind::Ptr;
58+
const auto& isPtr = (pSrcEntityKind == EntityKind::Ptr);
59+
// GCOVR_EXCL_START
60+
if (pSrcEntityKind == EntityKind::Wrapper) {
61+
//TODO: Will fail for any other wrapper other than 'RObjectUPtr<>'.
62+
const auto& srcRUptr = std::any_cast<const RObjectUPtr<std::string>&>(pSrc);
63+
return std::any(srcRUptr.get()->data());
64+
}
65+
// GCOVR_EXCL_STOP
66+
else {
67+
const auto& srcObj = (isPtr ? *std::any_cast<const std::string_view*>(pSrc) : std::any_cast<const std::string_view&>(pSrc));
68+
return std::any(srcObj.data());
69+
}
70+
}
71+
// GCOVR_EXCL_START
72+
catch (const std::exception&) {
73+
pNewEntityKind = EntityKind::None;
74+
return std::any();
75+
}
76+
// GCOVR_EXCL_STOP
4277
};
4378
conversions().emplace_back(std::pair(traits::uid<char>::value, conversion));
4479
}
@@ -51,10 +86,27 @@ namespace rtl::detail
5186
using _toType = std::string;
5287
const auto& conversion = [](const std::any& pSrc, const EntityKind& pSrcEntityKind, EntityKind& pNewEntityKind)-> std::any
5388
{
54-
pNewEntityKind = EntityKind::Value;
55-
const auto& isPtr = (pSrcEntityKind == EntityKind::Ptr);
56-
const auto& srcObj = (isPtr ? *std::any_cast<const std::string_view*>(pSrc) : std::any_cast<const std::string_view&>(pSrc));
57-
return std::any(_toType(srcObj));
89+
try {
90+
pNewEntityKind = EntityKind::Value;
91+
const auto& isPtr = (pSrcEntityKind == EntityKind::Ptr);
92+
// GCOVR_EXCL_START
93+
if (pSrcEntityKind == EntityKind::Wrapper) {
94+
//TODO: Will fail for any other wrapper other than 'RObjectUPtr<>'.
95+
const auto& srcRUptr = std::any_cast<const RObjectUPtr<std::string_view>&>(pSrc);
96+
return std::any(_toType(*srcRUptr.get()));
97+
}
98+
// GCOVR_EXCL_STOP
99+
else {
100+
const auto& srcObj = (isPtr ? *std::any_cast<const std::string_view*>(pSrc) : std::any_cast<const std::string_view&>(pSrc));
101+
return std::any(_toType(srcObj));
102+
}
103+
}
104+
// GCOVR_EXCL_START
105+
catch (const std::exception&) {
106+
pNewEntityKind = EntityKind::None;
107+
return std::any();
108+
}
109+
// GCOVR_EXCL_STOP
58110
};
59111
conversions().emplace_back(std::pair(traits::uid<_toType>::value, conversion));
60112
}

0 commit comments

Comments
 (0)