diff --git a/src/include/OpenImageIO/attrdelegate.h b/src/include/OpenImageIO/attrdelegate.h index da0125b333..22d84e6605 100644 --- a/src/include/OpenImageIO/attrdelegate.h +++ b/src/include/OpenImageIO/attrdelegate.h @@ -149,6 +149,33 @@ template class AttrDelegate { return m_obj->getattribute(m_name, TypeString, &s) ? T(s) : defaultval; } + // `Delegate->get_indexed(int index, defaultval=T())` retrieves the + // index-th base value in the data as type T, or the defaultval if no + // such named data exists or is not the designated type. + template::value, int>::type = 0> + inline T get_indexed(int index, const T& defaultval = T()) const + { + T result; + if (!m_obj->getattribute_indexed(m_name, index, + TypeDescFromC::value(), &result)) + result = defaultval; + return result; + } + + // Using enable_if, make a slightly different version of get_indexed<> + // for strings, which need to do some ustring magic because we can't + // directly store in a std::string or string_view. + template::value, int>::type = 1> + inline T get_indexed(int index, const T& defaultval = T()) const + { + ustring s; + return m_obj->getattribute_indexed(m_name, index, TypeString, &s) + ? T(s) + : defaultval; + } + // `Delegate->as_string(defaultval="")` returns the data, no matter its // type, as a string. Returns the defaultval if no such data exists at // all. diff --git a/src/include/OpenImageIO/paramlist.h b/src/include/OpenImageIO/paramlist.h index 4443786597..f1732564c3 100644 --- a/src/include/OpenImageIO/paramlist.h +++ b/src/include/OpenImageIO/paramlist.h @@ -368,6 +368,15 @@ class OIIO_API ParamValueList : public std::vector { bool getattribute(string_view name, std::string& value, bool casesensitive = false) const; + /// Retrieve from list: If found its data type is reasonably convertible + /// to `type`, copy/convert the value into val[...] and return true. + /// Otherwise, return false and don't modify what val points to. + bool getattribute_indexed(string_view name, int index, TypeDesc type, + void* value, bool casesensitive = false) const; + /// Shortcut for retrieving a single string via getattribute. + bool getattribute_indexed(string_view name, int index, std::string& value, + bool casesensitive = false) const; + /// Sort alphabetically, optionally case-insensitively, locale- /// independently, and with all the "un-namespaced" items appearing /// first, followed by items with "prefixed namespaces" (e.g. "z" comes diff --git a/src/include/OpenImageIO/typedesc.h b/src/include/OpenImageIO/typedesc.h index 01725036ca..3e856cf015 100644 --- a/src/include/OpenImageIO/typedesc.h +++ b/src/include/OpenImageIO/typedesc.h @@ -222,9 +222,9 @@ struct OIIO_API TypeDesc { /// ignoring whether it's an array). size_t elementsize () const noexcept { return aggregate * basesize(); } - // /// Return just the underlying C scalar type, i.e., strip out the - // /// array-ness and the aggregateness. -// BASETYPE basetype () const { return TypeDesc(base); } + /// Return just the underlying C scalar type, i.e., strip out the + /// array-ness and the aggregateness. + constexpr TypeDesc scalartype() const { return TypeDesc(BASETYPE(basetype)); } /// Return the base type size, i.e., stripped of both array-ness /// and aggregateness. @@ -240,7 +240,7 @@ struct OIIO_API TypeDesc { /// Shortcut: is it UNKNOWN? constexpr bool is_unknown () const noexcept { return (basetype == UNKNOWN); } - /// if (typespec) is the same as asking whether it's not UNKNOWN. + /// if (typedesc) is the same as asking whether it's not UNKNOWN. constexpr operator bool () const noexcept { return (basetype != UNKNOWN); } /// Set *this to the type described in the string. Return the diff --git a/src/libutil/paramlist.cpp b/src/libutil/paramlist.cpp index b4ce3dc774..a85372a90d 100644 --- a/src/libutil/paramlist.cpp +++ b/src/libutil/paramlist.cpp @@ -597,6 +597,49 @@ ParamValueList::getattribute(string_view name, std::string& value, +bool +ParamValueList::getattribute_indexed(string_view name, int index, TypeDesc type, + void* value, bool casesensitive) const +{ + auto p = find(name, TypeUnknown, casesensitive); + if (p != cend()) { + if (index >= int(p->type().basevalues())) + return false; + TypeDesc basetype = p->type().scalartype(); + return convert_type(basetype, + (const char*)p->data() + index * basetype.size(), + type, value); + } else { + return false; + } +} + + + +bool +ParamValueList::getattribute_indexed(string_view name, int index, + std::string& value, + bool casesensitive) const +{ + auto p = find(name, TypeUnknown, casesensitive); + if (p != cend()) { + if (index >= int(p->type().basevalues())) + return false; + TypeDesc basetype = p->type().scalartype(); + ustring s; + bool ok = convert_type(basetype, + (const char*)p->data() + index * basetype.size(), + TypeString, &s); + if (ok) + value = s.string(); + return ok; + } else { + return false; + } +} + + + void ParamValueList::sort(bool casesensitive) { diff --git a/src/libutil/paramlist_test.cpp b/src/libutil/paramlist_test.cpp index 04147d22df..813f95365c 100644 --- a/src/libutil/paramlist_test.cpp +++ b/src/libutil/paramlist_test.cpp @@ -347,6 +347,9 @@ test_delegates() OIIO_CHECK_EQUAL(pl["bar4"].get(), "barbarbar?"); OIIO_CHECK_EQUAL(pl["red"].get(), Imath::Color3f(1.0f, 0.0f, 0.0f)); + OIIO_CHECK_EQUAL(pl["red"].get_indexed(0), 1.0f); + OIIO_CHECK_EQUAL(pl["red"].get_indexed(1), 0.0f); + OIIO_CHECK_EQUAL(pl["red"].get_indexed(2), 0.0f); OIIO_CHECK_EQUAL(pl["xy"].get(), Imath::V3f(0.5f, 0.5f, 0.0f)); OIIO_CHECK_EQUAL(pl["Tx"].get(), Imath::M44f(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 42, 0, 0,