Skip to content

Commit

Permalink
AnariAny suppor for string_list
Browse files Browse the repository at this point in the history
  • Loading branch information
tarcila committed Nov 18, 2024
1 parent ac61b5b commit 1834a5d
Show file tree
Hide file tree
Showing 3 changed files with 179 additions and 7 deletions.
3 changes: 3 additions & 0 deletions src/anari/include/anari/anari_cpp/Traits.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ ANARI_TYPEFOR_SPECIALIZATION_STRING(char[], ANARI_STRING);
ANARI_TYPEFOR_SPECIALIZATION_STRING(const char *, ANARI_STRING);
ANARI_TYPEFOR_SPECIALIZATION_STRING(const char[], ANARI_STRING);

ANARI_TYPEFOR_SPECIALIZATION(char*[], ANARI_STRING_LIST);
ANARI_TYPEFOR_SPECIALIZATION(char**, ANARI_STRING_LIST);

ANARI_TYPEFOR_SPECIALIZATION(bool, ANARI_BOOL);

ANARI_TYPEFOR_SPECIALIZATION(int8_t, ANARI_INT8);
Expand Down
81 changes: 74 additions & 7 deletions src/helium/utility/AnariAny.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@
// anari
#include <anari/anari_cpp.hpp>
// std
#include <algorithm>
#include <array>
#include <cstdint>
#include <cstring>
#include <string>
#include <vector>

namespace helium {

Expand Down Expand Up @@ -58,6 +59,10 @@ struct AnariAny
void reserveString(size_t size);
void resizeString(size_t size);

std::vector<std::string> getStringList() const;
void reserveStringList(size_t size);
void resizeStringList(size_t size);

template <typename T>
bool is() const;

Expand All @@ -83,6 +88,8 @@ struct AnariAny

std::array<uint8_t, MAX_LOCAL_STORAGE> m_storage;
std::string m_string;
std::vector<std::string> m_stringList;
mutable std::vector<const char*> m_stringListPtrs;
ANARIDataType m_type{ANARI_UNKNOWN};
};

Expand All @@ -97,6 +104,7 @@ inline AnariAny::AnariAny(const AnariAny &copy)
{
std::memcpy(m_storage.data(), copy.m_storage.data(), m_storage.size());
m_string = copy.m_string;
m_stringList = copy.m_stringList;
m_type = copy.m_type;
refIncObject();
}
Expand All @@ -105,6 +113,8 @@ inline AnariAny::AnariAny(AnariAny &&tmp)
{
std::memcpy(m_storage.data(), tmp.m_storage.data(), m_storage.size());
m_string = std::move(tmp.m_string);
m_stringList = std::move(tmp.m_stringList);
m_stringListPtrs = std::move(tmp.m_stringListPtrs);
m_type = tmp.m_type;
tmp.m_type = ANARI_UNKNOWN;
}
Expand All @@ -118,7 +128,21 @@ inline AnariAny::AnariAny(T value) : AnariAny()

if constexpr (type == ANARI_STRING)
m_string = value;
else
else if constexpr (type == ANARI_STRING_LIST) {
if constexpr (std::is_same_v<T, std::vector<std::string>>) {
m_stringList = value;
m_stringListPtrs.clear();
} else if constexpr (std::is_same_v<T, const char**>) {
m_stringList.clear();
m_stringListPtrs.clear();
if (value) {
while (*value)
m_stringList.push_back(*value++);
}
} else
static_assert(false, "AnariAny string list can only be built from const char**, const char*[] and vector<string>.");

} else
std::memcpy(m_storage.data(), &value, sizeof(value));

m_type = type;
Expand All @@ -138,7 +162,12 @@ inline AnariAny::AnariAny(ANARIDataType type, const void *v) : AnariAny()
if (v != nullptr) {
if (type == ANARI_STRING)
m_string = (const char *)v;
else if (type == ANARI_VOID_POINTER)
else if (type == ANARI_STRING_LIST) {
const char** stringPtr = (const char**)v;
m_stringList.clear();
m_stringListPtrs.clear();
while (stringPtr && *stringPtr) m_stringList.push_back(*stringPtr++);
} else if (type == ANARI_VOID_POINTER)
std::memcpy(m_storage.data(), &v, anari::sizeOf(type));
else
std::memcpy(m_storage.data(), v, anari::sizeOf(type));
Expand All @@ -156,6 +185,8 @@ inline AnariAny &AnariAny::operator=(const AnariAny &rhs)
reset();
std::memcpy(m_storage.data(), rhs.m_storage.data(), m_storage.size());
m_string = rhs.m_string;
m_stringList = rhs.m_stringList;
m_stringListPtrs.clear();
m_type = rhs.m_type;
refIncObject();
return *this;
Expand All @@ -166,6 +197,8 @@ inline AnariAny &AnariAny::operator=(AnariAny &&rhs)
reset();
std::memcpy(m_storage.data(), rhs.m_storage.data(), m_storage.size());
m_string = std::move(rhs.m_string);
m_stringList = std::move(rhs.m_stringList);
m_stringListPtrs = std::move(rhs.m_stringListPtrs);
m_type = rhs.m_type;
rhs.m_type = ANARI_UNKNOWN;
return *this;
Expand All @@ -185,6 +218,8 @@ inline T AnariAny::get() const
!anari::isObject(type), "use AnariAny::getObject() for getting objects");
static_assert(
type != ANARI_STRING, "use AnariAny::getString() for getting strings");
static_assert(
type != ANARI_STRING_LIST, "use AnaryAny::getStringList() for getting string lists");

if (!valid())
throw std::runtime_error("get() called on empty visrtx::AnariAny");
Expand All @@ -211,14 +246,27 @@ inline bool AnariAny::get() const

