aboutsummaryrefslogtreecommitdiff
path: root/libbuild2
diff options
context:
space:
mode:
Diffstat (limited to 'libbuild2')
-rw-r--r--libbuild2/variable.cxx18
-rw-r--r--libbuild2/variable.hxx6
-rw-r--r--libbuild2/variable.ixx18
-rw-r--r--libbuild2/variable.txx22
4 files changed, 52 insertions, 12 deletions
diff --git a/libbuild2/variable.cxx b/libbuild2/variable.cxx
index a4c3ef3..91b25bd 100644
--- a/libbuild2/variable.cxx
+++ b/libbuild2/variable.cxx
@@ -410,6 +410,24 @@ namespace build2
v.assign (move (ns), nullptr); // Assign new data.
}
+ [[noreturn]] void
+ convert_throw (const value_type* from, const value_type& to)
+ {
+ string m ("invalid ");
+ m += to.name;
+ m += " value: ";
+
+ if (from != nullptr)
+ {
+ m += "conversion from ";
+ m += from->name;
+ }
+ else
+ m += "null";
+
+ throw invalid_argument (move (m));
+ }
+
// Throw invalid_argument for an invalid simple value.
//
[[noreturn]] static void
diff --git a/libbuild2/variable.hxx b/libbuild2/variable.hxx
index 6c78c95..3152c71 100644
--- a/libbuild2/variable.hxx
+++ b/libbuild2/variable.hxx
@@ -47,6 +47,8 @@ namespace build2
//
const value_type* base_type;
+ template <typename T> const value_type* is_a () const;
+
// Element type, if this is a vector.
//
const value_type* element_type;
@@ -628,6 +630,10 @@ namespace build2
//
template <typename T> T convert (value&&);
+ // As above but preserving the value.
+ //
+ template <typename T> T convert (const value&);
+
// Default implementations of the dtor/copy_ctor/copy_assing callbacks for
// types that are stored directly in value::data_ and the provide all the
// necessary functions (copy/move ctor and assignment operator).
diff --git a/libbuild2/variable.ixx b/libbuild2/variable.ixx
index a11ee12..c8f9541 100644
--- a/libbuild2/variable.ixx
+++ b/libbuild2/variable.ixx
@@ -7,6 +7,19 @@
namespace build2
{
+ // value_type
+ //
+ template <typename T>
+ inline const value_type* value_type::
+ is_a () const
+ {
+ const value_type* b (this);
+ for (;
+ b != nullptr && b != &value_traits<T>::value_type;
+ b = b->base_type) ;
+ return b;
+ }
+
// value
//
inline bool value::
@@ -169,10 +182,7 @@ namespace build2
//
// Note that here we use the value type address as type identity.
//
- const value_type* b (v.type);
- for (;
- b != nullptr && b != &value_traits<T>::value_type;
- b = b->base_type) ;
+ const value_type* b (v.type->is_a<T> ());
assert (b != nullptr);
return *static_cast<const T*> (v.type->cast == nullptr
diff --git a/libbuild2/variable.txx b/libbuild2/variable.txx
index 51176ae..0e10e87 100644
--- a/libbuild2/variable.txx
+++ b/libbuild2/variable.txx
@@ -55,6 +55,9 @@ namespace build2
(n == 0 ? " value: empty" : " value: multiple names"));
}
+ [[noreturn]] void
+ convert_throw (const value_type* from, const value_type& to);
+
template <typename T>
T
convert (value&& v)
@@ -67,19 +70,22 @@ namespace build2
return move (v).as<T> ();
}
- string m ("invalid ");
- m += value_traits<T>::value_type.name;
- m += " value: ";
+ convert_throw (v ? v.type : nullptr, value_traits<T>::value_type);
+ }
+ template <typename T>
+ T
+ convert (const value& v)
+ {
if (v)
{
- m += "conversion from ";
- m += v.type->name;
+ if (v.type == nullptr)
+ return convert<T> (names (v.as<names> ()));
+ else if (v.type == &value_traits<T>::value_type)
+ return v.as<T> ();
}
- else
- m += "null";
- throw invalid_argument (move (m));
+ convert_throw (v ? v.type : nullptr, value_traits<T>::value_type);
}
template <typename T>