From 2cccbe9150669f9df00f439b8db03054a97ed4bb Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 14 Oct 2016 14:59:35 +0200 Subject: Implement auxiliary data storage pad in target --- build2/target | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 70 insertions(+), 3 deletions(-) (limited to 'build2/target') diff --git a/build2/target b/build2/target index 8fc0e8c..3123905 100644 --- a/build2/target +++ b/build2/target @@ -6,7 +6,7 @@ #define BUILD2_TARGET #include // tags, etc. -#include +#include // aligned_storage #include #include // map_iterator_adapter @@ -251,7 +251,7 @@ namespace build2 public: virtual - ~target () = default; + ~target (); target (const target&) = delete; target& operator= (const target&) = delete; @@ -260,7 +260,7 @@ namespace build2 : dir (move (d)), out (move (o)), name (move (n)), ext (e) {} // Reset the target before matching it to a rule. The default - // implementation clears prerequisite_targets. + // implementation clears the auxilary data and prerequisite_targets. // virtual void reset (action_type); @@ -457,6 +457,73 @@ namespace build2 // size_t dependents; + // Auxilary data storage. + // + public: + // A rule that matches (i.e., returns true from its match() function) may + // use this pad to pass data between its match and apply functions as well + // as the recipe. After the recipe is executed, the data is destroyed by + // calling data_dtor (if not NULL). The rule should static assert that the + // size of the pad is sufficient for its needs. + // + // Note also that normally at least 2 extra pointers may be stored without + // a dynamic allocation in the returned recipe (small object optimization + // in std::function). So if you need to pass data only between apply() and + // the recipe, then this might be a more convenient way. + // + // 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 pad. + // + // Currenly the data is not destroyed until the next match. + // + std::aligned_storage::type data_pad; + void (*data_dtor) (void*) = nullptr; + + // VC 14 needs decltype. + // + static const size_t data_size = sizeof (decltype (data_pad)); + + template ::type>::type> + typename std::enable_if::value,T&>::type + data (R&& d) + { + assert (sizeof (T) <= data_size && data_dtor == nullptr); + return *new (&data_pad) T (forward (d)); + } + + template ::type>::type> + typename std::enable_if::value,T&>::type + data (R&& d) + { + assert (sizeof (T) <= data_size && data_dtor == nullptr); + T& r (*new (&data_pad) T (forward (d))); + data_dtor = [] (void* p) {static_cast (p)->~T ();}; + return r; + } + + template + T& + data () {return *reinterpret_cast (&data_pad);} + + template + const T& + data () const {return *reinterpret_cast (&data_pad);} + + void + clear_data () + { + if (data_dtor != nullptr) + { + data_dtor (&data_pad); + data_dtor = nullptr; + } + } + public: action_type action; // Action this recipe is for. -- cgit v1.1