Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ comment:

ignore:
- "demo/**"
- "RTLBenchmarkApp/**"
- "RTLBenchmarkApp/**"
- "ReflectionTemplateLib/rtl/detail/src/RObjectConverters_string.cpp"
File renamed without changes.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,12 +170,12 @@ RTL provides the following callable entities, designed to be as lightweight and

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

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).
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).

### How to Build (Windows / Linux)
```sh
mkdir build && cd build
cmake -G "<Generator>" # Use a C++20-compatible compiler
cmake ../ -G "<Generator>" # Use a C++20-compatible compiler
cmake --build .
```
Run the generated binaries from `bin/`:
Expand Down
74 changes: 37 additions & 37 deletions RTLTestRunApp/src/RObjectTests/RObjectReflecting_strings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -337,43 +337,43 @@ namespace unit_test
// Create an RObject that reflects a string value (init with 'std::string').
RObject robj = rtl::reflect(STR_STD_STRING);

// Check if the value can be accessed as 'std::string'.
ASSERT_TRUE(robj.canViewAs<std::string>());

// Try to obtain a view as 'std::string' and verify it is present.
auto view0 = robj.view<std::string>();
ASSERT_TRUE(view0.has_value());

// Validate the string content matches the original input.
const std::string& str_cref0 = view0->get();
ASSERT_EQ(str_cref0, STR_STD_STRING);

auto [err, robjcp] = robj.clone<rtl::alloc::Heap>();
EXPECT_EQ(err, rtl::error::None);
EXPECT_EQ(robj.getTypeId(), robjcp.getTypeId());

// Check if the value can be accessed as 'std::string'.
ASSERT_TRUE(robj.canViewAs<std::string>());

// Try to obtain a view as 'std::string' and verify it is present.
auto view1 = robj.view<std::string>();
ASSERT_TRUE(view1.has_value());

// Validate the string content matches the original input.
const std::string& str_cref1 = view1->get();
ASSERT_EQ(str_cref1, STR_STD_STRING);
ASSERT_TRUE(robjcp.canViewAs<char>());
ASSERT_TRUE(robjcp.canViewAs<std::string>());

//TODO: Fix the crash here.

// Try to obtain a view as 'const char*' and verify it is present.
//auto view2 = robjcp.view<char>();
//ASSERT_TRUE(view2.has_value());

//// Validate the base address are different, since RObject is reflecting a copy.
//const char& str_addr = view2->get();
//ASSERT_NE(&str_addr, STR_STD_STRING.c_str());
EXPECT_TRUE(robj.canViewAs<std::string>());
EXPECT_TRUE(robj.canViewAs<char>());

auto testWithAlloc = [&]<typename rtl::alloc alloc_t>()
{
auto [err, robjcp] = robj.clone<alloc_t>();

EXPECT_EQ(err, rtl::error::None);
EXPECT_EQ(robj.getTypeId(), robjcp.getTypeId());
{
// Check if the value can be accessed as 'std::string'.
ASSERT_TRUE(robjcp.template canViewAs<std::string>());

// Try to obtain a view as 'std::string' and verify it is present.
auto view = robjcp.template view<std::string>();
ASSERT_TRUE(view.has_value());

// Validate the string content matches the original input.
const std::string& str_cref = view->get();
ASSERT_EQ(str_cref, STR_STD_STRING);
} {
ASSERT_TRUE(robjcp.template canViewAs<char>());

// Try to obtain a view as 'const char*' and verify it is present.
auto view = robjcp.template view<char>();
ASSERT_TRUE(view.has_value());

// Validate the base address are different, since RObject is reflecting a copy.
const char& str_addr = view->get();
ASSERT_NE(&str_addr, STR_STD_STRING.c_str());
}
};

// Should even std::string to 'char' conversion be allowed implicitly?
// Need to re-think it. The implicit conversions are not used in core dispatch yet.
testWithAlloc.operator()<rtl::alloc::Stack>();
testWithAlloc.operator()<rtl::alloc::Heap>();
}


Expand Down
76 changes: 64 additions & 12 deletions ReflectionTemplateLib/rtl/detail/src/RObjectConverters_string.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include <rtl/rtl_typeid.h>
#include <detail/inc/ReflectCast.hpp>
#include <detail/inc/RObjectUPtr.h>