inline const void *AnariAny::data() const
{
return type() == ANARI_STRING ? (const void *)m_string.data()
: (const void *)m_storage.data();
switch (type()) {
case ANARI_STRING:
return m_string.data();
case ANARI_STRING_LIST: {
if (m_stringListPtrs.empty()) {
m_stringListPtrs.reserve(m_stringList.size() + 1);
for (const auto& s : m_stringList)
m_stringListPtrs.push_back(s.c_str());
m_stringListPtrs.push_back(nullptr);
}
return m_stringListPtrs.data();
}
default:
return m_storage.data();
}
}

inline void *AnariAny::data()
{
return type() == ANARI_STRING ? (void *)m_string.data()
: (void *)m_storage.data();
return const_cast<void*>(
const_cast<const AnariAny*>(this)->data());
}

template <typename T>
Expand Down Expand Up @@ -267,6 +315,8 @@ inline void AnariAny::reset()
refDecObject();
std::fill(m_storage.begin(), m_storage.end(), 0);
m_string.clear();
m_stringList.clear();
m_stringListPtrs.clear();
m_type = ANARI_UNKNOWN;
}

Expand All @@ -280,6 +330,8 @@ inline bool AnariAny::operator==(const AnariAny &rhs) const
return get<bool>() == rhs.get<bool>();
else if (type() == ANARI_STRING)
return m_string == rhs.m_string;
else if (type() == ANARI_STRING_LIST)
return m_stringList == rhs.m_stringList;
else {
return std::equal(m_storage.data(),
m_storage.data() + ::anari::sizeOf(type()),
Expand Down Expand Up @@ -316,6 +368,21 @@ inline void AnariAny::resizeString(size_t size)
m_string.resize(size);
}

inline std::vector<std::string> AnariAny::getStringList() const
{
return type() == ANARI_STRING_LIST ? m_stringList : std::vector<std::string>{};
}

inline void AnariAny::reserveStringList(size_t size) {
m_stringList.reserve(size);
}

inline void AnariAny::resizeStringList(size_t size) {
m_stringListPtrs.clear();
m_stringList.resize(size);
}


inline void AnariAny::refIncObject() const
{
if (anari::isObject(type())) {
Expand Down
102 changes: 102 additions & 0 deletions tests/unit/test_helium_AnariAny.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,25 @@ inline void verify_value(const AnariAny &v, const char *correctValue)
REQUIRE(v.getString() == correctValue);
}

template<>
inline void verify_value(const AnariAny &v, const char **correctValue)
{
REQUIRE(v.valid());
REQUIRE(v.type() == ANARI_STRING_LIST);
auto stringList = v.getStringList();
REQUIRE(
stringList.empty() == (correctValue == nullptr || *correctValue == nullptr)
);

auto it = stringList.cbegin();
while (it != stringList.cend() && *correctValue) {
REQUIRE(*it == *correctValue);
++it;
++correctValue;
}
REQUIRE((it == stringList.cend() && *correctValue == nullptr));
}

template <typename T>
inline void test_interface(T testValue, T testValue2)
{
Expand Down Expand Up @@ -172,6 +191,74 @@ inline void test_interface(const char *testValue, const char *testValue2)
}
}

template <>
inline void test_interface(const char **testValue, const char **testValue2)
{
AnariAny v;
REQUIRE(!v.valid());

SECTION("Can make valid by C++ construction")
{
AnariAny v2(testValue);
verify_value(v2, testValue);
}

SECTION("Can make valid by C construction")
{
AnariAny v2(ANARI_STRING_LIST, testValue);
verify_value(v2, testValue);
}

SECTION("Can make valid by calling operator=()")
{
v = testValue;
verify_value(v, testValue);
}

SECTION("Can make valid by copy construction")
{
v = testValue;
AnariAny v2(v);
verify_value(v2, testValue);
}

SECTION("Two objects with same value are equal if constructed the same")
{
v = testValue;
AnariAny v2 = testValue;
REQUIRE(v.type() == v2.type());
REQUIRE(v == v2);
}

SECTION("Two objects with same value are equal if assigned from another")
{
v = testValue;
AnariAny v2 = testValue2;
v = v2;
REQUIRE(v == v2);
}

SECTION("Two objects with different values are not equal")
{
v = testValue;
AnariAny v2 = testValue2;
REQUIRE(v != v2);
}

SECTION("Get raw data from matches the input data")
{
v = testValue;
const char** anyValue = reinterpret_cast<const char**>(v.data());
REQUIRE(anyValue != nullptr);
while (*testValue && *anyValue) {
REQUIRE(strcmp(*testValue++, *anyValue++) == 0);
}
REQUIRE(*testValue == nullptr);
REQUIRE(*anyValue == nullptr);
}
}


// Value Tests ////////////////////////////////////////////////////////////////

TEST_CASE("helium::AnariAny 'int' type behavior", "[helium_AnariAny]")
Expand All @@ -194,6 +281,21 @@ TEST_CASE("helium::AnariAny 'string' type behavior", "[helium_AnariAny]")
test_interface<const char *>("test1", "test2");
}

TEST_CASE("helium::AnariAny 'stringList' type behavior", "[helium_AnariAny]")
{
const char* test1[] = {
"a",
"b",
"c",
nullptr,
};
const char* test2[] = {
"d",
"e",
nullptr,
};
test_interface<const char**>(test1, test2);
}
// Object Tests ///////////////////////////////////////////////////////////////

SCENARIO("helium::AnariAny object behavior", "[helium_AnariAny]")
Expand Down

0 comments on commit 1834a5d

Please sign in to comment.