diff options
Diffstat (limited to 'include/lldb/Utility')
-rw-r--r-- | include/lldb/Utility/AnsiTerminal.h | 9 | ||||
-rw-r--r-- | include/lldb/Utility/Either.h | 154 | ||||
-rw-r--r-- | include/lldb/Utility/Iterable.h | 25 | ||||
-rw-r--r-- | include/lldb/Utility/JSON.h | 127 | ||||
-rw-r--r-- | include/lldb/Utility/ProcessStructReader.h | 8 | ||||
-rw-r--r-- | include/lldb/Utility/PseudoTerminal.h | 2 | ||||
-rw-r--r-- | include/lldb/Utility/PythonPointer.h | 73 | ||||
-rw-r--r-- | include/lldb/Utility/SharedCluster.h | 6 | ||||
-rw-r--r-- | include/lldb/Utility/SharingPtr.h | 79 | ||||
-rw-r--r-- | include/lldb/Utility/StringExtractor.h | 3 | ||||
-rw-r--r-- | include/lldb/Utility/TaskPool.h | 221 |
11 files changed, 528 insertions, 179 deletions
diff --git a/include/lldb/Utility/AnsiTerminal.h b/include/lldb/Utility/AnsiTerminal.h index 9a5117a..a43dd1b 100644 --- a/include/lldb/Utility/AnsiTerminal.h +++ b/include/lldb/Utility/AnsiTerminal.h @@ -41,8 +41,13 @@ #define ANSI_CTRL_CONCEAL 8 #define ANSI_CTRL_CROSSED_OUT 9 -#define ANSI_ESC_START "\033[" -#define ANSI_ESC_END "m" +#define ANSI_ESC_START "\033[" +#define ANSI_ESC_END "m" + +#define ANSI_STR(s) #s +#define ANSI_DEF_STR(s) ANSI_STR(s) + +#define ANSI_ESCAPE1(s) ANSI_ESC_START ANSI_DEF_STR(s) ANSI_ESC_END #define ANSI_1_CTRL(ctrl1) "\033["##ctrl1 ANSI_ESC_END #define ANSI_2_CTRL(ctrl1,ctrl2) "\033["##ctrl1";"##ctrl2 ANSI_ESC_END diff --git a/include/lldb/Utility/Either.h b/include/lldb/Utility/Either.h new file mode 100644 index 0000000..ae64736 --- /dev/null +++ b/include/lldb/Utility/Either.h @@ -0,0 +1,154 @@ +//===-- Either.h -----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_Either_h_ +#define liblldb_Either_h_ + +#include "llvm/ADT/Optional.h" + +#include <functional> + +namespace lldb_utility { + template <typename T1, typename T2> + class Either + { + private: + enum class Selected + { + One, Two + }; + + Selected m_selected; + union + { + T1 m_t1; + T2 m_t2; + }; + + public: + Either (const T1& t1) + { + m_t1 = t1; + m_selected = Selected::One; + } + + Either (const T2& t2) + { + m_t2 = t2; + m_selected = Selected::Two; + } + + Either (const Either<T1,T2>& rhs) + { + switch (rhs.m_selected) + { + case Selected::One: + m_t1 = rhs.GetAs<T1>().getValue(); + m_selected = Selected::One; + break; + case Selected::Two: + m_t2 = rhs.GetAs<T2>().getValue(); + m_selected = Selected::Two; + break; + } + } + + template <class X, typename std::enable_if<std::is_same<T1,X>::value>::type * = nullptr> + llvm::Optional<T1> + GetAs() const + { + switch (m_selected) + { + case Selected::One: + return m_t1; + default: + return llvm::Optional<T1>(); + } + } + + template <class X, typename std::enable_if<std::is_same<T2,X>::value>::type * = nullptr> + llvm::Optional<T2> + GetAs() const + { + switch (m_selected) + { + case Selected::Two: + return m_t2; + default: + return llvm::Optional<T2>(); + } + } + + template <class ResultType> + ResultType + Apply (std::function<ResultType(T1)> if_T1, + std::function<ResultType(T2)> if_T2) const + { + switch (m_selected) + { + case Selected::One: + return if_T1(m_t1); + case Selected::Two: + return if_T2(m_t2); + } + } + + bool + operator == (const Either<T1,T2>& rhs) + { + return (GetAs<T1>() == rhs.GetAs<T1>()) && (GetAs<T2>() == rhs.GetAs<T2>()); + } + + explicit + operator bool () + { + switch (m_selected) + { + case Selected::One: + return (bool)m_t1; + case Selected::Two: + return (bool)m_t2; + } + } + + Either<T1,T2>& + operator = (const Either<T1,T2>& rhs) + { + switch (rhs.m_selected) + { + case Selected::One: + m_t1 = rhs.GetAs<T1>().getValue(); + m_selected = Selected::One; + break; + case Selected::Two: + m_t2 = rhs.GetAs<T2>().getValue(); + m_selected = Selected::Two; + break; + } + return *this; + } + + ~Either () + { + switch (m_selected) + { + case Selected::One: + m_t1.T1::~T1(); + break; + case Selected::Two: + m_t2.T2::~T2(); + break; + } + } + }; + +} // namespace lldb_utility + +#endif // #ifndef liblldb_Either_h_ + diff --git a/include/lldb/Utility/Iterable.h b/include/lldb/Utility/Iterable.h index 17c8cf4..2317225 100644 --- a/include/lldb/Utility/Iterable.h +++ b/include/lldb/Utility/Iterable.h @@ -10,6 +10,12 @@ #ifndef liblldb_Iterable_h_ #define liblldb_Iterable_h_ +// C Includes +// C++ Includes +#include <utility> + +// Other libraries and framework includes +// Project includes #include "lldb/Host/Mutex.h" namespace lldb_private @@ -34,9 +40,7 @@ template <typename C, typename E, E (*A)(typename C::const_iterator &)> class Ad { public: typedef typename C::const_iterator BackingIterator; -private: - BackingIterator m_iter; -public: + // Wrapping constructor AdaptedConstIterator (BackingIterator backing_iterator) : m_iter(backing_iterator) @@ -63,7 +67,7 @@ public: } // Destructible - ~AdaptedConstIterator () { } + ~AdaptedConstIterator() = default; // Comparable bool operator== (const AdaptedConstIterator &rhs) @@ -160,6 +164,9 @@ public: template <typename C1, typename E1, E1 (*A1)(typename C1::const_iterator &)> friend void swap(AdaptedConstIterator<C1, E1, A1> &, AdaptedConstIterator<C1, E1, A1> &); + +private: + BackingIterator m_iter; }; template <typename C, typename E, E (*A)(typename C::const_iterator &)> @@ -203,8 +210,6 @@ public: template <typename C, typename E, E (*A)(typename C::const_iterator &)> class LockingAdaptedIterable : public AdaptedIterable<C, E, A> { -private: - Mutex *m_mutex = nullptr; public: LockingAdaptedIterable (C &container, Mutex &mutex) : AdaptedIterable<C,E,A>(container), @@ -217,7 +222,7 @@ public: AdaptedIterable<C,E,A>(rhs), m_mutex(rhs.m_mutex) { - rhs.m_mutex = NULL; + rhs.m_mutex = nullptr; } ~LockingAdaptedIterable () @@ -227,9 +232,11 @@ public: } private: + Mutex *m_mutex = nullptr; + DISALLOW_COPY_AND_ASSIGN(LockingAdaptedIterable); }; -} +} // namespace lldb_private -#endif +#endif // liblldb_Iterable_h_ diff --git a/include/lldb/Utility/JSON.h b/include/lldb/Utility/JSON.h index da5e26d..e61c5ee 100644 --- a/include/lldb/Utility/JSON.h +++ b/include/lldb/Utility/JSON.h @@ -71,8 +71,8 @@ namespace lldb_private { JSONString& operator = (const JSONString& s) = delete; - virtual void - Write (Stream& s); + void + Write(Stream& s) override; typedef std::shared_ptr<JSONString> SP; @@ -84,8 +84,7 @@ namespace lldb_private { return V->GetKind() == JSONValue::Kind::String; } - virtual - ~JSONString () = default; + ~JSONString() override = default; private: @@ -98,43 +97,79 @@ namespace lldb_private { class JSONNumber : public JSONValue { public: - JSONNumber (); - explicit JSONNumber (uint64_t i); - explicit JSONNumber (double d); + typedef std::shared_ptr<JSONNumber> SP; + + // We cretae a constructor for all integer and floating point type with using templates and + // SFINAE to avoid having ambiguous overloads because of the implicit type promotion. If we + // would have constructors only with int64_t, uint64_t and double types then constructing a + // JSONNumber from an int32_t (or any other similar type) would fail to compile. + + template <typename T, + typename std::enable_if<std::is_integral<T>::value && + std::is_unsigned<T>::value>::type* = nullptr> + explicit JSONNumber (T u) : + JSONValue(JSONValue::Kind::Number), + m_data_type(DataType::Unsigned) + { + m_data.m_unsigned = u; + } + + template <typename T, + typename std::enable_if<std::is_integral<T>::value && + std::is_signed<T>::value>::type* = nullptr> + explicit JSONNumber (T s) : + JSONValue(JSONValue::Kind::Number), + m_data_type(DataType::Signed) + { + m_data.m_signed = s; + } + + template <typename T, + typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr> + explicit JSONNumber (T d) : + JSONValue(JSONValue::Kind::Number), + m_data_type(DataType::Double) + { + m_data.m_double = d; + } + + ~JSONNumber() override = default; JSONNumber (const JSONNumber& s) = delete; JSONNumber& operator = (const JSONNumber& s) = delete; - virtual void - Write (Stream& s); - - typedef std::shared_ptr<JSONNumber> SP; + void + Write(Stream& s) override; uint64_t - GetData () { return m_data; } + GetAsUnsigned() const; + + int64_t + GetAsSigned() const; double - GetAsDouble() - { - if (m_is_integer) - return (double)m_data; - else - return m_double; - } + GetAsDouble() const; static bool classof(const JSONValue *V) { return V->GetKind() == JSONValue::Kind::Number; } - - virtual - ~JSONNumber () = default; - + private: - bool m_is_integer; - uint64_t m_data; - double m_double; + enum class DataType : uint8_t + { + Unsigned, + Signed, + Double + } m_data_type; + + union + { + uint64_t m_unsigned; + int64_t m_signed; + double m_double; + } m_data; }; class JSONTrue : public JSONValue @@ -146,8 +181,8 @@ namespace lldb_private { JSONTrue& operator = (const JSONTrue& s) = delete; - virtual void - Write (Stream& s); + void + Write(Stream& s) override; typedef std::shared_ptr<JSONTrue> SP; @@ -156,8 +191,7 @@ namespace lldb_private { return V->GetKind() == JSONValue::Kind::True; } - virtual - ~JSONTrue () = default; + ~JSONTrue() override = default; }; class JSONFalse : public JSONValue @@ -169,8 +203,8 @@ namespace lldb_private { JSONFalse& operator = (const JSONFalse& s) = delete; - virtual void - Write (Stream& s); + void + Write(Stream& s) override; typedef std::shared_ptr<JSONFalse> SP; @@ -179,8 +213,7 @@ namespace lldb_private { return V->GetKind() == JSONValue::Kind::False; } - virtual - ~JSONFalse () = default; + ~JSONFalse() override = default; }; class JSONNull : public JSONValue @@ -192,8 +225,8 @@ namespace lldb_private { JSONNull& operator = (const JSONNull& s) = delete; - virtual void - Write (Stream& s); + void + Write(Stream& s) override; typedef std::shared_ptr<JSONNull> SP; @@ -202,8 +235,7 @@ namespace lldb_private { return V->GetKind() == JSONValue::Kind::Null; } - virtual - ~JSONNull () = default; + ~JSONNull() override = default; }; class JSONObject : public JSONValue @@ -215,8 +247,8 @@ namespace lldb_private { JSONObject& operator = (const JSONObject& s) = delete; - virtual void - Write (Stream& s); + void + Write(Stream& s) override; typedef std::shared_ptr<JSONObject> SP; @@ -232,8 +264,7 @@ namespace lldb_private { JSONValue::SP GetObject (const std::string& key); - virtual - ~JSONObject () = default; + ~JSONObject() override = default; private: typedef std::map<std::string, JSONValue::SP> Map; @@ -250,8 +281,8 @@ namespace lldb_private { JSONArray& operator = (const JSONArray& s) = delete; - virtual void - Write (Stream& s); + void + Write(Stream& s) override; typedef std::shared_ptr<JSONArray> SP; @@ -280,13 +311,11 @@ namespace lldb_private { Size GetNumElements (); - virtual - ~JSONArray () = default; + ~JSONArray() override = default; Vector m_elements; }; - class JSONParser : public StringExtractor { public: @@ -327,6 +356,6 @@ namespace lldb_private { JSONValue::SP ParseJSONArray (); }; -} +} // namespace lldb_private -#endif // utility_ProcessStructReader_h_ +#endif // utility_JSON_h_ diff --git a/include/lldb/Utility/ProcessStructReader.h b/include/lldb/Utility/ProcessStructReader.h index d053b70..80f90fe 100644 --- a/include/lldb/Utility/ProcessStructReader.h +++ b/include/lldb/Utility/ProcessStructReader.h @@ -16,7 +16,7 @@ #include "lldb/Core/ConstString.h" #include "lldb/Core/DataExtractor.h" #include "lldb/Core/Error.h" -#include "lldb/Symbol/ClangASTType.h" +#include "lldb/Symbol/CompilerType.h" #include "lldb/Target/Process.h" #include <initializer_list> @@ -29,7 +29,7 @@ namespace lldb_private { protected: struct FieldImpl { - ClangASTType type; + CompilerType type; size_t offset; size_t size; }; @@ -40,7 +40,7 @@ namespace lldb_private { size_t m_addr_byte_size; public: - ProcessStructReader (Process *process, lldb::addr_t base_addr, ClangASTType struct_type) + ProcessStructReader (Process *process, lldb::addr_t base_addr, CompilerType struct_type) { if (!process) return; @@ -55,7 +55,7 @@ namespace lldb_private { uint64_t bit_offset; uint32_t bitfield_bit_size; bool is_bitfield; - ClangASTType field_type = struct_type.GetFieldAtIndex(idx,name,&bit_offset,&bitfield_bit_size,&is_bitfield); + CompilerType field_type = struct_type.GetFieldAtIndex(idx,name,&bit_offset,&bitfield_bit_size,&is_bitfield); // no support for bitfields in here (yet) if (is_bitfield) return; diff --git a/include/lldb/Utility/PseudoTerminal.h b/include/lldb/Utility/PseudoTerminal.h index 595b2fc..d732534 100644 --- a/include/lldb/Utility/PseudoTerminal.h +++ b/include/lldb/Utility/PseudoTerminal.h @@ -260,7 +260,7 @@ private: }; -} // namespace lldb +} // namespace lldb_utility #endif // #if defined(__cplusplus) #endif // #ifndef liblldb_PseudoTerminal_h_ diff --git a/include/lldb/Utility/PythonPointer.h b/include/lldb/Utility/PythonPointer.h deleted file mode 100644 index fe90670..0000000 --- a/include/lldb/Utility/PythonPointer.h +++ /dev/null @@ -1,73 +0,0 @@ -//===---------------------PythonPointer.h ------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef utility_PythonPointer_h_ -#define utility_PythonPointer_h_ - -#include <algorithm> - -#include "lldb/lldb-python.h" - -namespace lldb_private { - -template<class T> -class PythonPointer -{ -public: - typedef PyObject* element_type; -private: - element_type* ptr_; - bool my_ref; -public: - - PythonPointer(element_type p, bool steal_ref = false) : - ptr_(p), - my_ref(!steal_ref) - { - if (my_ref) - Py_INCREF(ptr_); - } - - PythonPointer(const PythonPointer& r, bool steal_ref = false) : - ptr_(r.ptr_), - my_ref(!steal_ref) - { - if (my_ref) - Py_INCREF(ptr_); - } - - ~PythonPointer() - { - if (my_ref) - Py_XDECREF(ptr_); - } - - PythonPointer - StealReference() - { - return PythonPointer(ptr_,true); - } - - PythonPointer - DuplicateReference() - { - return PythonPointer(ptr_, false); - } - - element_type get() const {return ptr_;} - - bool IsNull() { return ptr_ == NULL; } - bool IsNone() { return ptr_ == Py_None; } - - operator PyObject* () { return ptr_; } -}; - -} // namespace lldb - -#endif // utility_PythonPointer_h_ diff --git a/include/lldb/Utility/SharedCluster.h b/include/lldb/Utility/SharedCluster.h index 3a34d8d..2c03c40 100644 --- a/include/lldb/Utility/SharedCluster.h +++ b/include/lldb/Utility/SharedCluster.h @@ -27,14 +27,15 @@ namespace imp shared_ptr_refcount() : shared_count (0) {} - virtual ~shared_ptr_refcount () + ~shared_ptr_refcount() override { } - virtual void on_zero_shared () + void on_zero_shared() override { manager->DecrementRefCount(); } + private: T *manager; }; @@ -100,4 +101,5 @@ private: }; } // namespace lldb_private + #endif // utility_SharedCluster_h_ diff --git a/include/lldb/Utility/SharingPtr.h b/include/lldb/Utility/SharingPtr.h index 5c77dad..29538bc 100644 --- a/include/lldb/Utility/SharingPtr.h +++ b/include/lldb/Utility/SharingPtr.h @@ -10,6 +10,8 @@ #ifndef utility_SharingPtr_h_ #define utility_SharingPtr_h_ +// C Includes +// C++ Includes #include <algorithm> #include <memory> @@ -22,6 +24,9 @@ #include <atomic> #endif +// Other libraries and framework includes +// Project includes + //#define ENABLE_SP_LOGGING 1 // DON'T CHECK THIS LINE IN UNLESS COMMENTED OUT #if defined (ENABLE_SP_LOGGING) @@ -38,6 +43,13 @@ class shared_count shared_count(const shared_count&); shared_count& operator=(const shared_count&); +public: + explicit shared_count(long refs = 0) + : shared_owners_(refs) {} + + void add_shared(); + void release_shared(); + long use_count() const {return shared_owners_ + 1;} protected: #ifdef _MSC_VER long shared_owners_; @@ -45,16 +57,9 @@ protected: std::atomic<long> shared_owners_; #endif virtual ~shared_count(); + private: virtual void on_zero_shared() = 0; - -public: - explicit shared_count(long refs = 0) - : shared_owners_(refs) {} - - void add_shared(); - void release_shared(); - long use_count() const {return shared_owners_ + 1;} }; template <class T> @@ -67,7 +72,7 @@ public: : data_(p) {} private: - virtual void on_zero_shared(); + void on_zero_shared() override; // Outlaw copy constructor and assignment operator to keep effective C++ // warnings down to a minimum @@ -113,7 +118,8 @@ public: : data_(a0, a1, a2, a3, a4) {} private: - virtual void on_zero_shared(); + void on_zero_shared() override; + public: T* get() {return &data_;} }; @@ -124,18 +130,20 @@ shared_ptr_emplace<T>::on_zero_shared() { } -} // namespace +} // namespace imp template<class T> class SharingPtr { public: typedef T element_type; + private: element_type* ptr_; imp::shared_count* cntrl_; struct nat {int for_bool_;}; + public: SharingPtr(); SharingPtr(std::nullptr_t); @@ -161,7 +169,7 @@ public: element_type* operator->() const {return ptr_;} long use_count() const {return cntrl_ ? cntrl_->use_count() : 0;} bool unique() const {return use_count() == 1;} - bool empty() const {return cntrl_ == 0;} + bool empty() const {return cntrl_ == nullptr;} operator nat*() const {return (nat*)get();} static SharingPtr<T> make_shared(); @@ -182,30 +190,29 @@ public: static SharingPtr<T> make_shared(A0&, A1&, A2&, A3&, A4&); private: - template <class U> friend class SharingPtr; }; template<class T> inline SharingPtr<T>::SharingPtr() - : ptr_(0), - cntrl_(0) + : ptr_(nullptr), + cntrl_(nullptr) { } template<class T> inline SharingPtr<T>::SharingPtr(std::nullptr_t) -: ptr_(0), -cntrl_(0) +: ptr_(nullptr), +cntrl_(nullptr) { } template<class T> template<class Y> SharingPtr<T>::SharingPtr(Y* p) - : ptr_(p), cntrl_(0) + : ptr_(p), cntrl_(nullptr) { std::unique_ptr<Y> hold(p); typedef imp::shared_ptr_pointer<Y*> _CntrlBlk; @@ -431,7 +438,6 @@ make_shared(A0& a0, A1& a1, A2& a2, A3& a3, A4& a4) return SharingPtr<T>::make_shared(a0, a1, a2, a3, a4); } - template<class T, class U> inline bool @@ -490,12 +496,8 @@ public: // action: false means increment just happened // true means decrement is about to happen -private: - Callback cb_; - void* baton_; + LoggingSharingPtr() : cb_(0), baton_(nullptr) {} -public: - LoggingSharingPtr() : cb_(0), baton_(0) {} LoggingSharingPtr(Callback cb, void* baton) : cb_(cb), baton_(baton) { @@ -505,7 +507,7 @@ public: template <class Y> LoggingSharingPtr(Y* p) - : base(p), cb_(0), baton_(0) {} + : base(p), cb_(0), baton_(nullptr) {} template <class Y> LoggingSharingPtr(Y* p, Callback cb, void* baton) @@ -568,9 +570,12 @@ public: cb_ = 0; baton_ = 0; } + +private: + Callback cb_; + void* baton_; }; - - + template <class T> class IntrusiveSharingPtr; @@ -637,14 +642,10 @@ public: imp::shared_count(-1) { } - - virtual - ~ReferenceCountedBaseVirtual () - { - } - - virtual void on_zero_shared (); - + + ~ReferenceCountedBaseVirtual() override = default; + + void on_zero_shared() override; }; template <class T> @@ -716,7 +717,7 @@ public: // those would be builds for release. But for debug and release builds // that are for development, we NULL out the pointers to catch potential // issues. - ptr_ = NULL; + ptr_ = nullptr; #endif // #if defined (LLDB_CONFIGURATION_DEBUG) || defined (LLDB_CONFIGURATION_RELEASE) } @@ -754,7 +755,7 @@ public: } void - reset(T* ptr = NULL) + reset(T* ptr = nullptr) { IntrusiveSharingPtr(ptr).swap(*this); } @@ -793,7 +794,7 @@ private: if (ptr_) { #if defined (ENABLE_SP_LOGGING) - track_sp (this, NULL, ptr_->use_count() - 1); + track_sp (this, nullptr, ptr_->use_count() - 1); #endif ptr_->release_shared(); } @@ -838,4 +839,4 @@ inline bool operator!= (T* lhs, const IntrusiveSharingPtr<U>& rhs) } // namespace lldb_private -#endif // utility_SharingPtr_h_ +#endif // utility_SharingPtr_h_ diff --git a/include/lldb/Utility/StringExtractor.h b/include/lldb/Utility/StringExtractor.h index 0f2dbb1..db1b83b 100644 --- a/include/lldb/Utility/StringExtractor.h +++ b/include/lldb/Utility/StringExtractor.h @@ -115,6 +115,9 @@ public: GetHexU8 (uint8_t fail_value = 0, bool set_eof_on_fail = true); bool + GetHexU8Ex (uint8_t& ch, bool set_eof_on_fail = true); + + bool GetNameColonValue (std::string &name, std::string &value); int32_t diff --git a/include/lldb/Utility/TaskPool.h b/include/lldb/Utility/TaskPool.h new file mode 100644 index 0000000..443e2a5 --- /dev/null +++ b/include/lldb/Utility/TaskPool.h @@ -0,0 +1,221 @@ +//===--------------------- TaskPool.h ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef utility_TaskPool_h_ +#define utility_TaskPool_h_ + +#if defined(__cplusplus) && defined(_MSC_VER) && (_HAS_EXCEPTIONS == 0) +// Compiling MSVC libraries with _HAS_EXCEPTIONS=0, eliminates most but not all +// calls to __uncaught_exception. Unfortunately, it does seem to eliminate +// the delcaration of __uncaught_excpeiton. Including <eh.h> ensures that it is +// declared. This may not be necessary after MSVC 12. +#include <eh.h> +#endif + +#if defined(_MSC_VER) +// Due to another bug in MSVC 2013, including <future> will generate hundreds of +// warnings in the Concurrency Runtime. This can be removed when we switch to +// MSVC 2015 +#pragma warning(push) +#pragma warning(disable:4062) +#endif + +#include <cassert> +#include <cstdint> +#include <future> +#include <list> +#include <queue> +#include <thread> +#include <vector> + +// Global TaskPool class for running tasks in parallel on a set of worker thread created the first +// time the task pool is used. The TaskPool provide no gurantee about the order the task will be run +// and about what tasks will run in parrallel. None of the task added to the task pool should block +// on something (mutex, future, condition variable) what will be set only by the completion of an +// other task on the task pool as they may run on the same thread sequentally. +class TaskPool +{ +public: + // Add a new task to the task pool and return a std::future belonging to the newly created task. + // The caller of this function has to wait on the future for this task to complete. + template<typename F, typename... Args> + static std::future<typename std::result_of<F(Args...)>::type> + AddTask(F&& f, Args&&... args); + + // Run all of the specified tasks on the task pool and wait until all of them are finished + // before returning. This method is intended to be used for small number tasks where listing + // them as function arguments is acceptable. For running large number of tasks you should use + // AddTask for each task and then call wait() on each returned future. + template<typename... T> + static void + RunTasks(T&&... tasks); + +private: + TaskPool() = delete; + + template<typename... T> + struct RunTaskImpl; + + static void + AddTaskImpl(std::function<void()>&& task_fn); +}; + +// Wrapper class around the global TaskPool implementation to make it possible to create a set of +// tasks and then wait for the tasks to be completed by the WaitForNextCompletedTask call. This +// class should be used when WaitForNextCompletedTask is needed because this class add no other +// extra functionality to the TaskPool class and it have a very minor performance overhead. +template <typename T> // The return type of the tasks what will be added to this task runner +class TaskRunner +{ +public: + // Add a task to the task runner what will also add the task to the global TaskPool. The + // function doesn't return the std::future for the task because it will be supplied by the + // WaitForNextCompletedTask after the task is completed. + template<typename F, typename... Args> + void + AddTask(F&& f, Args&&... args); + + // Wait for the next task in this task runner to finish and then return the std::future what + // belongs to the finished task. If there is no task in this task runner (neither pending nor + // comleted) then this function will return an invalid future. Usually this function should be + // called in a loop processing the results of the tasks until it returns an invalid std::future + // what means that all task in this task runner is completed. + std::future<T> + WaitForNextCompletedTask(); + + // Convenience method to wait for all task in this TaskRunner to finish. Do NOT use this class + // just because of this method. Use TaskPool instead and wait for each std::future returned by + // AddTask in a loop. + void + WaitForAllTasks(); + +private: + std::list<std::future<T>> m_ready; + std::list<std::future<T>> m_pending; + std::mutex m_mutex; + std::condition_variable m_cv; +}; + +template<typename F, typename... Args> +std::future<typename std::result_of<F(Args...)>::type> +TaskPool::AddTask(F&& f, Args&&... args) +{ + auto task_sp = std::make_shared<std::packaged_task<typename std::result_of<F(Args...)>::type()>>( + std::bind(std::forward<F>(f), std::forward<Args>(args)...)); + + AddTaskImpl([task_sp]() { (*task_sp)(); }); + + return task_sp->get_future(); +} + +template<typename... T> +void +TaskPool::RunTasks(T&&... tasks) +{ + RunTaskImpl<T...>::Run(std::forward<T>(tasks)...); +} + +template<typename Head, typename... Tail> +struct TaskPool::RunTaskImpl<Head, Tail...> +{ + static void + Run(Head&& h, Tail&&... t) + { + auto f = AddTask(std::forward<Head>(h)); + RunTaskImpl<Tail...>::Run(std::forward<Tail>(t)...); + f.wait(); + } +}; + +template<> +struct TaskPool::RunTaskImpl<> +{ + static void + Run() {} +}; + +template <typename T> +template<typename F, typename... Args> +void +TaskRunner<T>::AddTask(F&& f, Args&&... args) +{ + std::unique_lock<std::mutex> lock(m_mutex); + auto it = m_pending.emplace(m_pending.end()); + *it = std::move(TaskPool::AddTask( + [this, it](F f, Args... args) + { + T&& r = f(std::forward<Args>(args)...); + + std::unique_lock<std::mutex> lock(this->m_mutex); + this->m_ready.splice(this->m_ready.end(), this->m_pending, it); + lock.unlock(); + + this->m_cv.notify_one(); + return r; + }, + std::forward<F>(f), + std::forward<Args>(args)...)); +} + +template <> +template<typename F, typename... Args> +void +TaskRunner<void>::AddTask(F&& f, Args&&... args) +{ + std::unique_lock<std::mutex> lock(m_mutex); + auto it = m_pending.emplace(m_pending.end()); + *it = std::move(TaskPool::AddTask( + [this, it](F f, Args... args) + { + f(std::forward<Args>(args)...); + + std::unique_lock<std::mutex> lock(this->m_mutex); + this->m_ready.emplace_back(std::move(*it)); + this->m_pending.erase(it); + lock.unlock(); + + this->m_cv.notify_one(); + }, + std::forward<F>(f), + std::forward<Args>(args)...)); +} + +template <typename T> +std::future<T> +TaskRunner<T>::WaitForNextCompletedTask() +{ + std::unique_lock<std::mutex> lock(m_mutex); + if (m_ready.empty() && m_pending.empty()) + return std::future<T>(); // No more tasks + + if (m_ready.empty()) + m_cv.wait(lock, [this](){ return !this->m_ready.empty(); }); + + std::future<T> res = std::move(m_ready.front()); + m_ready.pop_front(); + + lock.unlock(); + res.wait(); + + return std::move(res); +} + +template <typename T> +void +TaskRunner<T>::WaitForAllTasks() +{ + while (WaitForNextCompletedTask().valid()); +} + + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +#endif // #ifndef utility_TaskPool_h_ |