From fd94c6f239d2436b6152935b4c99217129953a5d Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 20 May 2024 12:23:58 +0200 Subject: Add convert_to_base(value) variants that allow derive-to-base conversion --- libbuild2/variable.hxx | 15 +++++++++++---- libbuild2/variable.txx | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/libbuild2/variable.hxx b/libbuild2/variable.hxx index aed3350..6dfbbc6 100644 --- a/libbuild2/variable.hxx +++ b/libbuild2/variable.hxx @@ -92,6 +92,9 @@ namespace build2 // static_cast to const T*. If it is NULL, then cast data_ directly. Note // that this function is used for both const and non-const values. // + // @@ This is currently ignored by as() which is now used in quite a + // few places (in particular, grep for as). + // const void* (*const cast) (const value&, const value_type*); // If NULL, then the types are compared as PODs using memcmp(). @@ -702,14 +705,18 @@ namespace build2 template T convert (names&&); // Convert value to T. If value is already of type T, then simply cast it. - // Otherwise call convert(names) above. If value is NULL, then throw - // invalid_argument (with an appropriate message). + // Otherwise call convert(names) above. If the value is NULL, then throw + // invalid_argument (with an appropriate message). See also + // convert_to_base() below. // template T convert (value&&); + template T convert (const value&); - // As above but preserving the value. + // As above but also allow the derived-to-base conversions (where T is + // base). Note that this call may potentially slice the value. // - template T convert (const value&); + template T convert_to_base (value&&); + template T convert_to_base (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 diff --git a/libbuild2/variable.txx b/libbuild2/variable.txx index 0b831e9..a1ee340 100644 --- a/libbuild2/variable.txx +++ b/libbuild2/variable.txx @@ -38,6 +38,11 @@ namespace build2 { if (v.type == nullptr) return convert (move (v).as ()); + // + // Note that while it may be tempting to use is_a() here like in cast(), + // the implications are unclear (i.e., we may end up relaxing things we + // don't want to). So we have the convert_to_base() variants instead. + // else if (v.type == &value_traits::value_type) return move (v).as (); } @@ -61,6 +66,36 @@ namespace build2 } template + T + convert_to_base (value&& v) + { + if (v) + { + if (v.type == nullptr) + return convert (move (v).as ()); + else if (v.type->is_a ()) + return move (v).as (); + } + + convert_throw (v ? v.type : nullptr, value_traits::value_type); + } + + template + T + convert_to_base (const value& v) + { + if (v) + { + if (v.type == nullptr) + return convert (names (v.as ())); + else if (v.type->is_a ()) + return v.as (); + } + + convert_throw (v ? v.type : nullptr, value_traits::value_type); + } + + template void default_dtor (value& v) { -- cgit v1.1