diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2017-02-15 03:55:15 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2017-03-02 14:03:34 +0200 |
commit | b37f1aa6398065be806e6605a023189685669885 (patch) | |
tree | b9b32091e3d70a31852302b24c99ecb62465464a /build2/diagnostics | |
parent | a64b2ae2099346471ead988d5f2d383d55a9bf89 (diff) |
Implement parallel match
Diffstat (limited to 'build2/diagnostics')
-rw-r--r-- | build2/diagnostics | 78 |
1 files changed, 74 insertions, 4 deletions
diff --git a/build2/diagnostics b/build2/diagnostics index dff1bd6..b889fd4 100644 --- a/build2/diagnostics +++ b/build2/diagnostics @@ -113,6 +113,70 @@ namespace build2 using butl::diag_stream; using butl::diag_epilogue; + // Diagnostics stack. Each frame is "applied" to the fail/error/warn/info + // diag record. + // + // Unfortunately most of our use-cases don't fit into the 2-pointer small + // object optimization of std::function. So we have to complicate things + // a bit here. + // + struct diag_frame + { + explicit + diag_frame (void (*f) (const diag_frame&, const diag_record&)) + : func_ (f), prev_ (stack) {stack = this;} + + // Start with an existing stack, for example, from another thread. + // + explicit + diag_frame (const diag_frame* prev) + : prev_ (stack) {stack = prev;} // Just a restore guard. + + static void + apply (const diag_record& r) + { + for (const diag_frame* f (stack); f != nullptr; f = f->prev_) + f->func_ (*f, r); + } + + ~diag_frame () {stack = prev_;} + + static +#ifdef __cpp_thread_local + thread_local +#else + __thread +#endif + const diag_frame* stack; // Tip of the stack. + + private: + void (*func_) (const diag_frame&, const diag_record&); + const diag_frame* prev_; + }; + + template <typename F> + struct diag_frame_impl: diag_frame + { + explicit + diag_frame_impl (F f): diag_frame (&thunk), func_ (move (f)) {} + + private: + static void + thunk (const diag_frame& f, const diag_record& r) + { + static_cast<const diag_frame_impl&> (f).func_ (r); + } + + const F func_; + }; + + template <typename F> + inline diag_frame_impl<F> + make_diag_frame (F f) + { + return diag_frame_impl<F> (move (f)); + } + // Diagnostic facility, project specifics. // struct simple_prologue_base @@ -179,11 +243,11 @@ namespace build2 explicit basic_mark_base (const char* type, + diag_epilogue* epilogue = &diag_frame::apply, uint16_t (*sverb) () = &stream_verb_map, const char* mod = nullptr, const char* name = nullptr, - const void* data = nullptr, - diag_epilogue* epilogue = nullptr) + const void* data = nullptr) : sverb_ (sverb), type_ (type), mod_ (mod), name_ (name), data_ (data), epilogue_ (epilogue) {} @@ -235,6 +299,7 @@ namespace build2 const char* name, const void* data = nullptr) : basic_mark_base ("trace", + nullptr, // No diag stack. []() {return stream_verb_max;}, mod, name, @@ -251,11 +316,16 @@ namespace build2 fail_mark_base (const char* type, const void* data = nullptr) : basic_mark_base (type, + [](const diag_record& r) + { + diag_frame::apply (r); + r.flush (); + throw failed (); + }, &stream_verb_map, nullptr, nullptr, - data, - [](const diag_record&) {throw failed ();}) {} + data) {} }; using fail_mark = butl::diag_mark<fail_mark_base>; |