namespace rtl::detail
{
Expand All @@ -20,10 +21,27 @@ namespace rtl::detail
{
const auto& conversion = [](const std::any& pSrc, const EntityKind& pSrcEntityKind, EntityKind& pNewEntityKind)-> std::any
{
pNewEntityKind = EntityKind::Ptr;
const auto& isPtr = (pSrcEntityKind == EntityKind::Ptr);
const auto& srcObj = (isPtr ? *std::any_cast<const std::string*>(pSrc) : std::any_cast<const std::string&>(pSrc));
return std::any(srcObj.c_str());
try {
pNewEntityKind = EntityKind::Ptr;
const auto& isPtr = (pSrcEntityKind == EntityKind::Ptr);
// GCOVR_EXCL_START
if (pSrcEntityKind == EntityKind::Wrapper) {
//TODO: Will fail for any other wrapper other than 'RObjectUPtr<>'.
const auto& srcRUptr = std::any_cast<const RObjectUPtr<std::string>&>(pSrc);
return std::any(srcRUptr.get()->c_str());
}
// GCOVR_EXCL_STOP
else {
const auto& srcObj = (isPtr ? *std::any_cast<const std::string*>(pSrc) : std::any_cast<const std::string&>(pSrc));
return std::any(srcObj.c_str());
}
}
// GCOVR_EXCL_START
catch (const std::exception&) {
pNewEntityKind = EntityKind::None;
return std::any();
}
// GCOVR_EXCL_STOP
};
conversions().emplace_back(std::pair(traits::uid<char>::value, conversion));
}
Expand All @@ -35,10 +53,27 @@ namespace rtl::detail
{
const auto& conversion = [](const std::any& pSrc, const EntityKind& pSrcEntityKind, EntityKind& pNewEntityKind)-> std::any
{
pNewEntityKind = EntityKind::Ptr;
const auto& isPtr = (pSrcEntityKind == EntityKind::Ptr);
const auto& srcObj = (isPtr ? *std::any_cast<const std::string_view*>(pSrc) : std::any_cast<const std::string_view&>(pSrc));
return std::any(srcObj.data());
try {
pNewEntityKind = EntityKind::Ptr;
const auto& isPtr = (pSrcEntityKind == EntityKind::Ptr);
// GCOVR_EXCL_START
if (pSrcEntityKind == EntityKind::Wrapper) {
//TODO: Will fail for any other wrapper other than 'RObjectUPtr<>'.
const auto& srcRUptr = std::any_cast<const RObjectUPtr<std::string>&>(pSrc);
return std::any(srcRUptr.get()->data());
}
// GCOVR_EXCL_STOP
else {
const auto& srcObj = (isPtr ? *std::any_cast<const std::string_view*>(pSrc) : std::any_cast<const std::string_view&>(pSrc));
return std::any(srcObj.data());
}
}
// GCOVR_EXCL_START
catch (const std::exception&) {
pNewEntityKind = EntityKind::None;
return std::any();
}
// GCOVR_EXCL_STOP
};
conversions().emplace_back(std::pair(traits::uid<char>::value, conversion));
}
Expand All @@ -51,10 +86,27 @@ namespace rtl::detail
using _toType = std::string;
const auto& conversion = [](const std::any& pSrc, const EntityKind& pSrcEntityKind, EntityKind& pNewEntityKind)-> std::any
{
pNewEntityKind = EntityKind::Value;
const auto& isPtr = (pSrcEntityKind == EntityKind::Ptr);
const auto& srcObj = (isPtr ? *std::any_cast<const std::string_view*>(pSrc) : std::any_cast<const std::string_view&>(pSrc));
return std::any(_toType(srcObj));
try {
pNewEntityKind = EntityKind::Value;
const auto& isPtr = (pSrcEntityKind == EntityKind::Ptr);
// GCOVR_EXCL_START
if (pSrcEntityKind == EntityKind::Wrapper) {
//TODO: Will fail for any other wrapper other than 'RObjectUPtr<>'.
const auto& srcRUptr = std::any_cast<const RObjectUPtr<std::string_view>&>(pSrc);
return std::any(_toType(*srcRUptr.get()));
}
// GCOVR_EXCL_STOP
else {
const auto& srcObj = (isPtr ? *std::any_cast<const std::string_view*>(pSrc) : std::any_cast<const std::string_view&>(pSrc));
return std::any(_toType(srcObj));
}
}
// GCOVR_EXCL_START
catch (const std::exception&) {
pNewEntityKind = EntityKind::None;
return std::any();
}
// GCOVR_EXCL_STOP
};
conversions().emplace_back(std::pair(traits::uid<_toType>::value, conversion));
}
Expand Down