From 9b138ccbebdcdc6bfdd6f6d52e534ae14df280af Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 20 Apr 2022 10:55:50 +0200 Subject: Replace match_extra::buffer with more general data storage facility --- libbuild2/target.hxx | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 2 deletions(-) (limited to 'libbuild2/target.hxx') diff --git a/libbuild2/target.hxx b/libbuild2/target.hxx index 563c264..bf8c4fe 100644 --- a/libbuild2/target.hxx +++ b/libbuild2/target.hxx @@ -145,8 +145,70 @@ namespace build2 // struct match_extra { - bool fallback; // True if matching a fallback rule (see match_rule()). - string buffer; // Auxiliary buffer that's reused during match/apply. + bool fallback; // True if matching a fallback rule (see match_rule()). + + // Auxiliary data storage. + // + // A rule (whether matches or not) may use this pad to pass data between + // its match and apply functions (but not the recipe). The rule should + // static assert that the size of the pad is sufficient for its needs. + // + // This facility is complementary to the auxiliary data storage in target: + // it can store slightly more/extra data without dynamic memory allocation + // but can only be used during match/apply. + // + // Note also that a rule that delegates to another rule may not be able to + // use this mechanism fully since the delegated-to rule may also need the + // data storage. + // + static constexpr size_t data_size = (sizeof (string) > sizeof (void*) * 4 + ? sizeof (string) + : sizeof (void*) * 4); + + std::aligned_storage::type data_; + void (*data_dtor_) (void*) = nullptr; + + template ::type>::type> + typename std::enable_if::value,T&>::type + data (R&& d) + { + assert (sizeof (T) <= data_size); + clear_data (); + return *new (&data_) T (forward (d)); + } + + template ::type>::type> + typename std::enable_if::value,T&>::type + data (R&& d) + { + assert (sizeof (T) <= data_size); + clear_data (); + T& r (*new (&data_) T (forward (d))); + data_dtor_ = [] (void* p) {static_cast (p)->~T ();}; + return r; + } + + template + T& + data () {return *reinterpret_cast (&data_);} + + template + const T& + data () const {return *reinterpret_cast (&data_);} + + void + clear_data () + { + if (data_dtor_ != nullptr) + { + data_dtor_ (&data_); + data_dtor_ = nullptr; + } + } // Implementation details. // @@ -840,6 +902,8 @@ namespace build2 // } // }; // + // Note: see also similar facility in match_extra. + // // After the recipe is executed, the recipe/data is destroyed, unless // explicitly requested not to (see below). The rule may static assert // that the small size of the storage (which doesn't require dynamic -- cgit v1.1