mirror of
https://github.com/lighttransport/tinyusdz.git
synced 2026-01-18 01:11:17 +01:00
Use tinyusdz-customized linb::any.
This commit is contained in:
@@ -277,3 +277,4 @@ TinyUSDZ is licensed under MIT license.
|
||||
* formatxx: unlicense. https://github.com/seanmiddleditch/formatxx
|
||||
* mapbox/variant: BSD-3 or BSL-1.0 license. https://github.com/mapbox/variant
|
||||
* ubench.h: Unlicense. https://github.com/sheredom/ubench.h
|
||||
* thelink2012/any : BSL-1.0 license. https://github.com/thelink2012/any
|
||||
|
||||
@@ -9,16 +9,36 @@ UBENCH(perf, vector_double_push_back_10M)
|
||||
constexpr size_t niter = 10 * 10000;
|
||||
for (size_t i = 0; i < niter; i++) {
|
||||
v.push_back(double(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UBENCH(perf, any_value_double_10M)
|
||||
{
|
||||
constexpr size_t niter = 10 * 10000;
|
||||
for (size_t i = 0; i < niter; i++) {
|
||||
tinyusdz::value::any_value a;
|
||||
linb::any a;
|
||||
a = double(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UBENCH(perf, thelink2012_any_float_10M)
|
||||
{
|
||||
constexpr size_t niter = 10 * 10000;
|
||||
for (size_t i = 0; i < niter; i++) {
|
||||
linb::any a;
|
||||
a = float(i);
|
||||
}
|
||||
}
|
||||
|
||||
UBENCH(perf, thelink2012_any_double_10M)
|
||||
{
|
||||
constexpr size_t niter = 10 * 10000;
|
||||
|
||||
std::vector<linb::any> v;
|
||||
|
||||
for (size_t i = 0; i < niter; i++) {
|
||||
v.push_back(double(i));
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
@@ -28,7 +48,7 @@ UBENCH(perf, any_value_100M)
|
||||
for (size_t i = 0; i < niter; i++) {
|
||||
tinyusdz::value::any_value a;
|
||||
a = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -41,7 +61,7 @@ UBENCH(perf, timesamples_double_10M)
|
||||
for (size_t i = 0; i < ns; i++) {
|
||||
ts.times.push_back(double(i));
|
||||
ts.values.push_back(double(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//int main(int argc, char **argv)
|
||||
|
||||
@@ -438,8 +438,9 @@ class CrateValue {
|
||||
// Undefined behavior(usually will triger segmentation fault) when
|
||||
// type-mismatch. (We don't throw exception)
|
||||
template <class T>
|
||||
const T &value() const {
|
||||
return (*reinterpret_cast<const T *>(value_.value()));
|
||||
const T value() const {
|
||||
//return (*reinterpret_cast<const T *>(value_.value()));
|
||||
return linb::any_cast<const T>(value_);
|
||||
}
|
||||
|
||||
// Type-safe way to get concrete value.
|
||||
@@ -456,7 +457,8 @@ class CrateValue {
|
||||
}
|
||||
|
||||
private:
|
||||
value::any_value value_;
|
||||
// TODO: Use value::Value?
|
||||
linb::any value_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -84,11 +84,20 @@ struct PrimVar {
|
||||
}
|
||||
|
||||
if (value::TypeTrait<T>::type_id == var.values[0].type_id()) {
|
||||
return std::move(*reinterpret_cast<const T *>(var.values[0].value()));
|
||||
//return std::move(*reinterpret_cast<const T *>(var.values[0].value()));
|
||||
auto pv = linb::any_cast<const T>(&var.values[0]);
|
||||
if (pv) {
|
||||
return (*pv);
|
||||
}
|
||||
return nonstd::nullopt;
|
||||
} else if (value::TypeTrait<T>::underlying_type_id == var.values[0].underlying_type_id()) {
|
||||
// `roll` type. Can be able to cast to underlying type since the memory
|
||||
// layout does not change.
|
||||
return *reinterpret_cast<const T *>(var.values[0].value());
|
||||
//return *reinterpret_cast<const T *>(var.values[0].value());
|
||||
if (auto pv = linb::any_cast<const T>(&var.values[0])) {
|
||||
return (*pv);
|
||||
}
|
||||
return nonstd::nullopt;
|
||||
}
|
||||
return nonstd::nullopt;
|
||||
}
|
||||
|
||||
618
src/tiny-any.inc
Normal file
618
src/tiny-any.inc
Normal file
@@ -0,0 +1,618 @@
|
||||
//
|
||||
// Implementation of N4562 std::experimental::any (merged into C++17) for C++11 compilers.
|
||||
//
|
||||
// See also:
|
||||
// + http://en.cppreference.com/w/cpp/any
|
||||
// + http://en.cppreference.com/w/cpp/experimental/any
|
||||
// + http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4562.html#any
|
||||
// + https://cplusplus.github.io/LWG/lwg-active.html#2509
|
||||
//
|
||||
//
|
||||
// Copyright (c) 2016 Denilson das Mercês Amorim
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// TinyUSDZ modification
|
||||
// - Disable exceptions, RTTI
|
||||
// - Use type_id with TypeTrait<T>::type_id
|
||||
// - Use type_name with TypeTrait<T>::type_name
|
||||
// - Assume this tiny-any.inc is included inside value-type.hh (since TypeTrait<T> implementations are required)
|
||||
//
|
||||
#ifndef LINB_ANY_HPP
|
||||
#define LINB_ANY_HPP
|
||||
#pragma once
|
||||
|
||||
//#include <typeinfo>
|
||||
#include <type_traits>
|
||||
//#include <stdexcept>
|
||||
#include <utility>
|
||||
#include <cstdint>
|
||||
|
||||
#if 0
|
||||
//#include "value-type.hh"
|
||||
|
||||
namespace tinyusdz {
|
||||
namespace value {
|
||||
|
||||
// Forward decl.
|
||||
template<typename dtype>
|
||||
class TypeTrait;
|
||||
|
||||
} // namespace value
|
||||
} // namespace tinyusdz
|
||||
#endif
|
||||
|
||||
#ifndef ANY_IMPL_NO_EXCEPTIONS
|
||||
#define ANY_IMPL_NO_EXCEPTIONS
|
||||
#endif
|
||||
|
||||
#ifndef ANY_IMPL_NO_RTTI
|
||||
#define ANY_IMPL_NO_RTTI
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(PARTICLE)
|
||||
#if !defined(__cpp_exceptions) && !defined(ANY_IMPL_NO_EXCEPTIONS) && !defined(ANY_IMPL_EXCEPTIONS)
|
||||
# define ANY_IMPL_NO_EXCEPTIONS
|
||||
# endif
|
||||
#else
|
||||
// you can opt-out of exceptions by definining ANY_IMPL_NO_EXCEPTIONS,
|
||||
// but you must ensure not to cast badly when passing an `any' object to any_cast<T>(any)
|
||||
#endif
|
||||
|
||||
#if defined(PARTICLE)
|
||||
#if !defined(__cpp_rtti) && !defined(ANY_IMPL_NO_RTTI) && !defined(ANY_IMPL_RTTI)
|
||||
# define ANY_IMPL_NO_RTTI
|
||||
# endif
|
||||
#else
|
||||
// you can opt-out of RTTI by defining ANY_IMPL_NO_RTTI,
|
||||
// in order to disable functions working with the typeid of a type
|
||||
#endif
|
||||
|
||||
|
||||
namespace linb
|
||||
{
|
||||
|
||||
|
||||
#ifndef ANY_IMPL_NO_EXCEPTIONS
|
||||
class bad_any_cast : public std::bad_cast
|
||||
{
|
||||
public:
|
||||
const char* what() const noexcept override
|
||||
{
|
||||
return "bad any cast";
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
class any final
|
||||
{
|
||||
public:
|
||||
/// Constructs an object of type any with an empty state.
|
||||
any() :
|
||||
vtable(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
/// Constructs an object of type any with an equivalent state as other.
|
||||
any(const any& rhs) :
|
||||
vtable(rhs.vtable)
|
||||
{
|
||||
if(!rhs.empty())
|
||||
{
|
||||
rhs.vtable->copy(rhs.storage, this->storage);
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs an object of type any with a state equivalent to the original state of other.
|
||||
/// rhs is left in a valid but otherwise unspecified state.
|
||||
any(any&& rhs) noexcept :
|
||||
vtable(rhs.vtable)
|
||||
{
|
||||
if(!rhs.empty())
|
||||
{
|
||||
rhs.vtable->move(rhs.storage, this->storage);
|
||||
rhs.vtable = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/// Same effect as this->clear().
|
||||
~any()
|
||||
{
|
||||
this->clear();
|
||||
}
|
||||
|
||||
/// Constructs an object of type any that contains an object of type T direct-initialized with std::forward<ValueType>(value).
|
||||
///
|
||||
/// T shall satisfy the CopyConstructible requirements, otherwise the program is ill-formed.
|
||||
/// This is because an `any` may be copy constructed into another `any` at any time, so a copy should always be allowed.
|
||||
template<typename ValueType, typename = typename std::enable_if<!std::is_same<typename std::decay<ValueType>::type, any>::value>::type>
|
||||
any(ValueType&& value)
|
||||
{
|
||||
static_assert(std::is_copy_constructible<typename std::decay<ValueType>::type>::value,
|
||||
"T shall satisfy the CopyConstructible requirements.");
|
||||
this->construct(std::forward<ValueType>(value));
|
||||
}
|
||||
|
||||
/// Has the same effect as any(rhs).swap(*this). No effects if an exception is thrown.
|
||||
any& operator=(const any& rhs)
|
||||
{
|
||||
any(rhs).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Has the same effect as any(std::move(rhs)).swap(*this).
|
||||
///
|
||||
/// The state of *this is equivalent to the original state of rhs and rhs is left in a valid
|
||||
/// but otherwise unspecified state.
|
||||
any& operator=(any&& rhs) noexcept
|
||||
{
|
||||
any(std::move(rhs)).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Has the same effect as any(std::forward<ValueType>(value)).swap(*this). No effect if a exception is thrown.
|
||||
///
|
||||
/// T shall satisfy the CopyConstructible requirements, otherwise the program is ill-formed.
|
||||
/// This is because an `any` may be copy constructed into another `any` at any time, so a copy should always be allowed.
|
||||
template<typename ValueType, typename = typename std::enable_if<!std::is_same<typename std::decay<ValueType>::type, any>::value>::type>
|
||||
any& operator=(ValueType&& value)
|
||||
{
|
||||
static_assert(std::is_copy_constructible<typename std::decay<ValueType>::type>::value,
|
||||
"T shall satisfy the CopyConstructible requirements.");
|
||||
any(std::forward<ValueType>(value)).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// If not empty, destroys the contained object.
|
||||
void clear() noexcept
|
||||
{
|
||||
if(!empty())
|
||||
{
|
||||
this->vtable->destroy(storage);
|
||||
this->vtable = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if *this has no contained object, otherwise false.
|
||||
bool empty() const noexcept
|
||||
{
|
||||
return this->vtable == nullptr;
|
||||
}
|
||||
|
||||
#ifndef ANY_IMPL_NO_RTTI
|
||||
/// If *this has a contained object of type T, typeid(T); otherwise typeid(void).
|
||||
const std::type_info& type() const noexcept
|
||||
{
|
||||
return empty()? typeid(void) : this->vtable->type();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 1 // tinyusdz
|
||||
uint32_t type_id() const noexcept
|
||||
{
|
||||
return empty()? tinyusdz::value::TypeTrait<void>::type_id : this->vtable->type_id();
|
||||
}
|
||||
|
||||
uint32_t underlying_type_id() const noexcept
|
||||
{
|
||||
return empty()? tinyusdz::value::TypeTrait<void>::underlying_type_id : this->vtable->underlying_type_id();
|
||||
}
|
||||
|
||||
const std::string type_name() const noexcept
|
||||
{
|
||||
return empty()? tinyusdz::value::TypeTrait<void>::type_name() : this->vtable->type_name();
|
||||
}
|
||||
|
||||
const std::string underlying_type_name() const noexcept
|
||||
{
|
||||
return empty()? tinyusdz::value::TypeTrait<void>::underlying_type_name() : this->vtable->underlying_type_name();
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Exchange the states of *this and rhs.
|
||||
void swap(any& rhs) noexcept
|
||||
{
|
||||
if(this->vtable != rhs.vtable)
|
||||
{
|
||||
any tmp(std::move(rhs));
|
||||
|
||||
// move from *this to rhs.
|
||||
rhs.vtable = this->vtable;
|
||||
if(this->vtable != nullptr)
|
||||
{
|
||||
this->vtable->move(this->storage, rhs.storage);
|
||||
//this->vtable = nullptr; -- unneeded, see below
|
||||
}
|
||||
|
||||
// move from tmp (previously rhs) to *this.
|
||||
this->vtable = tmp.vtable;
|
||||
if(tmp.vtable != nullptr)
|
||||
{
|
||||
tmp.vtable->move(tmp.storage, this->storage);
|
||||
tmp.vtable = nullptr;
|
||||
}
|
||||
}
|
||||
else // same types
|
||||
{
|
||||
if(this->vtable != nullptr)
|
||||
this->vtable->swap(this->storage, rhs.storage);
|
||||
}
|
||||
}
|
||||
|
||||
private: // Storage and Virtual Method Table
|
||||
|
||||
union storage_union
|
||||
{
|
||||
using stack_storage_t = typename std::aligned_storage<2 * sizeof(void*), std::alignment_of<void*>::value>::type;
|
||||
|
||||
void* dynamic;
|
||||
stack_storage_t stack; // 2 words for e.g. shared_ptr
|
||||
};
|
||||
|
||||
/// Base VTable specification.
|
||||
struct vtable_type
|
||||
{
|
||||
// Note: The caller is responssible for doing .vtable = nullptr after destructful operations
|
||||
// such as destroy() and/or move().
|
||||
|
||||
#ifndef ANY_IMPL_NO_RTTI
|
||||
/// The type of the object this vtable is for.
|
||||
const std::type_info& (*type)() noexcept;
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
uint32_t (*type_id)() noexcept;
|
||||
uint32_t (*underlying_type_id)() noexcept;
|
||||
const std::string (*type_name)() noexcept;
|
||||
const std::string (*underlying_type_name)() noexcept;
|
||||
#endif
|
||||
|
||||
/// Destroys the object in the union.
|
||||
/// The state of the union after this call is unspecified, caller must ensure not to use src anymore.
|
||||
void(*destroy)(storage_union&) noexcept;
|
||||
|
||||
/// Copies the **inner** content of the src union into the yet unitialized dest union.
|
||||
/// As such, both inner objects will have the same state, but on separate memory locations.
|
||||
void(*copy)(const storage_union& src, storage_union& dest);
|
||||
|
||||
/// Moves the storage from src to the yet unitialized dest union.
|
||||
/// The state of src after this call is unspecified, caller must ensure not to use src anymore.
|
||||
void(*move)(storage_union& src, storage_union& dest) noexcept;
|
||||
|
||||
/// Exchanges the storage between lhs and rhs.
|
||||
void(*swap)(storage_union& lhs, storage_union& rhs) noexcept;
|
||||
};
|
||||
|
||||
/// VTable for dynamically allocated storage.
|
||||
template<typename T>
|
||||
struct vtable_dynamic
|
||||
{
|
||||
#ifndef ANY_IMPL_NO_RTTI
|
||||
static const std::type_info& type() noexcept
|
||||
{
|
||||
return typeid(T);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 1 // tinyusdz
|
||||
static uint32_t type_id() noexcept
|
||||
{
|
||||
return tinyusdz::value::TypeTrait<T>::type_id;
|
||||
}
|
||||
|
||||
static uint32_t underlying_type_id() noexcept
|
||||
{
|
||||
return tinyusdz::value::TypeTrait<T>::underlying_type_id;
|
||||
}
|
||||
|
||||
static const std::string type_name() noexcept
|
||||
{
|
||||
return tinyusdz::value::TypeTrait<T>::type_name();
|
||||
}
|
||||
|
||||
static const std::string underlying_type_name() noexcept
|
||||
{
|
||||
return tinyusdz::value::TypeTrait<T>::underlying_type_name();
|
||||
}
|
||||
#endif
|
||||
|
||||
static void destroy(storage_union& storage) noexcept
|
||||
{
|
||||
//assert(reinterpret_cast<T*>(storage.dynamic));
|
||||
delete reinterpret_cast<T*>(storage.dynamic);
|
||||
}
|
||||
|
||||
static void copy(const storage_union& src, storage_union& dest)
|
||||
{
|
||||
dest.dynamic = new T(*reinterpret_cast<const T*>(src.dynamic));
|
||||
}
|
||||
|
||||
static void move(storage_union& src, storage_union& dest) noexcept
|
||||
{
|
||||
dest.dynamic = src.dynamic;
|
||||
src.dynamic = nullptr;
|
||||
}
|
||||
|
||||
static void swap(storage_union& lhs, storage_union& rhs) noexcept
|
||||
{
|
||||
// just exchage the storage pointers.
|
||||
std::swap(lhs.dynamic, rhs.dynamic);
|
||||
}
|
||||
};
|
||||
|
||||
/// VTable for stack allocated storage.
|
||||
template<typename T>
|
||||
struct vtable_stack
|
||||
{
|
||||
#ifndef ANY_IMPL_NO_RTTI
|
||||
static const std::type_info& type() noexcept
|
||||
{
|
||||
return typeid(T);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 1 // tinyusdz
|
||||
static uint32_t type_id() noexcept
|
||||
{
|
||||
return tinyusdz::value::TypeTrait<T>::type_id;
|
||||
}
|
||||
|
||||
static uint32_t underlying_type_id() noexcept
|
||||
{
|
||||
return tinyusdz::value::TypeTrait<T>::underlying_type_id;
|
||||
}
|
||||
|
||||
static const std::string type_name() noexcept
|
||||
{
|
||||
return tinyusdz::value::TypeTrait<T>::type_name();
|
||||
}
|
||||
|
||||
static const std::string underlying_type_name() noexcept
|
||||
{
|
||||
return tinyusdz::value::TypeTrait<T>::underlying_type_name();
|
||||
}
|
||||
#endif
|
||||
|
||||
static void destroy(storage_union& storage) noexcept
|
||||
{
|
||||
reinterpret_cast<T*>(&storage.stack)->~T();
|
||||
}
|
||||
|
||||
static void copy(const storage_union& src, storage_union& dest)
|
||||
{
|
||||
new (&dest.stack) T(reinterpret_cast<const T&>(src.stack));
|
||||
}
|
||||
|
||||
static void move(storage_union& src, storage_union& dest) noexcept
|
||||
{
|
||||
// one of the conditions for using vtable_stack is a nothrow move constructor,
|
||||
// so this move constructor will never throw a exception.
|
||||
new (&dest.stack) T(std::move(reinterpret_cast<T&>(src.stack)));
|
||||
destroy(src);
|
||||
}
|
||||
|
||||
static void swap(storage_union& lhs, storage_union& rhs) noexcept
|
||||
{
|
||||
storage_union tmp_storage;
|
||||
move(rhs, tmp_storage);
|
||||
move(lhs, rhs);
|
||||
move(tmp_storage, lhs);
|
||||
}
|
||||
};
|
||||
|
||||
/// Whether the type T must be dynamically allocated or can be stored on the stack.
|
||||
template<typename T>
|
||||
struct requires_allocation :
|
||||
std::integral_constant<bool,
|
||||
!(std::is_nothrow_move_constructible<T>::value // N4562 §6.3/3 [any.class]
|
||||
&& sizeof(T) <= sizeof(storage_union::stack)
|
||||
&& std::alignment_of<T>::value <= std::alignment_of<storage_union::stack_storage_t>::value)>
|
||||
{};
|
||||
|
||||
/// Returns the pointer to the vtable of the type T.
|
||||
template<typename T>
|
||||
static vtable_type* vtable_for_type()
|
||||
{
|
||||
using VTableType = typename std::conditional<requires_allocation<T>::value, vtable_dynamic<T>, vtable_stack<T>>::type;
|
||||
static vtable_type table = {
|
||||
#ifndef ANY_IMPL_NO_RTTI
|
||||
VTableType::type,
|
||||
#endif
|
||||
#if 1
|
||||
VTableType::type_id,
|
||||
VTableType::underlying_type_id,
|
||||
VTableType::type_name,
|
||||
VTableType::underlying_type_name,
|
||||
#endif
|
||||
VTableType::destroy,
|
||||
VTableType::copy, VTableType::move,
|
||||
VTableType::swap,
|
||||
};
|
||||
return &table;
|
||||
}
|
||||
|
||||
protected:
|
||||
template<typename T>
|
||||
friend const T* any_cast(const any* operand) noexcept;
|
||||
template<typename T>
|
||||
friend T* any_cast(any* operand) noexcept;
|
||||
|
||||
#ifndef ANY_IMPL_NO_RTTI
|
||||
/// Same effect as is_same(this->type(), t);
|
||||
bool is_typed(const std::type_info& t) const
|
||||
{
|
||||
return is_same(this->type(), t);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef ANY_IMPL_NO_RTTI
|
||||
/// Checks if two type infos are the same.
|
||||
///
|
||||
/// If ANY_IMPL_FAST_TYPE_INFO_COMPARE is defined, checks only the address of the
|
||||
/// type infos, otherwise does an actual comparision. Checking addresses is
|
||||
/// only a valid approach when there's no interaction with outside sources
|
||||
/// (other shared libraries and such).
|
||||
static bool is_same(const std::type_info& a, const std::type_info& b)
|
||||
{
|
||||
#ifdef ANY_IMPL_FAST_TYPE_INFO_COMPARE
|
||||
return &a == &b;
|
||||
#else
|
||||
return a == b;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Casts (with no type_info checks) the storage pointer as const T*.
|
||||
template<typename T>
|
||||
const T* cast() const noexcept
|
||||
{
|
||||
return requires_allocation<typename std::decay<T>::type>::value?
|
||||
reinterpret_cast<const T*>(storage.dynamic) :
|
||||
reinterpret_cast<const T*>(&storage.stack);
|
||||
}
|
||||
|
||||
/// Casts (with no type_info checks) the storage pointer as T*.
|
||||
template<typename T>
|
||||
T* cast() noexcept
|
||||
{
|
||||
return requires_allocation<typename std::decay<T>::type>::value?
|
||||
reinterpret_cast<T*>(storage.dynamic) :
|
||||
reinterpret_cast<T*>(&storage.stack);
|
||||
}
|
||||
|
||||
private:
|
||||
storage_union storage; // on offset(0) so no padding for align
|
||||
vtable_type* vtable;
|
||||
|
||||
template<typename ValueType, typename T>
|
||||
typename std::enable_if<requires_allocation<T>::value>::type
|
||||
do_construct(ValueType&& value)
|
||||
{
|
||||
storage.dynamic = new T(std::forward<ValueType>(value));
|
||||
}
|
||||
|
||||
template<typename ValueType, typename T>
|
||||
typename std::enable_if<!requires_allocation<T>::value>::type
|
||||
do_construct(ValueType&& value)
|
||||
{
|
||||
new (&storage.stack) T(std::forward<ValueType>(value));
|
||||
}
|
||||
|
||||
/// Chooses between stack and dynamic allocation for the type decay_t<ValueType>,
|
||||
/// assigns the correct vtable, and constructs the object on our storage.
|
||||
template<typename ValueType>
|
||||
void construct(ValueType&& value)
|
||||
{
|
||||
using T = typename std::decay<ValueType>::type;
|
||||
|
||||
this->vtable = vtable_for_type<T>();
|
||||
|
||||
do_construct<ValueType,T>(std::forward<ValueType>(value));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template<typename ValueType>
|
||||
inline ValueType any_cast_move_if_true(typename std::remove_reference<ValueType>::type* p, std::true_type)
|
||||
{
|
||||
return std::move(*p);
|
||||
}
|
||||
|
||||
template<typename ValueType>
|
||||
inline ValueType any_cast_move_if_true(typename std::remove_reference<ValueType>::type* p, std::false_type)
|
||||
{
|
||||
return *p;
|
||||
}
|
||||
}
|
||||
|
||||
/// Performs *any_cast<add_const_t<remove_reference_t<ValueType>>>(&operand), or throws bad_any_cast on failure.
|
||||
template<typename ValueType>
|
||||
inline ValueType any_cast(const any& operand)
|
||||
{
|
||||
auto p = any_cast<typename std::add_const<typename std::remove_reference<ValueType>::type>::type>(&operand);
|
||||
#ifndef ANY_IMPL_NO_EXCEPTIONS
|
||||
if(p == nullptr) throw bad_any_cast();
|
||||
#endif
|
||||
return *p;
|
||||
}
|
||||
|
||||
/// Performs *any_cast<remove_reference_t<ValueType>>(&operand), or throws bad_any_cast on failure.
|
||||
template<typename ValueType>
|
||||
inline ValueType any_cast(any& operand)
|
||||
{
|
||||
auto p = any_cast<typename std::remove_reference<ValueType>::type>(&operand);
|
||||
#ifndef ANY_IMPL_NO_EXCEPTIONS
|
||||
if(p == nullptr) throw bad_any_cast();
|
||||
#endif
|
||||
return *p;
|
||||
}
|
||||
|
||||
///
|
||||
/// If ValueType is MoveConstructible and isn't a lvalue reference, performs
|
||||
/// std::move(*any_cast<remove_reference_t<ValueType>>(&operand)), otherwise
|
||||
/// *any_cast<remove_reference_t<ValueType>>(&operand). Throws bad_any_cast on failure.
|
||||
///
|
||||
template<typename ValueType>
|
||||
inline ValueType any_cast(any&& operand)
|
||||
{
|
||||
using can_move = std::integral_constant<bool,
|
||||
std::is_move_constructible<ValueType>::value
|
||||
&& !std::is_lvalue_reference<ValueType>::value>;
|
||||
|
||||
auto p = any_cast<typename std::remove_reference<ValueType>::type>(&operand);
|
||||
#ifndef ANY_IMPL_NO_EXCEPTIONS
|
||||
if(p == nullptr) throw bad_any_cast();
|
||||
#endif
|
||||
return detail::any_cast_move_if_true<ValueType>(p, can_move());
|
||||
}
|
||||
|
||||
/// If operand != nullptr && operand->type() == typeid(ValueType), a pointer to the object
|
||||
/// contained by operand, otherwise nullptr.
|
||||
template<typename ValueType>
|
||||
inline const ValueType* any_cast(const any* operand) noexcept
|
||||
{
|
||||
using T = typename std::decay<ValueType>::type;
|
||||
|
||||
#ifndef ANY_IMPL_NO_RTTI
|
||||
if (operand && operand->is_typed(typeid(T)))
|
||||
#else
|
||||
if (operand && operand->vtable == any::vtable_for_type<T>())
|
||||
#endif
|
||||
return operand->cast<ValueType>();
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// If operand != nullptr && operand->type() == typeid(ValueType), a pointer to the object
|
||||
/// contained by operand, otherwise nullptr.
|
||||
template<typename ValueType>
|
||||
inline ValueType* any_cast(any* operand) noexcept
|
||||
{
|
||||
using T = typename std::decay<ValueType>::type;
|
||||
|
||||
#ifndef ANY_IMPL_NO_RTTI
|
||||
if (operand && operand->is_typed(typeid(T)))
|
||||
#else
|
||||
if (operand && operand->vtable == any::vtable_for_type<T>())
|
||||
#endif
|
||||
return operand->cast<ValueType>();
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
inline void swap(linb::any& lhs, linb::any& rhs) noexcept
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -11,6 +11,8 @@
|
||||
// so an application should not frequently construct Token class
|
||||
// among threads.
|
||||
//
|
||||
// TODO: Deprecate `Token` class? Seems there is no beneficial usecase in TinyUSDZ(`std::string` may suffice)
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright 2022 - Present, Syoyo Fujita.
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "value-pprint.hh"
|
||||
#include "prim-types.hh"
|
||||
|
||||
@@ -222,7 +225,7 @@ std::ostream &operator<<(std::ostream &ofs, const tinyusdz::value::token &tok) {
|
||||
std::ostream &operator<<(std::ostream &ofs, const tinyusdz::value::dict &m) {
|
||||
ofs << "{\n";
|
||||
for (const auto &item : m) {
|
||||
ofs << item.first << " = " << item.second << "\n";
|
||||
ofs << item.first << " = " << tinyusdz::value::pprint_any(item.second) << "\n";
|
||||
}
|
||||
ofs << "}";
|
||||
|
||||
@@ -234,26 +237,30 @@ std::ostream &operator<<(std::ostream &ofs, const tinyusdz::value::dict &m) {
|
||||
namespace tinyusdz {
|
||||
namespace value {
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const any_value &v) {
|
||||
//std::ostream &operator<<(std::ostream &os, const any_value &v) {
|
||||
//std::ostream &operator<<(std::ostream &os, const linb::any &v) {
|
||||
std::string pprint_any(const linb::any &v) {
|
||||
|
||||
std::stringstream os;
|
||||
|
||||
// Simple brute-force way..
|
||||
// TODO: Use std::function or some template technique?
|
||||
|
||||
#define BASETYPE_CASE_EXPR(__ty) \
|
||||
case TypeTrait<__ty>::type_id: { \
|
||||
os << *reinterpret_cast<const __ty *>(v.value()); \
|
||||
os << linb::any_cast<const __ty>(v); \
|
||||
break; \
|
||||
}
|
||||
|
||||
#define ARRAY1DTYPE_CASE_EXPR(__ty) \
|
||||
case TypeTrait<std::vector<__ty>>::type_id: { \
|
||||
os << *reinterpret_cast<const std::vector<__ty> *>(v.value()); \
|
||||
os << linb::any_cast<const std::vector<__ty>>(v); \
|
||||
break; \
|
||||
}
|
||||
|
||||
#define ARRAY2DTYPE_CASE_EXPR(__ty) \
|
||||
case TypeTrait<std::vector<std::vector<__ty>>>::type_id: { \
|
||||
os << *reinterpret_cast<const std::vector<std::vector<__ty>> *>( \
|
||||
v.value()); \
|
||||
os << linb::any_cast<const std::vector<std::vector<__ty>>>(v); \
|
||||
break; \
|
||||
}
|
||||
|
||||
@@ -329,7 +336,7 @@ std::ostream &operator<<(std::ostream &os, const any_value &v) {
|
||||
#undef ARRAY2DTYPE_CASE_EXPR
|
||||
#undef CASE_EXPR_LIST
|
||||
|
||||
return os;
|
||||
return os.str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -83,7 +83,9 @@ namespace tinyusdz {
|
||||
namespace value {
|
||||
|
||||
//std::ostream &operator<<(std::ostream &os, const tinyusdz::value::Value &v);
|
||||
std::ostream &operator<<(std::ostream &os, const tinyusdz::value::any_value &v);
|
||||
//std::ostream &operator<<(std::ostream &os, const tinyusdz::value::any_value &v);
|
||||
//std::ostream &operator<<(std::ostream &os, const linb::any &v);
|
||||
std::string pprint_any(const linb::any &v);
|
||||
|
||||
} // namespace primvar
|
||||
} // namespace tinyusdz
|
||||
|
||||
@@ -7,9 +7,10 @@
|
||||
namespace tinyusdz {
|
||||
namespace value {
|
||||
|
||||
base_value::~base_value() {}
|
||||
//base_value::~base_value() {}
|
||||
|
||||
|
||||
#if 0
|
||||
bool is_float(const any_value &v) {
|
||||
if (v.underlying_type_name() == "float") {
|
||||
return true;
|
||||
@@ -89,6 +90,7 @@ bool is_double4(const Value &v) {
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0 // TODO: Remove
|
||||
bool Reconstructor::reconstruct(AttribMap &amap) {
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
/// Copyright 2021-present Syoyo Fujita.
|
||||
/// MIT license.
|
||||
///
|
||||
/// Type-erasure technique for Value, a Value class which can represent USD's mandatory and frequently used types(e.g. `float3`, `token`, `asset`)
|
||||
/// and its array and compound-types(1D/2D array, dictionary).
|
||||
/// Neigher std::any nor std::variant is applicable for such usecases, so write our own.
|
||||
/// Type-erasure technique for Value, a Value class which can represent USD's
|
||||
/// mandatory and frequently used types(e.g. `float3`, `token`, `asset`) and its
|
||||
/// array and compound-types(1D/2D array, dictionary). Neigher std::any nor
|
||||
/// std::variant is applicable for such usecases, so write our own.
|
||||
///
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
@@ -15,7 +17,6 @@
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
@@ -49,7 +50,11 @@
|
||||
#endif
|
||||
|
||||
#include "token-type.hh"
|
||||
//#include "external/staticstruct.hh"
|
||||
|
||||
// forward decl
|
||||
namespace linb {
|
||||
class any;
|
||||
};
|
||||
|
||||
namespace tinyusdz {
|
||||
namespace value {
|
||||
@@ -59,7 +64,7 @@ namespace value {
|
||||
constexpr char kToken[] = "token";
|
||||
constexpr char kString[] = "string";
|
||||
constexpr char kPath[] = "Path";
|
||||
constexpr char kAssetPath[] = "asset"; // `asset` in USDA
|
||||
constexpr char kAssetPath[] = "asset"; // `asset` in USDA
|
||||
constexpr char kDictionary[] = "dictionary";
|
||||
constexpr char kTimeCode[] = "timecode";
|
||||
|
||||
@@ -87,12 +92,12 @@ constexpr char kMatrix2d[] = "matrix2d";
|
||||
constexpr char kMatrix3d[] = "matrix3d";
|
||||
constexpr char kMatrix4d[] = "matrix4d";
|
||||
|
||||
constexpr char kFloat[] = "float";
|
||||
constexpr char kFloat[] = "float";
|
||||
constexpr char kFloat2[] = "float2";
|
||||
constexpr char kFloat3[] = "float3";
|
||||
constexpr char kFloat4[] = "float4";
|
||||
|
||||
constexpr char kDouble[] = "double";
|
||||
constexpr char kDouble[] = "double";
|
||||
constexpr char kDouble2[] = "double2";
|
||||
constexpr char kDouble3[] = "double3";
|
||||
constexpr char kDouble4[] = "double4";
|
||||
@@ -130,19 +135,17 @@ constexpr char kTexCoord3d[] = "texCoord3d";
|
||||
|
||||
constexpr char kRelationship[] = "rel";
|
||||
|
||||
inline std::string Add1DArraySuffix(const std::string &c) {
|
||||
return c + "[]";
|
||||
}
|
||||
inline std::string Add1DArraySuffix(const std::string &c) { return c + "[]"; }
|
||||
|
||||
using token = tinyusdz::Token;
|
||||
|
||||
// SdfAssetPath
|
||||
class asset_path
|
||||
{
|
||||
public:
|
||||
asset_path() = default;
|
||||
asset_path(const std::string &a) : asset_path_(a) {}
|
||||
asset_path(const std::string &a, const std::string &r) : asset_path_(a), resolved_path_(r) {}
|
||||
class asset_path {
|
||||
public:
|
||||
asset_path() = default;
|
||||
asset_path(const std::string &a) : asset_path_(a) {}
|
||||
asset_path(const std::string &a, const std::string &r)
|
||||
: asset_path_(a), resolved_path_(r) {}
|
||||
|
||||
private:
|
||||
std::string asset_path_;
|
||||
@@ -158,17 +161,17 @@ class asset_path
|
||||
// (See `crate-format.hh` for Type ID used in Crate binary)
|
||||
//
|
||||
// TODO(syoyo): Support 3D and 4D?
|
||||
constexpr uint32_t TYPE_ID_1D_ARRAY_BIT = 1 << 20; // 1024
|
||||
constexpr uint32_t TYPE_ID_2D_ARRAY_BIT = 1 << 21; // 2048
|
||||
//constexpr uint32_t TYPE_ID_3D_ARRAY_BIT = 1 << 22;
|
||||
//constexpr uint32_t TYPE_ID_4D_ARRAY_BIT = 1 << 23;
|
||||
constexpr uint32_t TYPE_ID_1D_ARRAY_BIT = 1 << 20; // 1024
|
||||
constexpr uint32_t TYPE_ID_2D_ARRAY_BIT = 1 << 21; // 2048
|
||||
// constexpr uint32_t TYPE_ID_3D_ARRAY_BIT = 1 << 22;
|
||||
// constexpr uint32_t TYPE_ID_4D_ARRAY_BIT = 1 << 23;
|
||||
|
||||
enum TypeId {
|
||||
TYPE_ID_INVALID, // = 0
|
||||
TYPE_ID_NULL,
|
||||
TYPE_ID_VOID,
|
||||
TYPE_ID_MONOSTATE,
|
||||
TYPE_ID_BLOCK, // None as type
|
||||
TYPE_ID_BLOCK, // None as type
|
||||
|
||||
TYPE_ID_TOKEN,
|
||||
TYPE_ID_STRING,
|
||||
@@ -248,11 +251,11 @@ enum TypeId {
|
||||
TYPE_ID_PAYLOAD,
|
||||
|
||||
TYPE_ID_TIMECODE,
|
||||
//TYPE_ID_TIMESAMPLE,
|
||||
// TYPE_ID_TIMESAMPLE,
|
||||
|
||||
TYPE_ID_DICT,
|
||||
|
||||
//TYPE_ID_ASSET,
|
||||
// TYPE_ID_ASSET,
|
||||
TYPE_ID_ASSET_PATH,
|
||||
|
||||
// Types in prim-types.hh
|
||||
@@ -324,8 +327,7 @@ enum TypeId {
|
||||
TYPE_ID_ALL = (TYPE_ID_2D_ARRAY_BIT - 1) // terminator.
|
||||
};
|
||||
|
||||
struct timecode
|
||||
{
|
||||
struct timecode {
|
||||
double value;
|
||||
};
|
||||
|
||||
@@ -617,16 +619,15 @@ struct texcoord3d {
|
||||
};
|
||||
|
||||
// Attribute Block(None)
|
||||
struct Block {
|
||||
};
|
||||
struct Block {};
|
||||
|
||||
using double2 = std::array<double, 2>;
|
||||
using double3 = std::array<double, 3>;
|
||||
using double4 = std::array<double, 4>;
|
||||
|
||||
struct any_value;
|
||||
|
||||
using dict = std::map<std::string, any_value>;
|
||||
//struct any_value;
|
||||
//using dict = std::map<std::string, any_value>;
|
||||
using dict = std::map<std::string, linb::any>;
|
||||
|
||||
template <class dtype>
|
||||
struct TypeTrait;
|
||||
@@ -697,7 +698,6 @@ DEFINE_TYPE_TRAIT(double2, kDouble2, TYPE_ID_DOUBLE2, 2);
|
||||
DEFINE_TYPE_TRAIT(double3, kDouble3, TYPE_ID_DOUBLE3, 3);
|
||||
DEFINE_TYPE_TRAIT(double4, kDouble4, TYPE_ID_DOUBLE4, 4);
|
||||
|
||||
|
||||
DEFINE_TYPE_TRAIT(quath, kQuath, TYPE_ID_QUATH, 1);
|
||||
DEFINE_TYPE_TRAIT(quatf, kQuatf, TYPE_ID_QUATF, 1);
|
||||
DEFINE_TYPE_TRAIT(quatd, kQuatd, TYPE_ID_QUATD, 1);
|
||||
@@ -748,7 +748,8 @@ DEFINE_TYPE_TRAIT(dict, kDictionary, TYPE_ID_DICT, 1);
|
||||
DEFINE_TYPE_TRAIT(asset_path, kAssetPath, TYPE_ID_ASSET_PATH, 1);
|
||||
|
||||
//
|
||||
// Other types(e.g. TYPE_ID_REFERENCE) are defined in `prim-types.hh` and `crate-format.hh`(Data types used in Crate data)
|
||||
// Other types(e.g. TYPE_ID_REFERENCE) are defined in `prim-types.hh` and
|
||||
// `crate-format.hh`(Data types used in Crate data)
|
||||
//
|
||||
|
||||
#undef DEFINE_TYPE_TRAIT
|
||||
@@ -791,6 +792,7 @@ struct TypeTrait<std::vector<std::vector<T>>> {
|
||||
nonstd::optional<std::string> TryGetTypeName(uint32_t tyid);
|
||||
std::string GetTypeName(uint32_t tyid);
|
||||
|
||||
#if 0 // TODO: Remove
|
||||
struct base_value {
|
||||
virtual ~base_value();
|
||||
virtual const std::string type_name() const = 0;
|
||||
@@ -918,20 +920,34 @@ struct any_value {
|
||||
return *(reinterpret_cast<const std::vector<T> *>(p->value()));
|
||||
}
|
||||
|
||||
std::shared_ptr<base_value> p; // TODO: Use raw pointer?
|
||||
std::shared_ptr<base_value> p; // TODO: Use raw pointer?
|
||||
};
|
||||
#endif
|
||||
|
||||
} // namespace value
|
||||
} // namespace tinyusdz
|
||||
|
||||
// TODO(syoyo): Replace any_value with linb::any
|
||||
// TODO(syoyo): Move TypeTrait<T> code to another header to simplify .inc
|
||||
// inclusion.
|
||||
#include "tiny-any.inc"
|
||||
|
||||
namespace tinyusdz {
|
||||
namespace value {
|
||||
|
||||
// Handy, but may not efficient for large time samples(e.g. 1M samples or more)
|
||||
//
|
||||
// For the runtime speed, adding 10M `double` samples to any_value takes roughly 3.1 ms on
|
||||
// Threadripper 1950X, whereas simple vector<double> push_back only takes 390 us(roughly x8 times faster).
|
||||
// (Build benchmarks to see the numbers on your CPU)
|
||||
// For the runtime speed, with "-O2 -g" optimization, adding 10M `double`
|
||||
// samples to linb::any takes roughly 1.8 ms on Threadripper 1950X, whereas
|
||||
// simple vector<double> push_back takes 390 us(roughly x4 times faster). (Build
|
||||
// benchmarks to see the numbers on your CPU)
|
||||
//
|
||||
// We assume having large time samples is rare situlation, but will do some C++ code optimization if required.
|
||||
// We assume having large time samples is rare situlation, but will do some C++
|
||||
// code optimization if required.
|
||||
//
|
||||
struct TimeSamples {
|
||||
std::vector<double> times;
|
||||
std::vector<any_value> values; // Could be an array of 'None' or Type T
|
||||
std::vector<linb::any> values; // Could be an array of 'None' or Type T
|
||||
|
||||
bool Valid() {
|
||||
if (times.size() > 0) {
|
||||
@@ -942,9 +958,8 @@ struct TimeSamples {
|
||||
};
|
||||
|
||||
// simple linear interpolator
|
||||
template<typename T>
|
||||
struct LinearInterpolator
|
||||
{
|
||||
template <typename T>
|
||||
struct LinearInterpolator {
|
||||
static T interpolate(const T *values, const size_t n, const double _t) {
|
||||
if (n == 0) {
|
||||
return static_cast<T>(0);
|
||||
@@ -955,8 +970,8 @@ struct LinearInterpolator
|
||||
// [0.0, 1.0]
|
||||
double t = std::fmin(0.0, std::fmax(_t, 1.0));
|
||||
|
||||
size_t idx0 = std::max(n-1, size_t(t * double(n)));
|
||||
size_t idx1 = std::max(n-1, idx0+1);
|
||||
size_t idx0 = std::max(n - 1, size_t(t * double(n)));
|
||||
size_t idx1 = std::max(n - 1, idx0 + 1);
|
||||
|
||||
return (1.0 - t) * values[idx0] + t * values[idx1];
|
||||
}
|
||||
@@ -973,23 +988,21 @@ struct LinearInterpolator
|
||||
//
|
||||
// radius = { 0: 1.0, 2: 3.0 }
|
||||
//
|
||||
template<typename T>
|
||||
struct AnimatableValue
|
||||
{
|
||||
std::vector<double> times; // Assume sorted
|
||||
template <typename T>
|
||||
struct AnimatableValue {
|
||||
std::vector<double> times; // Assume sorted
|
||||
std::vector<T> values;
|
||||
|
||||
bool is_scalar() const {
|
||||
return (times.size() == 0) && (values.size() == 1);
|
||||
}
|
||||
bool is_scalar() const { return (times.size() == 0) && (values.size() == 1); }
|
||||
|
||||
bool is_timesample() const {
|
||||
return (times.size() > 0) && (times.size() == values.size());
|
||||
}
|
||||
|
||||
template<class Interpolator>
|
||||
template <class Interpolator>
|
||||
T Get(double time = 0.0) {
|
||||
std::vector<double>::iterator it = std::lower_bound(times.begin(), times.end(), time);
|
||||
std::vector<double>::iterator it =
|
||||
std::lower_bound(times.begin(), times.end(), time);
|
||||
|
||||
size_t idx0, idx1;
|
||||
if (it != times.end()) {
|
||||
@@ -1010,6 +1023,7 @@ struct AnimatableValue
|
||||
}
|
||||
};
|
||||
|
||||
#if 0 // Remove
|
||||
struct PrimVar {
|
||||
// For scalar value, times.size() == 0, and values.size() == 1
|
||||
TimeSamples var;
|
||||
@@ -1048,11 +1062,13 @@ struct PrimVar {
|
||||
}
|
||||
|
||||
if (TypeTrait<T>::type_id == var.values[0].type_id()) {
|
||||
return std::move(*reinterpret_cast<const T *>(var.values[0].value()));
|
||||
//return std::move(*reinterpret_cast<const T *>(var.values[0].value()));
|
||||
return std::move(linb::any_cast<const T *>(var.values[0]));
|
||||
} else if (TypeTrait<T>::underlying_type_id == var.values[0].underlying_type_id()) {
|
||||
// `roll` type. Can be able to cast to underlying type since the memory
|
||||
// layout does not change.
|
||||
return std::move(*reinterpret_cast<const T *>(var.values[0].value()));
|
||||
//return std::move(*reinterpret_cast<const T *>(var.values[0].value()));
|
||||
return std::move(linb::any_cast<const T *>(var.values[0]));
|
||||
}
|
||||
return nonstd::nullopt;
|
||||
}
|
||||
@@ -1066,9 +1082,11 @@ struct PrimVar {
|
||||
}
|
||||
|
||||
};
|
||||
#endif
|
||||
|
||||
// using Object = std::map<std::string, any_value>;
|
||||
|
||||
///
|
||||
/// Generic Value class using any
|
||||
///
|
||||
class Value {
|
||||
public:
|
||||
// using Dict = std::map<std::string, Value>;
|
||||
@@ -1078,8 +1096,8 @@ class Value {
|
||||
template <class T>
|
||||
Value(const T &v) : v_(v) {}
|
||||
|
||||
//template <class T>
|
||||
//Value(T &&v) : v_(v) {}
|
||||
// template <class T>
|
||||
// Value(T &&v) : v_(v) {}
|
||||
|
||||
std::string type_name() const { return v_.type_name(); }
|
||||
std::string underlying_type_name() const { return v_.underlying_type_name(); }
|
||||
@@ -1091,7 +1109,8 @@ class Value {
|
||||
template <class T>
|
||||
const T *as() const {
|
||||
if (TypeTrait<T>::type_id == v_.type_id()) {
|
||||
return reinterpret_cast<const T *>(v_.value());
|
||||
//return reinterpret_cast<const T *>(v_.value());
|
||||
return linb::any_cast<const T>(&v_);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1101,8 +1120,9 @@ class Value {
|
||||
// Undefined behavior(usually will triger segmentation fault) when
|
||||
// type-mismatch. (We don't throw exception)
|
||||
template <class T>
|
||||
const T &value() const {
|
||||
return (*reinterpret_cast<const T *>(v_.value()));
|
||||
const T value() const {
|
||||
//return (*reinterpret_cast<const T *>(v_.value()));
|
||||
return linb::any_cast<const T>(v_);
|
||||
}
|
||||
|
||||
// Type-safe way to get concrete value.
|
||||
@@ -1124,24 +1144,23 @@ class Value {
|
||||
return (*this);
|
||||
}
|
||||
|
||||
bool is_array() const { return v_.ndim() > 0; }
|
||||
int32_t ndim() const { return v_.ndim(); }
|
||||
//bool is_array() const { return v_.ndim() > 0; }
|
||||
//int32_t ndim() const { return v_.ndim(); }
|
||||
|
||||
uint32_t ncomp() const { return v_.ncomp(); }
|
||||
//uint32_t ncomp() const { return v_.ncomp(); }
|
||||
|
||||
bool is_vector_type() const { return v_.ncomp() > 1; }
|
||||
//bool is_vector_type() const { return v_.ncomp() > 1; }
|
||||
|
||||
//friend std::ostream &operator<<(std::ostream &os, const Value &v);
|
||||
const any_value& get_raw() const {
|
||||
return v_;
|
||||
}
|
||||
// friend std::ostream &operator<<(std::ostream &os, const Value &v);
|
||||
//const any_value &get_raw() const { return v_; }
|
||||
|
||||
private:
|
||||
any_value v_;
|
||||
//any_value v_;
|
||||
linb::any v_;
|
||||
};
|
||||
|
||||
bool is_float(const any_value &v);
|
||||
bool is_double(const any_value &v);
|
||||
//bool is_float(const any_value &v);
|
||||
//bool is_double(const any_value &v);
|
||||
|
||||
// Frequently-used utility function
|
||||
bool is_float(const Value &v);
|
||||
@@ -1153,7 +1172,7 @@ bool is_double2(const Value &v);
|
||||
bool is_double3(const Value &v);
|
||||
bool is_double4(const Value &v);
|
||||
|
||||
|
||||
#if 0 // TODO: Remove? since not used so frequently at the moment.
|
||||
//
|
||||
// typecast from type_id
|
||||
// It does not throw exception.
|
||||
@@ -1185,7 +1204,9 @@ TYPECAST_BASETYPE(TYPE_ID_FLOAT | TYPE_ID_1D_ARRAY_BIT, std::vector<float>);
|
||||
// TODO(syoyo): Implement more types...
|
||||
|
||||
#undef TYPECAST_BASETYPE
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
//
|
||||
// Type checker
|
||||
//
|
||||
@@ -1195,19 +1216,21 @@ struct is_type {
|
||||
return TypeTrait<T>::type_id == v.type_id();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
struct AttribMap {
|
||||
std::map<std::string, any_value> attribs;
|
||||
std::map<std::string, Value> attribs;
|
||||
};
|
||||
|
||||
} // namespace value
|
||||
} // namespace tinyusdz
|
||||
} // namespace value
|
||||
} // namespace tinyusdz
|
||||
|
||||
namespace tinyusdz {
|
||||
namespace value {
|
||||
|
||||
static_assert(sizeof(quath) == 8, "sizeof(quath) must be 8");
|
||||
static_assert(sizeof(quatf) == 16, "sizeof(quatf) must be 16");
|
||||
static_assert(sizeof(quatd) == 32, "sizeof(quatd) must be 32");
|
||||
static_assert(sizeof(half) == 2, "sizeof(half) must be 2");
|
||||
static_assert(sizeof(half2) == 4, "sizeof(half2) must be 4");
|
||||
static_assert(sizeof(half3) == 6, "sizeof(half3) must be 6");
|
||||
@@ -1216,5 +1239,5 @@ static_assert(sizeof(float3) == 12, "sizeof(float3) must be 12");
|
||||
static_assert(sizeof(color3f) == 12, "sizeof(color3f) must be 12");
|
||||
static_assert(sizeof(color4f) == 16, "sizeof(color4f) must be 16");
|
||||
|
||||
} // namespace value
|
||||
} // namespace tinyusdz
|
||||
} // namespace value
|
||||
} // namespace tinyusdz
|
||||
|
||||
@@ -53,6 +53,7 @@ static bool ReconstructVertrices(const any_value &v, Mesh &mesh) {
|
||||
|
||||
void primvar_test(void) {
|
||||
|
||||
#if 0
|
||||
{
|
||||
any_value f = 1.2f;
|
||||
TEST_CHECK(is_float(f));
|
||||
@@ -74,6 +75,7 @@ void primvar_test(void) {
|
||||
auto c = typecast<TYPE_ID_FLOAT | TYPE_ID_1D_ARRAY_BIT>::to(f);
|
||||
std::cout << "c = " << c << "\n";
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user