From de15b95d09d00821aa23e96a0c3e827689c27a58 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 20 Jul 2016 16:18:29 +0200 Subject: Switch to dynamic empty() implementation in variable value The current model fell apart when we modified values directly. --- build2/cxx/link.cxx | 2 +- build2/dump.cxx | 6 +- build2/file.cxx | 2 +- build2/parser.cxx | 36 ++--- build2/variable | 121 ++++++++++------- build2/variable.cxx | 169 ++++++++++-------------- build2/variable.ixx | 370 +++++++++++++++++++++------------------------------- build2/variable.txx | 77 ++++++----- 8 files changed, 358 insertions(+), 425 deletions(-) diff --git a/build2/cxx/link.cxx b/build2/cxx/link.cxx index 88181aa..ba08119 100644 --- a/build2/cxx/link.cxx +++ b/build2/cxx/link.cxx @@ -1210,7 +1210,7 @@ namespace build2 { ranlib = rs["config.bin.ranlib"]; - if (ranlib->empty ()) // @@ BC LT [null]. + if (ranlib && ranlib->empty ()) // @@ BC LT [null]. ranlib = lookup (); const char* rl ( diff --git a/build2/dump.cxx b/build2/dump.cxx index 08700fc..7cb97ef 100644 --- a/build2/dump.cxx +++ b/build2/dump.cxx @@ -22,7 +22,7 @@ namespace build2 { // First print attributes if any. // - bool a (v.null () || (type && v.type != nullptr)); + bool a (!v || (type && v.type != nullptr)); if (a) os << '['; @@ -35,7 +35,7 @@ namespace build2 s = " "; } - if (v.null ()) + if (!v) { os << s << "null"; s = " "; @@ -46,7 +46,7 @@ namespace build2 // Now the value if there is one. // - if (!v.null ()) + if (v) { names storage; os << (a ? " " : "") << reverse (v, storage); diff --git a/build2/file.cxx b/build2/file.cxx index 9b3be0c..9ab01ce 100644 --- a/build2/file.cxx +++ b/build2/file.cxx @@ -659,7 +659,7 @@ namespace build2 // never set it to NULL). // auto l (root.vars["subprojects"]); - return l.defined () && (l->null () || l->type != nullptr); + return l.defined () && (l->null || l->type != nullptr); } void diff --git a/build2/parser.cxx b/build2/parser.cxx index 6b6c000..1987945 100644 --- a/build2/parser.cxx +++ b/build2/parser.cxx @@ -1093,7 +1093,7 @@ namespace build2 else attributes_pop (); - if (rhs.null ()) + if (!rhs) fail (t) << "null value in export"; export_value_ = move (rhs).as (); @@ -1342,22 +1342,22 @@ namespace build2 value tv; value_attributes (nullptr, tv, move (v), type::assign); - if (tv.null ()) - cout << "[null]" << endl; - else + if (tv) { names_type storage; cout << reverse (tv, storage) << endl; } + else + cout << "[null]" << endl; } else { attributes_pop (); - if (v.null ()) - cout << "[null]" << endl; - else + if (v) cout << v.as () << endl; + else + cout << "[null]" << endl; } if (tt != type::eos) @@ -1490,7 +1490,7 @@ namespace build2 if (k == "null") { - if (!rhs.empty ()) // Note: null means we had an expansion. + if (rhs && !rhs.empty ()) // Note: null means we had an expansion. fail (l) << "value with null attribute"; null = true; @@ -1637,7 +1637,7 @@ namespace build2 // this is. But for now ':' is always a scope/target qualified name // which we represent as a special ':'-style pair. // - if (lhs.type != nullptr || lhs.null () || lhs.empty ()) + if (lhs.type != nullptr || !lhs || lhs.empty ()) fail (l) << "scope/target expected before ':'"; names_type& ns (lhs.as ()); @@ -1647,7 +1647,7 @@ namespace build2 value rhs (eval_trailer (t, tt)); if (tt != type::rparen || - rhs.type != nullptr || rhs.null () || rhs.empty ()) + rhs.type != nullptr || !rhs || rhs.empty ()) fail (l) << "variable name expected after ':'"; ns.insert (ns.end (), @@ -2202,7 +2202,7 @@ namespace build2 expire_mode (); value v (eval (t, tt)); - if (v.null ()) + if (!v) fail (loc) << "null variable/function name"; names_type storage; @@ -2251,10 +2251,14 @@ namespace build2 value a (eval (t, tt)); cout << name << "("; - if (a.null ()) + if (a) + { + if (!a.empty ()) + cout << reverse (a, lv_storage); + } + else cout << "[null]"; - else if (!a.empty ()) - cout << reverse (a, lv_storage); + cout << ")" << endl; @@ -2264,7 +2268,7 @@ namespace build2 // See if we should propagate the NULL indicator. // - if (result.null ()) + if (!result) { if (set_null ()) null = true; @@ -2335,7 +2339,7 @@ namespace build2 // See if we should propagate the NULL indicator. // - if (result.null ()) + if (!result) { if (set_null ()) null = true; diff --git a/build2/variable b/build2/variable index 9473674..08d0020 100644 --- a/build2/variable +++ b/build2/variable @@ -54,9 +54,9 @@ namespace build2 // and is provided only for diagnostics. Return true if the resulting // value is not empty. // - bool (*const assign) (value&, names&&, const variable*); - bool (*const append) (value&, names&&, const variable*); - bool (*const prepend) (value&, names&&, const variable*); + void (*const assign) (value&, names&&, const variable*); + void (*const append) (value&, names&&, const variable*); + void (*const prepend) (value&, names&&, const variable*); // Reverse the value back to a vector of names. Storage can be used by the // implementation if necessary. Cannot be NULL. @@ -72,6 +72,10 @@ namespace build2 // If NULL, then the types are compared as PODs using memcmp(). // int (*const compare) (const value&, const value&); + + // If NULL, then the value is never empty. + // + bool (*const empty) (const value&); }; enum class variable_visibility @@ -117,29 +121,33 @@ namespace build2 typedef reference_wrapper variable_cref; - // value // - enum class value_state: uint8_t {null, empty, filled}; // Order is important. - + // class value { public: const value_type* type; // NULL means this value is not (yet) typed. - value_state state; + bool null; // Extra data that is associated with the value that can be used to store // flags, etc. It is initialized to 0 and copied (but not assigned) from // one value to another but is otherwise untouched (not even when the // value is reset to NULL). // + // Note: if deciding to use for something make sure it is not overlapping + // with an existing usage. + // uint16_t extra; - bool null () const {return state == value_state::null;} - bool empty () const {return state == value_state::empty;} + explicit operator bool () const {return !null;} + bool operator== (nullptr_t) const {return null;} + bool operator!= (nullptr_t) const {return !null;} - explicit operator bool () const {return !null ();} - bool operator== (nullptr_t) const {return null ();} - bool operator!= (nullptr_t) const {return !null ();} + // Check in a type-independent way if the value is empty. The value must + // not be NULL. + // + bool + empty () const; // Creation. A default-initialzied value is NULL and can be reset back to // NULL by assigning nullptr. Values can be copied and copy-assigned. Note @@ -151,8 +159,7 @@ namespace build2 ~value () {*this = nullptr;} explicit - value (const value_type* t = nullptr) - : type (t), state (value_state::null), extra (0) {} + value (const value_type* t = nullptr): type (t), null (true), extra (0) {} explicit value (names&&); // Create untyped value. @@ -160,7 +167,7 @@ namespace build2 // Note: preserves type. // value& - operator= (nullptr_t) {if (!null ()) reset (); return *this;} + operator= (nullptr_t) {if (!null) reset (); return *this;} value (value&&); explicit value (const value&); @@ -302,7 +309,7 @@ namespace build2 // Note: returns true if defined and not NULL. // - explicit operator bool () const {return defined () && !value->null ();} + explicit operator bool () const {return defined () && !value->null;} const value_type& operator* () const {return *value;} const value_type* operator-> () const {return value;} @@ -364,12 +371,12 @@ namespace build2 // // // static T convert (name&&, name* rhs); // - // // Assign/append/prepend T to value and return true if the result is - // // not empty. Value is already of type T but can be NULL. + // // Assign/append/prepend T to value which is already of type T but can + // // be NULL. // // - // static bool assign (value&, T&&); - // static bool append (value&, T&&); - // static bool prepend (value&, T&&); + // static void assign (value&, T&&); + // static void append (value&, T&&); + // static void prepend (value&, T&&); // // // Reverse a value back to name. Only needs to be provided by simple // // types. @@ -380,6 +387,10 @@ namespace build2 // // // static int compare (const T&, const T&); // + // // Return true if the value is empty. + // // + // static bool empty (const T&); + // // // For simple types (those that can be used as elements of containers), // // type_name must be constexpr in order to sidestep the static init // // order issue (in fact, that's the only reason we have it both here @@ -414,6 +425,13 @@ namespace build2 static void default_copy_assign (value&, const value&, bool); + // Default implementations of the empty callback that calls + // value_traits::empty(). + // + template + static bool + default_empty (const value&); + // Default implementations of the assign/append/prepend callbacks for simple // types. They call value_traits::convert() and then pass the result to // value_traits::assign()/append()/prepend(). As a result, it may not be @@ -422,15 +440,15 @@ namespace build2 // if false, then an empty value is not allowed. // template - static bool + static void simple_assign (value&, names&&, const variable*); template - static bool + static void simple_append (value&, names&&, const variable*); template - static bool + static void simple_prepend (value&, names&&, const variable*); // Default implementations of the reverse callback for simple types that @@ -456,8 +474,8 @@ namespace build2 static_assert (sizeof (bool) <= value::size_, "insufficient space"); static bool convert (name&&, name*); - static bool assign (value&, bool); - static bool append (value&, bool); // OR. + static void assign (value&, bool); + static void append (value&, bool); // OR. static name reverse (bool x) {return name (x ? "true" : "false");} static int compare (bool, bool); @@ -471,8 +489,8 @@ namespace build2 static_assert (sizeof (uint64_t) <= value::size_, "insufficient space"); static uint64_t convert (name&&, name*); - static bool assign (value&, uint64_t); - static bool append (value&, uint64_t); // ADD. + static void assign (value&, uint64_t); + static void append (value&, uint64_t); // ADD. static name reverse (uint64_t x) {return name (to_string (x));} static int compare (uint64_t, uint64_t); @@ -488,11 +506,12 @@ namespace build2 static_assert (sizeof (string) <= value::size_, "insufficient space"); static string convert (name&&, name*); - static bool assign (value&, string&&); - static bool append (value&, string&&); - static bool prepend (value&, string&&); + static void assign (value&, string&&); + static void append (value&, string&&); + static void prepend (value&, string&&); static name reverse (const string& x) {return name (x);} static int compare (const string&, const string&); + static bool empty (const string& x) {return x.empty ();} static const char* const type_name; static const build2::value_type value_type; @@ -506,11 +525,12 @@ namespace build2 static_assert (sizeof (path) <= value::size_, "insufficient space"); static path convert (name&&, name*); - static bool assign (value&, path&&); - static bool append (value&, path&&); // operator/ - static bool prepend (value&, path&&); // operator/ + static void assign (value&, path&&); + static void append (value&, path&&); // operator/ + static void prepend (value&, path&&); // operator/ static name reverse (const path& x) {return name (x.string ());} static int compare (const path&, const path&); + static bool empty (const path& x) {return x.empty ();} static const char* const type_name; static const build2::value_type value_type; @@ -524,11 +544,12 @@ namespace build2 static_assert (sizeof (dir_path) <= value::size_, "insufficient space"); static dir_path convert (name&&, name*); - static bool assign (value&, dir_path&&); - static bool append (value&, dir_path&&); // operator/ - static bool prepend (value&, dir_path&&); // operator/ + static void assign (value&, dir_path&&); + static void append (value&, dir_path&&); // operator/ + static void prepend (value&, dir_path&&); // operator/ static name reverse (const dir_path& x) {return name (x);} static int compare (const dir_path&, const dir_path&); + static bool empty (const dir_path& x) {return x.empty ();} static const char* const type_name; static const build2::value_type value_type; @@ -543,10 +564,11 @@ namespace build2 "insufficient space"); static abs_dir_path convert (name&&, name*); - static bool assign (value&, abs_dir_path&&); - static bool append (value&, abs_dir_path&&); // operator/ + static void assign (value&, abs_dir_path&&); + static void append (value&, abs_dir_path&&); // operator/ static name reverse (const abs_dir_path& x) {return name (x);} static int compare (const abs_dir_path&, const abs_dir_path&); + static bool empty (const abs_dir_path& x) {return x.empty ();} static const char* const type_name; static const build2::value_type value_type; @@ -560,11 +582,12 @@ namespace build2 static_assert (sizeof (name) <= value::size_, "insufficient space"); static name convert (name&&, name*); - static bool assign (value&, name&&); - static bool append (value&, name&&); - static bool prepend (value&, name&&); + static void assign (value&, name&&); + static void append (value&, name&&); + static void prepend (value&, name&&); static name reverse (const name& x) {return x;} static int compare (const name&, const name&); + static bool empty (const name& x) {return x.empty ();} static const char* const type_name; static const build2::value_type value_type; @@ -577,9 +600,10 @@ namespace build2 { static_assert (sizeof (vector) <= value::size_, "insufficient space"); - static bool assign (value&, vector&&); - static bool append (value&, vector&&); - static bool prepend (value&, vector&&); + static void assign (value&, vector&&); + static void append (value&, vector&&); + static void prepend (value&, vector&&); + static bool empty (const vector& x) {return x.empty ();} static const string type_name; static const build2::value_type value_type; @@ -594,10 +618,11 @@ namespace build2 static_assert (sizeof (map) <= value::size_, "insufficient space"); - static bool assign (value&, map&&); - static bool append (value&, map&&); - static bool prepend (value& v, map&& x) { + static void assign (value&, map&&); + static void append (value&, map&&); + static void prepend (value& v, map&& x) { return append (v, move (x));} + static bool empty (const map& x) {return x.empty ();} static const string type_name; static const build2::value_type value_type; diff --git a/build2/variable.cxx b/build2/variable.cxx index 78f9df8..7a333bb 100644 --- a/build2/variable.cxx +++ b/build2/variable.cxx @@ -22,14 +22,14 @@ namespace build2 else if (type->dtor != nullptr) type->dtor (*this); - state = value_state::null; + null = true; } value:: value (value&& v) - : type (v.type), state (v.state), extra (v.extra) + : type (v.type), null (v.null), extra (v.extra) { - if (!null ()) + if (!null) { if (type == nullptr) new (&data_) names (move (v).as ()); @@ -42,9 +42,9 @@ namespace build2 value:: value (const value& v) - : type (v.type), state (v.state), extra (v.extra) + : type (v.type), null (v.null), extra (v.extra) { - if (!null ()) + if (!null) { if (type == nullptr) new (&data_) names (v.as ()); @@ -73,21 +73,21 @@ namespace build2 // Now our types are the same. If the receiving value is NULL, then call // copy_ctor() instead of copy_assign(). // - if (!v.null ()) + if (v) { if (type == nullptr) { - if (null ()) + if (null) new (&data_) names (move (v).as ()); else as () = move (v).as (); } - else if (auto f = null () ? type->copy_ctor : type->copy_assign) + else if (auto f = null ? type->copy_ctor : type->copy_assign) f (*this, v, true); else data_ = v.data_; // Assign as POD. - state = v.state; + null = v.null; } else *this = nullptr; @@ -114,21 +114,21 @@ namespace build2 // Now our types are the same. If the receiving value is NULL, then call // copy_ctor() instead of copy_assign(). // - if (!v.null ()) + if (v) { if (type == nullptr) { - if (null ()) + if (null) new (&data_) names (v.as ()); else as () = v.as (); } - else if (auto f = null () ? type->copy_ctor : type->copy_assign) + else if (auto f = null ? type->copy_ctor : type->copy_assign) f (*this, v, false); else data_ = v.data_; // Assign as POD. - state = v.state; + null = v.null; } else *this = nullptr; @@ -142,54 +142,39 @@ namespace build2 { assert (type == nullptr || type->assign != nullptr); - bool r; - if (type == nullptr) { - names* p; - - if (null ()) - p = new (&data_) names (move (ns)); + if (null) + new (&data_) names (move (ns)); else - { - p = &as (); - *p = move (ns); - } - - r = !p->empty (); + as () = move (ns); } else - r = type->assign (*this, move (ns), var); + type->assign (*this, move (ns), var); - state = r ? value_state::filled : value_state::empty; + null = false; } void value:: append (names&& ns, const variable* var) { - bool r; - if (type == nullptr) { - names* p; - - if (null ()) - p = new (&data_) names (move (ns)); + if (null) + new (&data_) names (move (ns)); else { - p = &as (); + names& p (as ()); - if (p->empty ()) - *p = move (ns); + if (p.empty ()) + p = move (ns); else if (!ns.empty ()) { - p->insert (p->end (), - make_move_iterator (ns.begin ()), - make_move_iterator (ns.end ())); + p.insert (p.end (), + make_move_iterator (ns.begin ()), + make_move_iterator (ns.end ())); } } - - r = !p->empty (); } else { @@ -203,39 +188,33 @@ namespace build2 dr << " in variable " << var->name; } - r = type->append (*this, move (ns), var); + type->append (*this, move (ns), var); } - state = r ? value_state::filled : value_state::empty; + null = false; } void value:: prepend (names&& ns, const variable* var) { - bool r; - if (type == nullptr) { - names* p; - - if (null ()) - p = new (&data_) names (move (ns)); + if (null) + new (&data_) names (move (ns)); else { - p = &as (); + names& p (as ()); - if (p->empty ()) - *p = move (ns); + if (p.empty ()) + p = move (ns); else if (!ns.empty ()) { ns.insert (ns.end (), - make_move_iterator (p->begin ()), - make_move_iterator (p->end ())); - p->swap (ns); + make_move_iterator (p.begin ()), + make_move_iterator (p.end ())); + p.swap (ns); } } - - r = !p->empty (); } else { @@ -249,27 +228,24 @@ namespace build2 dr << " in variable " << var->name; } - r = type->prepend (*this, move (ns), var); + type->prepend (*this, move (ns), var); } - state = r ? value_state::filled : value_state::empty; + null = false; } bool operator== (const value& x, const value& y) { - bool xn (x.null ()); - bool yn (y.null ()); + bool xn (x.null); + bool yn (y.null); assert (x.type == y.type || (xn && x.type == nullptr) || (yn && y.type == nullptr)); - if (x.state != y.state) - return false; - - if (xn) - return true; // Both are NULL since same state. + if (xn || yn) + return xn == yn; if (x.type == nullptr) return x.as () == y.as (); @@ -283,25 +259,18 @@ namespace build2 bool operator< (const value& x, const value& y) { - bool xn (x.null ()); - bool yn (y.null ()); + bool xn (x.null); + bool yn (y.null); assert (x.type == y.type || (xn && x.type == nullptr) || (yn && y.type == nullptr)); - // NULL value is always less than non-NULL and we assume that empty - // value is always less than non-empty. - // - if (x.state < y.state) - return true; - else if (x.state > y.state) - return false; - else if (x.state != value_state::filled) // Both are NULL or empty. - return false; - - // Both are filled. + // NULL value is always less than non-NULL. // + if (xn || yn) + return xn > yn; // !xn < !yn + if (x.type == nullptr) return x.as () < y.as (); @@ -314,25 +283,18 @@ namespace build2 bool operator> (const value& x, const value& y) { - bool xn (x.null ()); - bool yn (y.null ()); + bool xn (x.null); + bool yn (y.null); assert (x.type == y.type || (xn && x.type == nullptr) || (yn && y.type == nullptr)); - // NULL value is always less than non-NULL and we assume that empty - // value is always less than non-empty. - // - if (x.state > y.state) - return true; - else if (x.state < y.state) - return false; - else if (x.state != value_state::filled) // Both are NULL or empty. - return false; - - // Both are filled. + // NULL value is always less than non-NULL. // + if (xn || yn) + return xn < yn; // !xn > !yn + if (x.type == nullptr) return x.as () > y.as (); @@ -347,7 +309,7 @@ namespace build2 { if (v.type == nullptr) { - if (!v.null ()) + if (v) { // Note: the order in which we do things here is important. // @@ -410,7 +372,8 @@ namespace build2 &simple_append, // Prepend same as append. &simple_reverse, nullptr, // No cast (cast data_ directly). - nullptr // No compare (compare as POD). + nullptr, // No compare (compare as POD). + nullptr // Never empty. }; // uint64_t value @@ -450,7 +413,8 @@ namespace build2 &simple_append, // Prepend same as append. &simple_reverse, nullptr, // No cast (cast data_ directly). - nullptr // No compare (compare as POD). + nullptr, // No compare (compare as POD). + nullptr // Never empty. }; // string value @@ -536,7 +500,8 @@ namespace build2 &simple_prepend, &simple_reverse, nullptr, // No cast (cast data_ directly). - &simple_compare + &simple_compare, + &default_empty }; // path value @@ -581,7 +546,8 @@ namespace build2 &simple_prepend, &simple_reverse, nullptr, // No cast (cast data_ directly). - &simple_compare + &simple_compare, + &default_empty }; // dir_path value @@ -624,7 +590,8 @@ namespace build2 &simple_prepend, &simple_reverse, nullptr, // No cast (cast data_ directly). - &simple_compare + &simple_compare, + &default_empty }; // abs_dir_path value @@ -657,7 +624,8 @@ namespace build2 nullptr, // No prepend. &simple_reverse, nullptr, // No cast (cast data_ directly). - &simple_compare + &simple_compare, + &default_empty }; // name value @@ -692,7 +660,8 @@ namespace build2 nullptr, // Prepend not supported. &name_reverse, nullptr, // No cast (cast data_ directly). - &simple_compare + &simple_compare, + &default_empty }; // variable_pool diff --git a/build2/variable.ixx b/build2/variable.ixx index e7d5654..6b59c72 100644 --- a/build2/variable.ixx +++ b/build2/variable.ixx @@ -8,11 +8,17 @@ namespace build2 { // value // + inline bool value:: + empty () const + { + assert (!null); + return type == nullptr ? as ().empty () : + type->empty == nullptr ? false : type->empty (*this); + } + inline value:: value (names&& ns) - : type (nullptr), - state (ns.empty () ? value_state::empty : value_state::filled), - extra (0) + : type (nullptr), null (false), extra (0) { new (&data_) names (move (ns)); } @@ -43,10 +49,8 @@ namespace build2 type = &value_traits::value_type; } - state = value_traits::assign (*this, move (v)) - ? value_state::filled - : value_state::empty; - + value_traits::assign (*this, move (v)); + null = false; return *this; } @@ -54,18 +58,15 @@ namespace build2 inline value& value:: operator+= (T v) { - assert (type == &value_traits::value_type || - (type == nullptr && null ())); + assert (type == &value_traits::value_type || (type == nullptr && null)); // Prepare the receiving value. // if (type == nullptr) type = &value_traits::value_type; - state = value_traits::append (*this, move (v)) - ? value_state::filled - : value_state::empty; - + value_traits::append (*this, move (v)); + null = false; return *this; } @@ -94,7 +95,7 @@ namespace build2 { // Note that it can still be a typed vector. // - assert (!v.null () && + assert (v && (v.type == nullptr || v.type == &value_traits::value_type)); return v.as (); } @@ -103,7 +104,7 @@ namespace build2 inline names& cast (value& v) { - assert (!v.null () && + assert (v && (v.type == nullptr || v.type == &value_traits::value_type)); return v.as (); } @@ -112,7 +113,7 @@ namespace build2 inline const T& cast (const value& v) { - assert (!v.null ()); + assert (v); // Find base if any. // @@ -129,7 +130,7 @@ namespace build2 inline T& cast (value& v) { - assert (!v.null () && v.type == &value_traits::value_type); + assert (v && v.type == &value_traits::value_type); return *static_cast (v.type->cast == nullptr ? static_cast (&v.data_) : const_cast (v.type->cast (v, v.type))); @@ -191,7 +192,7 @@ namespace build2 inline names_view reverse (const value& v, names& storage) { - assert (!v.null () && + assert (v && storage.empty () && (v.type == nullptr || v.type->reverse != nullptr)); return v.type == nullptr ? v.as () : v.type->reverse (v, storage); @@ -222,28 +223,25 @@ namespace build2 // bool value // - inline bool value_traits:: + inline void value_traits:: assign (value& v, bool x) { - if (v.null ()) - new (&v.data_) bool (x); - else + if (v) v.as () = x; + else + new (&v.data_) bool (x); - return true; } - inline bool value_traits:: + inline void value_traits:: append (value& v, bool x) { // Logical OR. // - if (v.null ()) - new (&v.data_) bool (x); - else + if (v) v.as () = v.as () || x; - - return true; + else + new (&v.data_) bool (x); } inline int value_traits:: @@ -254,28 +252,24 @@ namespace build2 // uint64_t value // - inline bool value_traits:: + inline void value_traits:: assign (value& v, uint64_t x) { - if (v.null ()) - new (&v.data_) uint64_t (x); - else + if (v) v.as () = x; - - return true; + else + new (&v.data_) uint64_t (x); } - inline bool value_traits:: + inline void value_traits:: append (value& v, uint64_t x) { // ADD. // - if (v.null ()) - new (&v.data_) uint64_t (x); - else + if (v) v.as () += x; - - return true; + else + new (&v.data_) uint64_t (x); } inline int value_traits:: @@ -286,57 +280,45 @@ namespace build2 // string value // - inline bool value_traits:: + inline void value_traits:: assign (value& v, string&& x) { - string* p; - - if (v.null ()) - p = new (&v.data_) string (move (x)); + if (v) + v.as () = move (x); else - p = &(v.as () = move (x)); - - return !p->empty (); + new (&v.data_) string (move (x)); } - inline bool value_traits:: + inline void value_traits:: append (value& v, string&& x) { - string* p; - - if (v.null ()) - p = new (&v.data_) string (move (x)); - else + if (v) { - p = &v.as (); + string& s (v.as ()); - if (p->empty ()) - p->swap (x); + if (s.empty ()) + s.swap (x); else - *p += x; + s += x; } - - return !p->empty (); + else + new (&v.data_) string (move (x)); } - inline bool value_traits:: + inline void value_traits:: prepend (value& v, string&& x) { - string* p; - - if (v.null ()) - p = new (&v.data_) string (move (x)); - else + if (v) { - p = &v.as (); + string& s (v.as ()); - if (!p->empty ()) - x += *p; + if (!s.empty ()) + x += s; - p->swap (x); + s.swap (x); } - - return !p->empty (); + else + new (&v.data_) string (move (x)); } inline int value_traits:: @@ -347,57 +329,45 @@ namespace build2 // path value // - inline bool value_traits:: + inline void value_traits:: assign (value& v, path&& x) { - path* p; - - if (v.null ()) - p = new (&v.data_) path (move (x)); + if (v) + v.as () = move (x); else - p = &(v.as () = move (x)); - - return !p->empty (); + new (&v.data_) path (move (x)); } - inline bool value_traits:: + inline void value_traits:: append (value& v, path&& x) { - path* p; - - if (v.null ()) - p = new (&v.data_) path (move (x)); - else + if (v) { - p = &v.as (); + path& p (v.as ()); - if (p->empty ()) - p->swap (x); + if (p.empty ()) + p.swap (x); else - *p /= x; + p /= x; } - - return !p->empty (); + else + new (&v.data_) path (move (x)); } - inline bool value_traits:: + inline void value_traits:: prepend (value& v, path&& x) { - path* p; - - if (v.null ()) - p = new (&v.data_) path (move (x)); - else + if (v) { - p = &v.as (); + path& p (v.as ()); - if (!p->empty ()) - x /= *p; + if (!p.empty ()) + x /= p; - p->swap (x); + p.swap (x); } - - return !p->empty (); + else + new (&v.data_) path (move (x)); } inline int value_traits:: @@ -408,57 +378,45 @@ namespace build2 // dir_path value // - inline bool value_traits:: + inline void value_traits:: assign (value& v, dir_path&& x) { - dir_path* p; - - if (v.null ()) - p = new (&v.data_) dir_path (move (x)); + if (v) + v.as () = move (x); else - p = &(v.as () = move (x)); - - return !p->empty (); + new (&v.data_) dir_path (move (x)); } - inline bool value_traits:: + inline void value_traits:: append (value& v, dir_path&& x) { - dir_path* p; - - if (v.null ()) - p = new (&v.data_) dir_path (move (x)); - else + if (v) { - p = &v.as (); + dir_path& p (v.as ()); - if (p->empty ()) - p->swap (x); + if (p.empty ()) + p.swap (x); else - *p /= x; + p /= x; } - - return !p->empty (); + else + new (&v.data_) dir_path (move (x)); } - inline bool value_traits:: + inline void value_traits:: prepend (value& v, dir_path&& x) { - dir_path* p; - - if (v.null ()) - p = new (&v.data_) dir_path (move (x)); - else + if (v) { - p = &v.as (); + dir_path& p (v.as ()); - if (!p->empty ()) - x /= *p; + if (!p.empty ()) + x /= p; - p->swap (x); + p.swap (x); } - - return !p->empty (); + else + new (&v.data_) dir_path (move (x)); } inline int value_traits:: @@ -469,37 +427,29 @@ namespace build2 // abs_dir_path value // - inline bool value_traits:: + inline void value_traits:: assign (value& v, abs_dir_path&& x) { - abs_dir_path* p; - - if (v.null ()) - p = new (&v.data_) abs_dir_path (move (x)); + if (v) + v.as () = move (x); else - p = &(v.as () = move (x)); - - return !p->empty (); + new (&v.data_) abs_dir_path (move (x)); } - inline bool value_traits:: + inline void value_traits:: append (value& v, abs_dir_path&& x) { - abs_dir_path* p; - - if (v.null ()) - p = new (&v.data_) abs_dir_path (move (x)); - else + if (v) { - p = &v.as (); + abs_dir_path& p (v.as ()); - if (p->empty ()) - p->swap (x); + if (p.empty ()) + p.swap (x); else - *p /= x; + p /= x; } - - return !p->empty (); + else + new (&v.data_) abs_dir_path (move (x)); } inline int value_traits:: @@ -510,17 +460,13 @@ namespace build2 // name value // - inline bool value_traits:: + inline void value_traits:: assign (value& v, name&& x) { - name* p; - - if (v.null ()) - p = new (&v.data_) name (move (x)); + if (v) + v.as () = move (x); else - p = &(v.as () = move (x)); - - return !p->empty (); + new (&v.data_) name (move (x)); } inline int value_traits:: @@ -532,105 +478,85 @@ namespace build2 // vector value // template - inline bool value_traits>:: + inline void value_traits>:: assign (value& v, vector&& x) { - vector* p; - - if (v.null ()) - p = new (&v.data_) vector (move (x)); + if (v) + v.as> () = move (x); else - p = &(v.as> () = move (x)); - - return !p->empty (); + new (&v.data_) vector (move (x)); } template - inline bool value_traits>:: + inline void value_traits>:: append (value& v, vector&& x) { - vector* p; - - if (v.null ()) - p = new (&v.data_) vector (move (x)); - else + if (v) { - p = &v.as> (); + vector& p (v.as> ()); - if (p->empty ()) - p->swap (x); + if (p.empty ()) + p.swap (x); else - p->insert (p->end (), - make_move_iterator (x.begin ()), - make_move_iterator (x.end ())); + p.insert (p.end (), + make_move_iterator (x.begin ()), + make_move_iterator (x.end ())); } - - return !p->empty (); + else + new (&v.data_) vector (move (x)); } template - inline bool value_traits>:: + inline void value_traits>:: prepend (value& v, vector&& x) { - vector* p; - - if (v.null ()) - p = new (&v.data_) vector (move (x)); - else + if (v) { - p = &v.as> (); + vector& p (v.as> ()); - if (!p->empty ()) + if (!p.empty ()) x.insert (x.end (), - make_move_iterator (p->begin ()), - make_move_iterator (p->end ())); + make_move_iterator (p.begin ()), + make_move_iterator (p.end ())); - p->swap (x); + p.swap (x); } - - return !p->empty (); + else + new (&v.data_) vector (move (x)); } // map value // template - inline bool value_traits>:: + inline void value_traits>:: assign (value& v, map&& x) { - map* p; - - if (v.null ()) - p = new (&v.data_) map (move (x)); + if (v) + v.as> () = move (x); else - p = &(v.as> () = move (x)); - - return !p->empty (); + new (&v.data_) map (move (x)); } template - inline bool value_traits>:: + inline void value_traits>:: append (value& v, map&& x) { - map* p; - - if (v.null ()) - p = new (&v.data_) map (move (x)); - else + if (v) { - p = &v.as> (); + map& m (v.as> ()); - if (p->empty ()) - p->swap (x); + if (m.empty ()) + m.swap (x); else // Note that this will only move values. Keys (being const) are still // copied. // - p->insert (p->end (), - make_move_iterator (x.begin ()), - make_move_iterator (x.end ())); + m.insert (m.end (), + make_move_iterator (x.begin ()), + make_move_iterator (x.end ())); } - - return !p->empty (); + else + new (&v.data_) map (move (x)); } // variable_pool diff --git a/build2/variable.txx b/build2/variable.txx index a86a936..f1335b4 100644 --- a/build2/variable.txx +++ b/build2/variable.txx @@ -35,8 +35,15 @@ namespace build2 l.as () = r.as (); } - template + template bool + default_empty (const value& v) + { + return value_traits::empty (v.as ()); + } + + template + void simple_assign (value& v, names&& ns, const variable* var) { size_t n (ns.size ()); @@ -45,11 +52,13 @@ namespace build2 { try { - return value_traits::assign ( + value_traits::assign ( v, (n == 0 ? T () : value_traits::convert (move (ns.front ()), nullptr))); + + return; } catch (const invalid_argument&) {} // Fall through. } @@ -68,7 +77,7 @@ namespace build2 } template - bool + void simple_append (value& v, names&& ns, const variable* var) { size_t n (ns.size ()); @@ -77,11 +86,13 @@ namespace build2 { try { - return value_traits::append ( + value_traits::append ( v, (n == 0 ? T () : value_traits::convert (move (ns.front ()), nullptr))); + + return; } catch (const invalid_argument&) {} // Fall through. } @@ -100,7 +111,7 @@ namespace build2 } template - bool + void simple_prepend (value& v, names&& ns, const variable* var) { size_t n (ns.size ()); @@ -109,11 +120,13 @@ namespace build2 { try { - return value_traits::prepend ( + value_traits::prepend ( v, (n == 0 ? T () : value_traits::convert (move (ns.front ()), nullptr))); + + return; } catch (const invalid_argument&) {} // Fall through. } @@ -150,12 +163,12 @@ namespace build2 // template - bool + void vector_append (value& v, names&& ns, const variable* var) { - vector* p (v.null () - ? new (&v.data_) vector () - : &v.as> ()); + vector& p (v + ? v.as> () + : *new (&v.data_) vector ()); // Convert each element to T while merging pairs. // @@ -183,7 +196,7 @@ namespace build2 try { - p->push_back (value_traits::convert (move (n), r)); + p.push_back (value_traits::convert (move (n), r)); } catch (const invalid_argument&) { @@ -200,22 +213,20 @@ namespace build2 dr << " in variable " << var->name; } } - - return !p->empty (); } template - bool + void vector_assign (value& v, names&& ns, const variable* var) { - if (!v.null ()) + if (v) v.as> ().clear (); - return vector_append (v, move (ns), var); + vector_append (v, move (ns), var); } template - bool + void vector_prepend (value& v, names&& ns, const variable* var) { // Reduce to append. @@ -223,21 +234,19 @@ namespace build2 vector t; vector* p; - if (v.null ()) - p = new (&v.data_) vector (); - else + if (v) { p = &v.as> (); p->swap (t); } + else + p = new (&v.data_) vector (); vector_append (v, move (ns), var); p->insert (p->end (), make_move_iterator (t.begin ()), make_move_iterator (t.end ())); - - return !p->empty (); } template @@ -294,20 +303,21 @@ namespace build2 &vector_prepend, &vector_reverse, nullptr, // No cast (cast data_ directly). - &vector_compare + &vector_compare, + &default_empty> }; // map value // template - bool + void map_append (value& v, names&& ns, const variable* var) { using std::map; - map* p (v.null () - ? new (&v.data_) map () - : &v.as> ()); + map& p (v + ? v.as> () + : *new (&v.data_) map ()); // Verify we have a sequence of pairs and convert each lhs/rhs to K/V. // @@ -348,7 +358,7 @@ namespace build2 { V v (value_traits::convert (move (r), nullptr)); - p->emplace (move (k), move (v)); + p.emplace (move (k), move (v)); } catch (const invalid_argument&) { @@ -372,20 +382,18 @@ namespace build2 dr << " in variable " << var->name; } } - - return !p->empty (); } template - bool + void map_assign (value& v, names&& ns, const variable* var) { using std::map; - if (!v.null ()) + if (v) v.as> ().clear (); - return map_append (v, move (ns), var); + map_append (v, move (ns), var); } template @@ -455,6 +463,7 @@ namespace build2 &map_append, // Prepend is the same as append. &map_reverse, nullptr, // No cast (cast data_ directly). - &map_compare + &map_compare, + &default_empty> }; } -- cgit v1.1