Import Geant4 11.3.0 source tree

This commit is contained in:
Gabriele Cosmo
2024-12-06 11:11:40 +01:00
parent e58e650b32
commit 32390e802b
1984 changed files with 98713 additions and 83996 deletions
+2 -2
View File
@@ -243,8 +243,8 @@ int main()
#pragma once
#include "PTL/Threading.hh"
#include "PTL/Utility.hh"
#include "PTL/ConsumeParameters.hh"
#include "PTL/Types.hh"
#include <chrono>
#include <iostream>
-802
View File
@@ -1,802 +0,0 @@
//
// MIT License
// Copyright (c) 2020 Jonathan R. Madsen
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED
// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// Backtrace
//
// Description:
//
// Prints backtraces after signals are caught. Available on Unix.
//
// Usage:
// A standard set of signals are enabled by default:
//
// SIGQUIT, SIGILL, SIGABRT, SIGKILL, SIGBUS, SIGSEGV
//
// These should not interfere with debuggers and/or FPEDetection.
// In order to turn off handling for one or more signals, one can do:
//
// BackTrace::DefaultSignals() = std::set<int>{};
// BackTrace::DefaultSignals() = std::set<int>{ SIGSEGV };
//
// and so on, *before* creating the run-manager. After the run-manager
// has been created, one should disable the signals:
//
// BackTrace::Disable(BackTrace::DefaultSignals());
//
// Additionally, at runtime, the environment variable "BACKTRACE" can
// be set to select a specific set of signals or none, e.g. in bash:
//
// export BACKTRACE="SIGQUIT,SIGSEGV"
// export BACKTRACE="none"
//
// The environment variable is case-insensitive and can use any of the
// following delimiters: space, comma, semi-colon, colon
//
// Author: J.Madsen, 19 October 2020
// --------------------------------------------------------------------
#ifndef PTL_Backtrace_hh
#define PTL_Backtrace_hh 1
#include "Threading.hh"
#include "Types.hh"
#if defined(PTL_UNIX)
# include <cxxabi.h>
# include <execinfo.h>
# include <unistd.h>
#endif
#if defined(PTL_LINUX)
# include <features.h>
#endif
#include <cfenv>
#include <cmath>
#include <csignal>
#include <cstring>
#include <type_traits>
namespace PTL
{
template <typename FuncT, typename... ArgTypes>
#if __cpp_lib_is_invocable >= 201703
using ResultOf_t = std::invoke_result_t<FuncT, ArgTypes...>;
#else
using ResultOf_t = typename std::result_of<FuncT(ArgTypes...)>::type;
#endif
} // namespace PTL
// compatible OS and compiler
#if defined(PTL_UNIX) && \
(defined(__GNUC__) || defined(__clang__) || defined(_INTEL_COMPILER))
# if !defined(PTL_SIGNAL_AVAILABLE)
# define PTL_SIGNAL_AVAILABLE
# endif
# if !defined(PTL_DEMANGLE_AVAILABLE)
# define PTL_DEMANGLE_AVAILABLE
# endif
#endif
#if !defined(PTL_PSIGINFO_AVAILABLE)
# if _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L
# define PTL_PSIGINFO_AVAILABLE 1
# else
# define PTL_PSIGINFO_AVAILABLE 0
# endif
#endif
//----------------------------------------------------------------------------//
namespace PTL
{
inline std::string
Demangle(const char* _str)
{
#if defined(PTL_DEMANGLE_AVAILABLE)
// demangling a string when delimiting
int _status = 0;
char* _ret = ::abi::__cxa_demangle(_str, nullptr, nullptr, &_status);
if(_ret && _status == 0)
return std::string(const_cast<const char*>(_ret));
return _str;
#else
return _str;
#endif
}
//----------------------------------------------------------------------------//
inline std::string
Demangle(const std::string& _str)
{
return Demangle(_str.c_str());
}
//----------------------------------------------------------------------------//
template <typename Tp>
inline std::string
Demangle()
{
return Demangle(typeid(Tp).name());
}
} // namespace PTL
//----------------------------------------------------------------------------//
//
// ONLY IF SIGNAL_AVAILABLE
//
//----------------------------------------------------------------------------//
//
#if defined(PTL_SIGNAL_AVAILABLE)
//
// these are not in the original POSIX.1-1990 standard so we are defining
// them in case the OS hasn't
// POSIX-1.2001
# ifndef SIGTRAP
# define SIGTRAP 5
# endif
// not specified in POSIX.1-2001, but nevertheless appears on most other
// UNIX systems, where its default action is typically to terminate the
// process with a core dump.
# ifndef SIGEMT
# define SIGEMT 7
# endif
// POSIX-1.2001
# ifndef SIGURG
# define SIGURG 16
# endif
// POSIX-1.2001
# ifndef SIGXCPU
# define SIGXCPU 24
# endif
// POSIX-1.2001
# ifndef SIGXFSZ
# define SIGXFSZ 25
# endif
// POSIX-1.2001
# ifndef SIGVTALRM
# define SIGVTALRM 26
# endif
// POSIX-1.2001
# ifndef SIGPROF
# define SIGPROF 27
# endif
// POSIX-1.2001
# ifndef SIGINFO
# define SIGINFO 29
# endif
//----------------------------------------------------------------------------//
# include <algorithm>
# include <array>
# include <cstdio>
# include <cstdlib>
# include <functional>
# include <iomanip>
# include <iostream>
# include <map>
# include <regex>
# include <set>
# include <sstream>
# include <string>
# include <tuple>
# include <vector>
// PTL header
# include "Threading.hh"
//----------------------------------------------------------------------------//
namespace PTL
{
class Backtrace
{
public:
using sigaction_t = struct sigaction;
using exit_action_t = std::function<void(int)>;
using frame_func_t = std::function<std::string(const char*)>;
using signal_set_t = std::set<int>;
public:
struct actions
{
using id_entry_t = std::tuple<std::string, int, std::string>;
using id_list_t = std::vector<id_entry_t>;
std::map<int, bool> is_active = {};
std::map<int, sigaction_t> current = {};
std::map<int, sigaction_t> previous = {};
std::vector<exit_action_t> exit_actions = {};
const id_list_t identifiers = {
id_entry_t("SIGHUP", SIGHUP, "terminal line hangup"),
id_entry_t("SIGINT", SIGINT, "interrupt program"),
id_entry_t("SIGQUIT", SIGQUIT, "quit program"),
id_entry_t("SIGILL", SIGILL, "illegal instruction"),
id_entry_t("SIGTRAP", SIGTRAP, "trace trap"),
id_entry_t("SIGABRT", SIGABRT, "abort program (formerly SIGIOT)"),
id_entry_t("SIGEMT", SIGEMT, "emulate instruction executed"),
id_entry_t("SIGFPE", SIGFPE, "floating-point exception"),
id_entry_t("SIGKILL", SIGKILL, "kill program"),
id_entry_t("SIGBUS", SIGBUS, "bus error"),
id_entry_t("SIGSEGV", SIGSEGV, "segmentation violation"),
id_entry_t("SIGSYS", SIGSYS, "non-existent system call invoked"),
id_entry_t("SIGPIPE", SIGPIPE, "write on a pipe with no reader"),
id_entry_t("SIGALRM", SIGALRM, "real-time timer expired"),
id_entry_t("SIGTERM", SIGTERM, "software termination signal"),
id_entry_t("SIGURG", SIGURG, "urgent condition present on socket"),
id_entry_t("SIGSTOP", SIGSTOP, "stop (cannot be caught or ignored)"),
id_entry_t("SIGTSTP", SIGTSTP, "stop signal generated from keyboard"),
id_entry_t("SIGCONT", SIGCONT, "continue after stop"),
id_entry_t("SIGCHLD", SIGCHLD, "child status has changed"),
id_entry_t("SIGTTIN", SIGTTIN,
"background read attempted from control terminal"),
id_entry_t("SIGTTOU", SIGTTOU,
"background write attempted to control terminal"),
id_entry_t("SIGIO ", SIGIO, "I/O is possible on a descriptor"),
id_entry_t("SIGXCPU", SIGXCPU, "cpu time limit exceeded"),
id_entry_t("SIGXFSZ", SIGXFSZ, "file size limit exceeded"),
id_entry_t("SIGVTALRM", SIGVTALRM, "virtual time alarm"),
id_entry_t("SIGPROF", SIGPROF, "profiling timer alarm"),
id_entry_t("SIGWINCH", SIGWINCH, "Window size change"),
id_entry_t("SIGINFO", SIGINFO, "status request from keyboard"),
id_entry_t("SIGUSR1", SIGUSR1, "User defined signal 1"),
id_entry_t("SIGUSR2", SIGUSR2, "User defined signal 2")
};
};
public:
// a functor called for each frame in the backtrace
static frame_func_t& FrameFunctor();
// default set of signals
static signal_set_t& DefaultSignals();
// the signal handler
static void Handler(int sig, siginfo_t* sinfo, void* context);
// information message about the signal, performs exit-actions
// and prints back-trace
static void Message(int sig, siginfo_t* sinfo, std::ostream&);
// calls user-provided functions after signal is caught but before abort
static void ExitAction(int sig);
// enable signals via a string (which is tokenized)
static int Enable(const std::string&);
// enable signals via set of integers, anything less than zero is ignored
static int Enable(const signal_set_t& _signals = DefaultSignals());
// disable signals
static int Disable(signal_set_t _signals = {});
// gets the numeric value for a signal name
static int GetSignal(const std::string&);
// provides a description of the signal
static std::string Description(int sig);
// adds an exit action
template <typename FuncT>
static void AddExitAction(FuncT&& func);
// gets a backtrace of "Depth" frames. The offset parameter is used
// to ignore initial frames (such as this function). A callback
// can be provided to inspect and/or tweak the frame string
template <size_t Depth, size_t Offset = 0, typename FuncT = frame_func_t>
static std::array<ResultOf_t<FuncT, const char*>, Depth> GetMangled(
FuncT&& func = FrameFunctor());
// gets a demangled backtrace of "Depth" frames. The offset parameter is
// used to ignore initial frames (such as this function). A callback
// can be provided to inspect and/or tweak the frame string
template <size_t Depth, size_t Offset = 0, typename FuncT = frame_func_t>
static std::array<ResultOf_t<FuncT, const char*>, Depth> GetDemangled(
FuncT&& func = FrameFunctor());
private:
static actions& GetData()
{
static auto _instance = actions{};
return _instance;
}
};
//----------------------------------------------------------------------------//
// a functor called for each frame in the backtrace
inline Backtrace::frame_func_t&
Backtrace::FrameFunctor()
{
static frame_func_t _instance = [](const char* inp) { return std::string(inp); };
return _instance;
}
//----------------------------------------------------------------------------//
// default set of signals
inline Backtrace::signal_set_t&
Backtrace::DefaultSignals()
{
static signal_set_t _instance = {
SIGQUIT, SIGILL, SIGABRT, SIGKILL, SIGBUS, SIGSEGV
};
return _instance;
}
//----------------------------------------------------------------------------//
template <typename FuncT>
inline void
Backtrace::AddExitAction(FuncT&& func)
{
GetData().exit_actions.emplace_back(std::forward<FuncT>(func));
}
//----------------------------------------------------------------------------//
inline void
Backtrace::ExitAction(int sig)
{
for(auto& itr : GetData().exit_actions)
itr(sig);
}
//----------------------------------------------------------------------------//
template <size_t Depth, size_t Offset, typename FuncT>
inline std::array<ResultOf_t<FuncT, const char*>, Depth>
Backtrace::GetMangled(FuncT&& func)
{
static_assert((Depth - Offset) >= 1, "Error Depth - Offset should be >= 1");
using type = ResultOf_t<FuncT, const char*>;
// destination
std::array<type, Depth> btrace;
btrace.fill((std::is_pointer<type>::value) ? nullptr : type{});
// plus one for this stack-frame
std::array<void*, Depth + Offset> buffer;
// size of returned buffer
auto sz = backtrace(buffer.data(), Depth + Offset);
// size of relevant data
auto n = sz - Offset;
// skip ahead (Offset + 1) stack frames
char** bsym = backtrace_symbols(buffer.data() + Offset, n);
// report errors
if(bsym == nullptr)
perror("backtrace_symbols");
else
{
for(decltype(n) i = 0; i < n; ++i)
btrace[i] = func(bsym[i]);
free(bsym);
}
return btrace;
}
//----------------------------------------------------------------------------//
template <size_t Depth, size_t Offset, typename FuncT>
inline std::array<ResultOf_t<FuncT, const char*>, Depth>
Backtrace::GetDemangled(FuncT&& func)
{
auto demangle_bt = [&](const char* cstr) {
auto _trim = [](std::string& _sub, size_t& _len) {
size_t _pos = 0;
while((_pos = _sub.find_first_of(' ')) == 0)
{
_sub = _sub.erase(_pos, 1);
--_len;
}
while((_pos = _sub.find_last_of(' ')) == _sub.length() - 1)
{
_sub = _sub.substr(0, _sub.length() - 1);
--_len;
}
return _sub;
};
auto str = Demangle(std::string(cstr));
auto beg = str.find("(");
if(beg == std::string::npos)
{
beg = str.find("_Z");
if(beg != std::string::npos)
beg -= 1;
}
auto end = str.find("+", beg);
if(beg != std::string::npos && end != std::string::npos)
{
auto len = end - (beg + 1);
auto sub = str.substr(beg + 1, len);
auto dem = Demangle(_trim(sub, len));
str = str.replace(beg + 1, len, dem);
}
else if(beg != std::string::npos)
{
auto len = str.length() - (beg + 1);
auto sub = str.substr(beg + 1, len);
auto dem = Demangle(_trim(sub, len));
str = str.replace(beg + 1, len, dem);
}
else if(end != std::string::npos)
{
auto len = end;
auto sub = str.substr(beg, len);
auto dem = Demangle(_trim(sub, len));
str = str.replace(beg, len, dem);
}
return func(str.c_str());
};
return GetMangled<Depth, Offset>(demangle_bt);
}
//----------------------------------------------------------------------------//
inline void
Backtrace::Message(int sig, siginfo_t* sinfo, std::ostream& os)
{
// try to avoid as many dynamic allocations as possible here to avoid
// overflowing the signal stack
// ignore future signals of this type
signal(sig, SIG_IGN);
os << "\n### CAUGHT SIGNAL: " << sig << " ### ";
if(sinfo)
os << "address: " << sinfo->si_addr << ", ";
os << Description(sig) << ". ";
if(sig == SIGSEGV)
{
if(sinfo)
{
switch(sinfo->si_code)
{
case SEGV_MAPERR: os << "Address not mapped to object."; break;
case SEGV_ACCERR: os << "Invalid permissions for mapped object."; break;
default:
os << "Unknown segmentation fault error: " << sinfo->si_code << ".";
break;
}
}
else
{
os << "Segmentation fault (unknown).";
}
}
else if(sig == SIGFPE)
{
if(sinfo)
{
switch(sinfo->si_code)
{
case FE_DIVBYZERO: os << "Floating point divide by zero."; break;
case FE_OVERFLOW: os << "Floating point overflow."; break;
case FE_UNDERFLOW: os << "Floating point underflow."; break;
case FE_INEXACT: os << "Floating point inexact result."; break;
case FE_INVALID: os << "Floating point invalid operation."; break;
default:
os << "Unknown floating point exception error: " << sinfo->si_code
<< ".";
break;
}
}
else
{
os << "Unknown floating point exception";
if(sinfo)
os << ": " << sinfo->si_code;
os << ". ";
}
}
os << '\n';
auto bt = GetMangled<256, 3>([](const char* _s) { return _s; });
char prefix[64];
snprintf(prefix, 64, "[PID=%i, TID=%i]", (int) getpid(),
(int) Threading::GetThreadId());
size_t sz = 0;
for(auto& itr : bt)
{
if(!itr)
break;
if(strlen(itr) == 0)
break;
++sz;
}
os << "\nBacktrace:\n";
auto _w = std::log10(sz) + 1;
for(size_t i = 0; i < sz; ++i)
{
os << prefix << "[" << std::setw(_w) << std::right << i << '/' << std::setw(_w)
<< std::right << sz << "]> " << std::left << bt.at(i) << '\n';
}
os << std::flush;
// exit action could cause more signals to be raise so make sure this is done
// after the message has been printed
try
{
ExitAction(sig);
} catch(std::exception& e)
{
std::cerr << "ExitAction(" << sig << ") threw an exception" << std::endl;
std::cerr << e.what() << std::endl;
}
}
//----------------------------------------------------------------------------//
inline void
Backtrace::Handler(int sig, siginfo_t* sinfo, void*)
{
Message(sig, sinfo, std::cerr);
char msg[1024];
snprintf(msg, 1024, "%s", "\n");
if(sinfo && PTL_PSIGINFO_AVAILABLE > 0)
{
# if PTL_PSIGINFO_AVAILABLE > 0
psiginfo(sinfo, msg);
fflush(stdout);
fflush(stderr);
# endif
}
else
{
std::cerr << msg << std::flush;
}
// ignore any termination signals
for(auto itr : { SIGKILL, SIGTERM, SIGABRT })
signal(itr, SIG_IGN);
abort();
}
//----------------------------------------------------------------------------//
inline int
Backtrace::Enable(const signal_set_t& _signals)
{
static bool _first = true;
if(_first)
{
std::string _msg = "!!! Backtrace is activated !!!";
std::stringstream _filler;
std::stringstream _spacer;
_filler.fill('#');
_filler << std::setw(_msg.length()) << "";
_spacer << std::setw(10) << "";
std::cout << "\n\n"
<< _spacer.str() << _filler.str() << "\n"
<< _spacer.str() << _msg << "\n"
<< _spacer.str() << _filler.str() << "\n\n"
<< std::flush;
}
_first = false;
int cnt = 0;
for(const auto& itr : _signals)
{
if(itr < 0)
continue;
if(GetData().is_active[itr])
continue;
++cnt;
sigfillset(&(GetData().current[itr].sa_mask));
sigdelset(&(GetData().current[itr].sa_mask), itr);
GetData().current[itr].sa_sigaction = &Handler;
GetData().current[itr].sa_flags = SA_SIGINFO;
sigaction(itr, &(GetData().current[itr]), &(GetData().previous[itr]));
}
return cnt;
}
//----------------------------------------------------------------------------//
inline int
Backtrace::Enable(const std::string& _signals)
{
if(_signals.empty())
return 0;
auto _add_signal = [](std::string sig, signal_set_t& _targ) {
if(!sig.empty())
{
for(auto& itr : sig)
itr = toupper(itr);
_targ.insert(Backtrace::GetSignal(sig));
}
};
const std::regex wsp_re("[ ,;:\t\n]+");
auto _maxid = GetData().identifiers.size();
auto _result = std::vector<std::string>(_maxid, "");
std::copy(std::sregex_token_iterator(_signals.begin(), _signals.end(), wsp_re, -1),
std::sregex_token_iterator(), _result.begin());
signal_set_t _sigset{};
for(auto& itr : _result)
_add_signal(itr, _sigset);
return Enable(_sigset);
}
//----------------------------------------------------------------------------//
inline int
Backtrace::Disable(signal_set_t _signals)
{
if(_signals.empty())
{
for(auto& itr : GetData().is_active)
_signals.insert(itr.first);
}
int cnt = 0;
for(const auto& itr : _signals)
{
if(itr < 0)
continue;
if(!GetData().is_active[itr])
continue;
++cnt;
sigaction(itr, &(GetData().previous[itr]), nullptr);
GetData().current.erase(itr);
GetData().is_active[itr] = false;
}
return cnt;
}
//----------------------------------------------------------------------------//
inline int
Backtrace::GetSignal(const std::string& sid)
{
for(auto&& itr : GetData().identifiers)
{
if(std::get<0>(itr) == sid)
return std::get<1>(itr);
}
return -1;
}
//----------------------------------------------------------------------------//
inline std::string
Backtrace::Description(int sig)
{
for(auto&& itr : GetData().identifiers)
{
if(std::get<1>(itr) == sig)
{
std::stringstream ss;
ss << " signal = " << std::setw(8) << std::get<0>(itr)
<< ", value = " << std::setw(4) << std::get<1>(itr)
<< ", description = " << std::get<2>(itr);
return ss.str();
}
}
std::stringstream ss;
ss << " signal = " << std::setw(8) << "unknown"
<< ", value = " << std::setw(4) << sig;
return ss.str();
}
//----------------------------------------------------------------------------//
} // namespace PTL
#else
# include <array>
# include <functional>
# include <map>
# include <set>
# include <string>
# include <tuple>
# include <vector>
namespace PTL
{
// dummy implementation
class Backtrace
{
public:
struct fake_siginfo
{};
struct fake_sigaction
{};
using siginfo_t = fake_siginfo;
using sigaction_t = fake_sigaction;
using exit_action_t = std::function<void(int)>;
using frame_func_t = std::function<std::string(const char*)>;
using signal_set_t = std::set<int>;
public:
struct actions
{
using id_entry_t = std::tuple<std::string, int, std::string>;
using id_list_t = std::vector<id_entry_t>;
std::map<int, bool> is_active = {};
std::map<int, sigaction_t> current = {};
std::map<int, sigaction_t> previous = {};
std::vector<exit_action_t> exit_actions = {};
const id_list_t identifiers = {};
};
public:
static void Handler(int, siginfo_t*, void*) {}
static void Message(int, siginfo_t*, std::ostream&) {}
static void ExitAction(int) {}
static int Enable(const std::string&) { return 0; }
static int Enable(const signal_set_t& = DefaultSignals()) { return 0; }
static int Disable(signal_set_t = {}) { return 0; }
static int GetSignal(const std::string&) { return -1; }
static std::string Description(int) { return std::string{}; }
template <typename FuncT>
static void AddExitAction(FuncT&&)
{}
template <size_t Depth, size_t Offset = 0, typename FuncT = frame_func_t>
static std::array<ResultOf_t<FuncT, const char*>, Depth> GetMangled(
FuncT&& func = FrameFunctor())
{
using type = ResultOf_t<FuncT, const char*>;
auto ret = std::array<type, Depth>{};
ret.fill(func(""));
return ret;
}
template <size_t Depth, size_t Offset = 0, typename FuncT = frame_func_t>
static std::array<ResultOf_t<FuncT, const char*>, Depth> GetDemangled(
FuncT&& func = FrameFunctor())
{
using type = ResultOf_t<FuncT, const char*>;
auto ret = std::array<type, Depth>{};
ret.fill(func(""));
return ret;
}
// a functor called for each frame in the backtrace
static frame_func_t& FrameFunctor()
{
static frame_func_t _instance = [](const char* _s) { return std::string(_s); };
return _instance;
}
// default set of signals
static signal_set_t& DefaultSignals()
{
static signal_set_t _instance = {};
return _instance;
}
static actions& GetData()
{
static auto _instance = actions{};
return _instance;
}
};
//----------------------------------------------------------------------------//
} // namespace PTL
#endif // SIGNAL_AVAILABLE
#endif // Backtrace_hh
@@ -16,25 +16,16 @@
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// ---------------------------------------------------------------
// Tasking class header file
//
// Class Description:
//
// This file wraps a TBB task_group into a TaskGroup
//
// ---------------------------------------------------------------
// Author: Jonathan Madsen (Jun 21st 2018)
// ---------------------------------------------------------------
#pragma once
#include "PTL/TaskGroup.hh"
namespace PTL
{
// in new version, TaskGroup handles TBB
template <typename Tp, typename Arg = Tp>
using TBBTaskGroup = TaskGroup<Tp, Arg>;
//--------------------------------------------------------------------------------------//
// use this function to get rid of "unused parameter" warnings
//
template <typename... Args>
void
ConsumeParameters(Args&&...)
{}
} // namespace PTL
+93
View File
@@ -0,0 +1,93 @@
//
// MIT License
// Copyright (c) 2020 Jonathan R. Madsen
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED
// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//
#pragma once
#include <cctype>
#include <cstdlib>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <mutex>
#include <set>
#include <sstream> // IWYU pragma: keep
#include <string>
#include <tuple>
#include <utility>
namespace PTL
{
//--------------------------------------------------------------------------------------//
// use this function to get an environment variable setting +
// a default if not defined, e.g.
// int num_threads =
// GetEnv<int>("FORCENUMBEROFTHREADS",
// std::thread::hardware_concurrency());
//
template <typename Tp>
Tp
GetEnv(const std::string& env_id, Tp _default = Tp())
{
char* env_var = std::getenv(env_id.c_str());
if(env_var)
{
std::string str_var = std::string(env_var);
std::istringstream iss(str_var);
Tp var = Tp();
iss >> var;
return var;
}
// return default if not specified in environment
return _default;
}
//--------------------------------------------------------------------------------------//
// overload for boolean
//
template <>
inline bool
GetEnv(const std::string& env_id, bool _default)
{
char* env_var = std::getenv(env_id.c_str());
if(env_var)
{
std::string var = std::string(env_var);
bool val = true;
if(var.find_first_not_of("0123456789") == std::string::npos)
val = (bool) atoi(var.c_str());
else
{
for(auto& itr : var)
itr = tolower(itr);
if(var == "off" || var == "false")
val = false;
}
return val;
}
// return default if not specified in environment
return _default;
}
//--------------------------------------------------------------------------------------//
} // namespace PTL
+1 -1
View File
@@ -30,7 +30,7 @@
#pragma once
#include "PTL/Types.hh"
#include "PTL/Macros.hh"
#include <functional>
#include <utility>
+107
View File
@@ -0,0 +1,107 @@
//
// MIT License
// Copyright (c) 2020 Jonathan R. Madsen
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED
// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
#pragma once
#if defined(__APPLE__) || defined(__MACH__)
# if !defined(PTL_MACOS)
# define PTL_MACOS 1
# endif
# if !defined(PTL_UNIX)
# define PTL_UNIX 1
# endif
#endif
#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
# if !defined(PTL_WINDOWS)
# define PTL_WINDOWS 1
# endif
#endif
#if defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
# if !defined(PTL_LINUX)
# define PTL_LINUX 1
# endif
# if !defined(PTL_UNIX)
# define PTL_UNIX 1
# endif
#endif
#if defined(__unix__) || defined(__unix) || defined(unix)
# if !defined(PTL_UNIX)
# define PTL_UNIX 1
# endif
#endif
#if defined(PTL_WINDOWS)
// Disable warning C4786 on WIN32 architectures:
// identifier was truncated to '255' characters
// in the debug information
//
# pragma warning(disable : 4786)
//
// Define DLL export macro for WIN32 systems for
// importing/exporting external symbols to DLLs
//
# if defined PTL_BUILD_DLL
# define DLLEXPORT __declspec(dllexport)
# define DLLIMPORT __declspec(dllimport)
# else
# define DLLEXPORT
# define DLLIMPORT
# endif
//
// Unique identifier for global module
//
# if defined PTL_ALLOC_EXPORT
# define PTL_DLL DLLEXPORT
# else
# define PTL_DLL DLLIMPORT
# endif
#else
# define DLLEXPORT
# define DLLIMPORT
# define PTL_DLL
#endif
#if !defined(PTL_DEFAULT_OBJECT)
# define PTL_DEFAULT_OBJECT(NAME) \
NAME() = default; \
~NAME() = default; \
NAME(const NAME&) = default; \
NAME(NAME&&) = default; \
NAME& operator=(const NAME&) = default; \
NAME& operator=(NAME&&) = default;
#endif
#if !defined(PTL_NO_SANITIZE_THREAD)
// expect that sanitizer is from compiler which supports __has_attribute
# if defined(__has_attribute)
# if __has_attribute(no_sanitize)
# define PTL_NO_SANITIZE_THREAD __attribute__((no_sanitize("thread")))
# else
# define PTL_NO_SANITIZE_THREAD
# endif
# elif defined(__clang__) || defined(__GNUC__)
# define PTL_NO_SANITIZE_THREAD __attribute__((no_sanitize("thread")))
# else
// otherwise, make blank
# define PTL_NO_SANITIZE_THREAD
# endif
#endif
-5
View File
@@ -20,9 +20,6 @@
#pragma once
#include "PTL/AutoLock.hh"
#include "PTL/Backtrace.hh"
#include "PTL/Globals.hh"
#include "PTL/TBBTaskGroup.hh"
#include "PTL/Task.hh"
#include "PTL/TaskGroup.hh"
#include "PTL/TaskManager.hh"
@@ -30,9 +27,7 @@
#include "PTL/ThreadData.hh"
#include "PTL/ThreadPool.hh"
#include "PTL/Threading.hh"
#include "PTL/Timer.hh"
#include "PTL/Types.hh"
#include "PTL/UserTaskQueue.hh"
#include "PTL/Utility.hh"
#include "PTL/VTask.hh"
#include "PTL/VUserTaskQueue.hh"
+61
View File
@@ -0,0 +1,61 @@
//
// MIT License
// Copyright (c) 2020 Jonathan R. Madsen
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED
// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
#pragma once
#include <functional>
#include <utility>
namespace PTL
{
struct ScopeDestructor
{
template <typename FuncT>
ScopeDestructor(FuncT&& _func)
: m_functor(std::forward<FuncT>(_func))
{}
// delete copy operations
ScopeDestructor(const ScopeDestructor&) = delete;
ScopeDestructor& operator=(const ScopeDestructor&) = delete;
// allow move operations
ScopeDestructor(ScopeDestructor&& rhs) noexcept
: m_functor(std::move(rhs.m_functor))
{
rhs.m_functor = []() {};
}
ScopeDestructor& operator=(ScopeDestructor&& rhs) noexcept
{
if(this != &rhs)
{
m_functor = std::move(rhs.m_functor);
rhs.m_functor = []() {};
}
return *this;
}
~ScopeDestructor() { m_functor(); }
private:
std::function<void()> m_functor = []() {};
};
} // namespace PTL
-405
View File
@@ -1,405 +0,0 @@
// MIT License
//
// Copyright (c) 2020 Jonathan R. Madsen
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
//
#pragma once
#include <atomic>
#include <functional>
#include <memory>
#include <mutex>
#include <set>
#include <thread>
#include <type_traits>
namespace PTL
{
/// \class PTL::Singleton
/// \brief Singleton object that allows a deleter class to be specified
///
template <typename Type,
typename PointerT = std::unique_ptr<Type, std::default_delete<Type>>>
class Singleton
{
public:
using this_type = Singleton<Type, PointerT>;
using thread_id_t = std::thread::id;
using mutex_t = std::recursive_mutex;
using auto_lock_t = std::unique_lock<mutex_t>;
using pointer = Type*;
using list_t = std::set<pointer>;
using smart_pointer = PointerT;
using deleter_t = std::function<void(PointerT&)>;
template <bool B, typename T = int>
using enable_if_t = typename std::enable_if<B, T>::type;
public:
// Constructor and Destructors
Singleton();
Singleton(pointer);
~Singleton();
Singleton(const Singleton&) = delete;
Singleton(Singleton&&) = delete;
Singleton& operator=(const Singleton&) = delete;
Singleton& operator=(Singleton&&) = delete;
public:
// public static functions
static pointer GetInstance();
static pointer GetMasterInstance();
static thread_id_t GetMasterThreadID() { return f_master_thread(); }
static list_t Children() { return f_children(); }
static bool IsMaster(pointer ptr) { return ptr == GetRawMasterInstance(); }
static bool IsMasterThread();
static void Insert(pointer);
static void Remove(pointer);
static mutex_t& GetMutex() { return f_mutex(); }
public:
// public member function
void Initialize();
void Initialize(pointer);
void Destroy();
void Reset(pointer);
void Reset();
// since we are overloading delete we overload new
void* operator new(size_t)
{
this_type* ptr = ::new this_type();
return static_cast<void*>(ptr);
}
// overload delete so that f_master_instance is guaranteed to be
// a nullptr after deletion
void operator delete(void* ptr)
{
this_type* _instance = (this_type*) (ptr);
::delete _instance;
if(std::this_thread::get_id() == f_master_thread())
f_master_instance() = nullptr;
}
protected:
friend class Type;
// instance functions that do not Initialize
smart_pointer& GetSmartInstance() { return _local_instance(); }
static smart_pointer& GetSmartMasterInstance() { return _master_instance(); }
// for checking but not allocating
pointer GetRawInstance()
{
return IsMasterThread() ? f_master_instance() : _local_instance().get();
}
static pointer GetRawMasterInstance() { return f_master_instance(); }
private:
// Private functions
static smart_pointer& _local_instance()
{
static thread_local smart_pointer _instance = smart_pointer();
return _instance;
}
static smart_pointer& _master_instance()
{
static smart_pointer _instance = smart_pointer();
return _instance;
}
void* operator new[](std::size_t) noexcept { return nullptr; }
void operator delete[](void*) noexcept {}
template <typename Tp = Type, typename PtrT = PointerT,
enable_if_t<(std::is_same<PtrT, std::shared_ptr<Tp>>::value)> = 0>
deleter_t& GetDeleter()
{
static deleter_t _instance = [](PointerT&) {};
return _instance;
}
template <typename Tp = Type, typename PtrT = PointerT,
enable_if_t<!(std::is_same<PtrT, std::shared_ptr<Tp>>::value)> = 0>
deleter_t& GetDeleter()
{
static deleter_t _instance = [](PointerT& _master) {
auto& del = _master.get_deleter();
del(_master.get());
_master.reset(nullptr);
};
return _instance;
}
private:
// Private variables
struct persistent_data
{
thread_id_t m_master_thread = std::this_thread::get_id();
mutex_t m_mutex;
pointer m_master_instance = nullptr;
list_t m_children = {};
persistent_data() = default;
~persistent_data() = default;
persistent_data(const persistent_data&) = delete;
persistent_data(persistent_data&&) = delete;
persistent_data& operator=(const persistent_data&) = delete;
persistent_data& operator=(persistent_data&&) = delete;
persistent_data(pointer _master, std::thread::id _tid)
: m_master_thread(_tid)
, m_master_instance(_master)
{}
void reset()
{
m_master_instance = nullptr;
m_children.clear();
}
};
bool m_IsMaster = false;
static thread_id_t& f_master_thread();
static mutex_t& f_mutex();
static pointer& f_master_instance();
static list_t& f_children();
static persistent_data& f_persistent_data()
{
static persistent_data _instance;
return _instance;
}
};
//======================================================================================//
template <typename Type, typename PointerT>
typename Singleton<Type, PointerT>::thread_id_t&
Singleton<Type, PointerT>::f_master_thread()
{
return f_persistent_data().m_master_thread;
}
//--------------------------------------------------------------------------------------//
template <typename Type, typename PointerT>
typename Singleton<Type, PointerT>::pointer&
Singleton<Type, PointerT>::f_master_instance()
{
return f_persistent_data().m_master_instance;
}
//--------------------------------------------------------------------------------------//
template <typename Type, typename PointerT>
typename Singleton<Type, PointerT>::mutex_t&
Singleton<Type, PointerT>::f_mutex()
{
return f_persistent_data().m_mutex;
}
//--------------------------------------------------------------------------------------//
template <typename Type, typename PointerT>
typename Singleton<Type, PointerT>::list_t&
Singleton<Type, PointerT>::f_children()
{
return f_persistent_data().m_children;
}
//--------------------------------------------------------------------------------------//
template <typename Type, typename PointerT>
Singleton<Type, PointerT>::Singleton()
{
Initialize();
}
//--------------------------------------------------------------------------------------//
template <typename Type, typename PointerT>
Singleton<Type, PointerT>::Singleton(pointer ptr)
{
Initialize(ptr);
}
//--------------------------------------------------------------------------------------//
template <typename Type, typename PointerT>
Singleton<Type, PointerT>::~Singleton()
{
auto& del = GetDeleter();
del(_master_instance());
}
//--------------------------------------------------------------------------------------//
template <typename Type, typename PointerT>
void
Singleton<Type, PointerT>::Initialize()
{
if(!f_master_instance())
{
f_master_thread() = std::this_thread::get_id();
f_master_instance() = new Type();
}
}
//--------------------------------------------------------------------------------------//
template <typename Type, typename PointerT>
void
Singleton<Type, PointerT>::Initialize(pointer ptr)
{
if(!f_master_instance())
{
f_master_thread() = std::this_thread::get_id();
f_master_instance() = ptr;
}
}
//--------------------------------------------------------------------------------------//
template <typename Type, typename PointerT>
void
Singleton<Type, PointerT>::Destroy()
{
if(std::this_thread::get_id() == f_master_thread() && f_master_instance())
{
delete f_master_instance();
f_master_instance() = nullptr;
}
else
{
remove(_local_instance().get());
}
}
//--------------------------------------------------------------------------------------//
template <typename Type, typename PointerT>
typename Singleton<Type, PointerT>::pointer
Singleton<Type, PointerT>::GetInstance()
{
if(std::this_thread::get_id() == f_master_thread())
return GetMasterInstance();
else if(!_local_instance().get())
{
_local_instance().reset(new Type());
Insert(_local_instance().get());
}
return _local_instance().get();
}
//--------------------------------------------------------------------------------------//
template <typename Type, typename PointerT>
typename Singleton<Type, PointerT>::pointer
Singleton<Type, PointerT>::GetMasterInstance()
{
if(!f_master_instance())
{
f_master_thread() = std::this_thread::get_id();
f_master_instance() = new Type();
}
return f_master_instance();
}
//--------------------------------------------------------------------------------------//
template <typename Type, typename PointerT>
void
Singleton<Type, PointerT>::Reset(pointer ptr)
{
if(IsMaster(ptr))
{
if(_master_instance().get())
_master_instance().reset();
else if(f_master_instance())
{
auto& del = GetDeleter();
del(_master_instance());
f_master_instance() = nullptr;
}
f_persistent_data().reset();
}
else
{
_local_instance().reset();
}
}
//--------------------------------------------------------------------------------------//
template <typename Type, typename PointerT>
void
Singleton<Type, PointerT>::Reset()
{
if(IsMasterThread())
_master_instance().reset();
_local_instance().reset();
f_persistent_data().reset();
}
//--------------------------------------------------------------------------------------//
template <typename Type, typename PointerT>
bool
Singleton<Type, PointerT>::IsMasterThread()
{
return std::this_thread::get_id() == f_master_thread();
}
//--------------------------------------------------------------------------------------//
template <typename Type, typename PointerT>
void
Singleton<Type, PointerT>::Insert(pointer itr)
{
auto_lock_t l(f_mutex());
f_children().insert(itr);
}
//--------------------------------------------------------------------------------------//
template <typename Type, typename PointerT>
void
Singleton<Type, PointerT>::Remove(pointer itr)
{
auto_lock_t l(f_mutex());
for(auto litr = f_children().begin(); litr != f_children().end(); ++litr)
{
if(*litr == itr)
{
f_children().erase(litr);
break;
}
}
}
//--------------------------------------------------------------------------------------//
} // namespace PTL
+3 -3
View File
@@ -30,8 +30,8 @@
#pragma once
#include "PTL/Globals.hh"
#include "PTL/VTask.hh"
#include "PTL/detail/CxxBackports.hh"
#include <cstdint>
#include <future>
@@ -113,7 +113,7 @@ public:
public:
// execution operator
void operator()() final { mpl::apply(std::move(m_ptask), std::move(m_args)); }
void operator()() final { PTL::apply(std::move(m_ptask), std::move(m_args)); }
future_type get_future() final { return m_ptask.get_future(); }
void wait() final { return m_ptask.get_future().wait(); }
RetT get() final { return m_ptask.get_future().get(); }
@@ -165,7 +165,7 @@ public:
void operator()() final
{
if(m_ptask.valid())
mpl::apply(std::move(m_ptask), std::move(m_args));
PTL::apply(std::move(m_ptask), std::move(m_args));
}
future_type get_future() final { return m_ptask.get_future(); }
void wait() final { return m_ptask.get_future().wait(); }
+6 -5
View File
@@ -35,15 +35,15 @@
#ifndef G4GMAKE
#include "PTL/Config.hh"
#endif
#include "PTL/Globals.hh"
#include "PTL/JoinFunction.hh"
#include "PTL/ScopeDestructor.hh"
#include "PTL/Task.hh"
#include "PTL/ThreadData.hh"
#include "PTL/ThreadPool.hh"
#include "PTL/Threading.hh"
#include "PTL/Utility.hh"
#include "PTL/Types.hh"
#include "PTL/VTask.hh"
#include "PTL/VUserTaskQueue.hh"
#include "PTL/detail/CxxBackports.hh"
#include <atomic>
#include <chrono>
@@ -54,6 +54,7 @@
#include <iostream>
#include <memory>
#include <mutex>
#include <sstream> // IWYU pragma: keep
#include <stdexcept>
#include <thread>
#include <type_traits>
@@ -61,7 +62,7 @@
#include <vector>
#if defined(PTL_USE_TBB)
# include <tbb/task_group.h>
# include <tbb/task_group.h> // IWYU pragma: keep
#endif
namespace PTL
@@ -733,6 +734,6 @@ TaskGroup<Tp, Arg, MaxDepth>::internal_update()
}
template <typename Tp, typename Arg, intmax_t MaxDepth>
int TaskGroup<Tp, Arg, MaxDepth>::f_verbose = GetEnv<int>("PTL_VERBOSE", 0);
int TaskGroup<Tp, Arg, MaxDepth>::f_verbose = 0;
} // namespace PTL
+1 -1
View File
@@ -30,7 +30,7 @@
#pragma once
#include "PTL/Globals.hh"
#include "PTL/Macros.hh"
#include "PTL/Task.hh"
#include "PTL/TaskGroup.hh"
#include "PTL/ThreadPool.hh"
+2 -4
View File
@@ -26,7 +26,6 @@
#pragma once
#include "PTL/ThreadPool.hh"
#include "PTL/VUserTaskQueue.hh"
#include <cstddef>
#include <cstdint>
@@ -35,6 +34,7 @@
namespace PTL
{
class TaskManager;
class VUserTaskQueue;
//======================================================================================//
@@ -68,8 +68,6 @@ public:
ThreadPool* GetThreadPool() const { return m_thread_pool; }
TaskManager* GetTaskManager() const { return m_task_manager; }
bool IsInitialized() const { return m_is_initialized; }
int GetVerbose() const { return m_verbose; }
void SetVerbose(int val) { m_verbose = val; }
public: // with description
// Singleton implementing master thread behavior
@@ -83,8 +81,8 @@ private:
protected:
// Barriers: synch points between master and workers
bool m_is_initialized = false;
int m_verbose = 0;
uint64_t m_workers = 0;
bool m_use_tbb = false;
VUserTaskQueue* m_task_queue = nullptr;
ThreadPool* m_thread_pool = nullptr;
TaskManager* m_task_manager = nullptr;
+1 -1
View File
@@ -20,7 +20,7 @@
#ifndef G4GMAKE
#include "PTL/Config.hh" // IWYU pragma: keep
#endif
#include "PTL/Globals.hh"
#include "PTL/Macros.hh"
#include "PTL/VTask.hh"
#if defined(PTL_USE_LOCKS)
# include "PTL/AutoLock.hh"
+11 -50
View File
@@ -138,16 +138,11 @@ public:
struct Config
{
PTL_DEFAULT_OBJECT(Config)
Config(bool, bool, bool, int, int, size_type, VUserTaskQueue*, affinity_func_t,
initialize_func_t, finalize_func_t);
bool init = true;
bool use_tbb = f_use_tbb();
bool use_affinity = f_use_cpu_affinity();
int verbose = f_verbose();
int priority = f_thread_priority();
bool use_tbb = false;
bool use_affinity = false;
int verbose = 0;
int priority = 0;
size_type pool_size = f_default_pool_size();
VUserTaskQueue* task_queue = nullptr;
affinity_func_t set_affinity = affinity_functor();
@@ -158,16 +153,7 @@ public:
public:
// Constructor and Destructors
explicit ThreadPool(const Config&);
ThreadPool(const size_type& pool_size, VUserTaskQueue* task_queue = nullptr,
bool _use_affinity = f_use_cpu_affinity(),
affinity_func_t = affinity_functor(),
initialize_func_t = initialization_functor(),
finalize_func_t = finalization_functor());
ThreadPool(const size_type& pool_size, initialize_func_t, finalize_func_t,
bool _use_affinity = f_use_cpu_affinity(),
affinity_func_t = affinity_functor(),
VUserTaskQueue* task_queue = nullptr);
virtual ~ThreadPool();
~ThreadPool();
ThreadPool(const ThreadPool&) = delete;
ThreadPool(ThreadPool&&) = default;
ThreadPool& operator=(const ThreadPool&) = delete;
@@ -192,30 +178,9 @@ public:
bool is_tbb_threadpool() const { return m_tbb_tp; }
public:
// Public functions related to TBB
static bool using_tbb();
// enable using TBB if available - semi-deprecated
static void set_use_tbb(bool _v);
/// set the default use of tbb
static void set_default_use_tbb(bool _v) { set_use_tbb(_v); }
/// set the default use of cpu affinity
static void set_default_use_cpu_affinity(bool _v);
/// set the default scheduling priority of threads in thread-pool
static void set_default_scheduling_priority(int _v) { f_thread_priority() = _v; }
/// set the default verbosity
static void set_default_verbose(int _v) { f_verbose() = _v; }
/// set the default pool size
static void set_default_size(size_type _v) { f_default_pool_size() = _v; }
/// get the default use of tbb
static bool get_default_use_tbb() { return f_use_tbb(); }
/// get the default use of cpu affinity
static bool get_default_use_cpu_affinity() { return f_use_cpu_affinity(); }
/// get the default scheduling priority of threads in thread-pool
static int get_default_scheduling_priority() { return f_thread_priority(); }
/// get the default verbosity
static int get_default_verbose() { return f_verbose(); }
/// get the default pool size
static size_type get_default_size() { return f_default_pool_size(); }
@@ -278,12 +243,12 @@ public:
static uintmax_t get_this_thread_id();
static uintmax_t add_thread_id(ThreadId = ThisThread::get_id());
protected:
private:
void execute_thread(VUserTaskQueue*); // function thread sits in
int insert(task_pointer&&, int = -1);
int run_on_this(task_pointer&&);
protected:
private:
// called in THREAD INIT
static void start_thread(ThreadPool*, thread_data_t*, intmax_t = -1);
@@ -296,8 +261,8 @@ private:
bool m_use_affinity = false;
bool m_tbb_tp = false;
bool m_delete_task_queue = false;
int m_verbose = f_verbose();
int m_priority = f_thread_priority();
int m_verbose = 0;
int m_priority = 0;
size_type m_pool_size = 0;
ThreadId m_main_tid = ThisThread::get_id();
atomic_bool_type m_alive_flag = std::make_shared<std::atomic_bool>(false);
@@ -329,10 +294,6 @@ private:
affinity_func_t m_affinity_func = affinity_functor();
private:
static bool& f_use_tbb();
static bool& f_use_cpu_affinity();
static int& f_thread_priority();
static int& f_verbose();
static size_type& f_default_pool_size();
static thread_id_map_t& f_thread_ids();
};
@@ -531,7 +492,7 @@ ThreadPool::execute_on_all_threads(FuncT&& _func)
// size of the thread-pool
size_t _sz = size();
// number of cores
size_t _ncore = Threading::GetNumberOfCores();
size_t _ncore = GetNumberOfCores();
// maximum depth for recursion
size_t _dmax = std::max<size_t>(_ncore, 8);
// how many threads we need to initialize
@@ -643,7 +604,7 @@ ThreadPool::execute_on_specific_threads(const std::set<std::thread::id>& _tids,
// executed the _exec function above
std::atomic<size_t> _total_exec{ 0 };
// number of cores
size_t _ncore = Threading::GetNumberOfCores();
size_t _ncore = GetNumberOfCores();
// maximum depth for recursion
size_t _dmax = std::max<size_t>(_ncore, 8);
// how many threads we need to initialize
+7 -56
View File
@@ -21,64 +21,15 @@
//
// Class Description:
//
// This file defines types and macros used to expose Tasking threading model.
#pragma once
#include <array>
#include <cstddef>
#include <future>
#include <mutex>
#include <thread>
namespace PTL
{
// global thread types
using Thread = std::thread;
using NativeThread = std::thread::native_handle_type;
// std::thread::id does not cast to integer
using Pid_t = std::thread::id;
// Condition
using Condition = std::condition_variable;
// Thread identifier
using ThreadId = Thread::id;
// will be used in the future when migrating threading to task-based style
template <typename Tp>
using Future = std::future<Tp>;
template <typename Tp>
using SharedFuture = std::shared_future<Tp>;
template <typename Tp>
using Promise = std::promise<Tp>;
// global mutex types
using Mutex = std::mutex;
using RecursiveMutex = std::recursive_mutex;
// static functions: get_id(), sleep_for(...), sleep_until(...), yield(),
namespace ThisThread
{
using namespace std::this_thread;
}
// Helper function for getting a unique static mutex for a specific
// class or type
// Usage example:
// a template class "Cache<T>" that required a static
// mutex for specific to type T:
// AutoLock l(TypeMutex<Cache<T>>());
template <typename Tp, typename MutexTp = Mutex, size_t N = 4>
MutexTp&
TypeMutex(const unsigned int& _n = 0)
{
static std::array<MutexTp, N> _mutex_array{};
return _mutex_array[_n % N];
}
//======================================================================================//
#pragma once
#include "PTL/Types.hh"
namespace PTL
{
namespace Threading
{
enum
@@ -88,6 +39,7 @@ enum
WORKER_ID = 0,
GENERICTHREAD_ID = -1000
};
}
Pid_t
GetPidId();
@@ -116,5 +68,4 @@ SetPinAffinity(int idx, NativeThread& _t);
bool
SetThreadPriority(int _v, NativeThread& _t);
} // namespace Threading
} // namespace PTL
-194
View File
@@ -1,194 +0,0 @@
//
// MIT License
// Copyright (c) 2019 Jonathan R. Madsen
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED
// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// ----------------------------------------------------------------------
// Class Timer
//
// Class description:
//
// Class for timer objects, able to measure elasped user/system process time.
//
// Note: Uses <sys/times.h> & <unistd.h> - POSIX.1 defined
// If used, this header must be included in the source (.cc) file and it
// must be the first header file to be included!
//
// Member functions:
//
// Timer()
// Construct a timer object
// Start()
// Start timing
// Stop()
// Stop timing
// bool IsValid()
// Return true if have a valid time (ie start() and stop() called)
// double GetRealElapsed()
// Return the elapsed real time between last calling start() and stop()
// double GetSystemElapsed()
// Return the elapsed system time between last calling start() and stop()
// double GetUserElapsed()
// Return the elapsed user time between last calling start() and stop()
//
// Operators:
//
// std::ostream& operator << (std::ostream& os, const Timer& t);
// Print the elapsed real,system and usertimes on os. Prints **s for times
// if !IsValid
//
// Member data:
//
// bool fValidTimes
// True after start and stop have both been called more than once and
// an equal number of times
// clock_t fStartRealTime,fEndRealTime
// Real times (arbitrary time 0)
// tms fStartTimes,fEndTimes
// Timing structures (see times(2)) for start and end times
// History:
// 23.08.96 P.Kent Updated to also computed real elapsed time
// 21.08.95 P.Kent
// 29.04.97 G.Cosmo Added timings for Windows/NT
#pragma once
#include "PTL/Types.hh"
#include <chrono>
#include <iomanip>
#include <sstream>
#if !(defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64))
# include <sys/times.h>
# include <time.h>
#else
# include <ctime>
# define _SC_CLK_TCK 1
extern "C"
{
int sysconf(int);
};
// Structure returned by times()
struct tms
{
clock_t tms_utime; /* user time */
clock_t tms_stime; /* system time */
clock_t tms_cutime; /* user time, children */
clock_t tms_cstime; /* system time, children */
};
extern "C"
{
extern clock_t times(struct tms*);
};
#endif /* WIN32 */
namespace PTL
{
class Timer
{
public:
PTL_DEFAULT_OBJECT(Timer)
public:
void Start();
void Stop();
bool IsValid() const;
double GetRealElapsed() const;
double GetSystemElapsed() const;
double GetUserElapsed() const;
static const char* GetClockTime();
private:
bool fValidTimes{ false };
using clock_type = std::chrono::high_resolution_clock;
std::chrono::time_point<clock_type> fStartRealTime, fEndRealTime;
tms fStartTimes, fEndTimes;
};
// ------------------------------------------------------------
// class inline implementation
// ------------------------------------------------------------
inline void
Timer::Start()
{
fValidTimes = false;
times(&fStartTimes);
fStartRealTime = clock_type::now();
}
inline void
Timer::Stop()
{
times(&fEndTimes);
fEndRealTime = clock_type::now();
fValidTimes = true;
}
inline bool
Timer::IsValid() const
{
return fValidTimes;
}
inline const char*
Timer::GetClockTime()
{
time_t rawtime;
struct tm* timeinfo;
time(&rawtime);
timeinfo = localtime(&rawtime);
return asctime(timeinfo);
}
inline std::ostream&
operator<<(std::ostream& os, const Timer& t)
{
// so fixed doesn't propagate
std::stringstream ss;
ss << std::fixed;
if(t.IsValid())
{
ss << "Real=" << t.GetRealElapsed() << "s User=" << t.GetUserElapsed()
<< "s Sys=" << t.GetSystemElapsed() << "s";
// avoid possible FPE error
if(t.GetRealElapsed() > 1.0e-6)
{
double cpu_util =
(t.GetUserElapsed() + t.GetSystemElapsed()) / t.GetRealElapsed() * 100.0;
ss << std::setprecision(1);
ss << " [Cpu=" << std::setprecision(1) << cpu_util << "%]";
}
}
else
{
ss << "Real=****s User=****s Sys=****s";
}
os << ss.str();
return os;
}
} // namespace PTL
+52 -65
View File
@@ -21,73 +21,60 @@
#pragma once
#if defined(__APPLE__) || defined(__MACH__)
# if !defined(PTL_MACOS)
# define PTL_MACOS 1
# endif
# if !defined(PTL_UNIX)
# define PTL_UNIX 1
# endif
#endif
// This file defines types used to expose Tasking threading model.
#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
# if !defined(PTL_WINDOWS)
# define PTL_WINDOWS 1
# endif
#endif
#pragma once
#if defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
# if !defined(PTL_LINUX)
# define PTL_LINUX 1
# endif
# if !defined(PTL_UNIX)
# define PTL_UNIX 1
# endif
#endif
#include <array>
#include <cstddef>
#include <future>
#include <mutex>
#include <thread>
#if defined(__unix__) || defined(__unix) || defined(unix)
# if !defined(PTL_UNIX)
# define PTL_UNIX 1
# endif
#endif
namespace PTL
{
// global thread types
using Thread = std::thread;
using NativeThread = std::thread::native_handle_type;
// std::thread::id does not cast to integer
using Pid_t = std::thread::id;
#if defined(PTL_WINDOWS)
// Disable warning C4786 on WIN32 architectures:
// identifier was truncated to '255' characters
// in the debug information
//
# pragma warning(disable : 4786)
//
// Define DLL export macro for WIN32 systems for
// importing/exporting external symbols to DLLs
//
# if defined PTL_BUILD_DLL
# define DLLEXPORT __declspec(dllexport)
# define DLLIMPORT __declspec(dllimport)
# else
# define DLLEXPORT
# define DLLIMPORT
# endif
//
// Unique identifier for global module
//
# if defined PTL_ALLOC_EXPORT
# define PTL_DLL DLLEXPORT
# else
# define PTL_DLL DLLIMPORT
# endif
#else
# define DLLEXPORT
# define DLLIMPORT
# define PTL_DLL
#endif
// Condition
using Condition = std::condition_variable;
#if !defined(PTL_DEFAULT_OBJECT)
# define PTL_DEFAULT_OBJECT(NAME) \
NAME() = default; \
~NAME() = default; \
NAME(const NAME&) = default; \
NAME(NAME&&) = default; \
NAME& operator=(const NAME&) = default; \
NAME& operator=(NAME&&) = default;
#endif
// Thread identifier
using ThreadId = Thread::id;
// will be used in the future when migrating threading to task-based style
template <typename Tp>
using Future = std::future<Tp>;
template <typename Tp>
using SharedFuture = std::shared_future<Tp>;
template <typename Tp>
using Promise = std::promise<Tp>;
// global mutex types
using Mutex = std::mutex;
using RecursiveMutex = std::recursive_mutex;
// static functions: get_id(), sleep_for(...), sleep_until(...), yield(),
namespace ThisThread
{
using namespace std::this_thread;
}
// Helper function for getting a unique static mutex for a specific
// class or type
// Usage example:
// a template class "Cache<T>" that required a static
// mutex for specific to type T:
// AutoLock l(TypeMutex<Cache<T>>());
template <typename Tp, typename MutexTp = Mutex, size_t N = 4>
MutexTp&
TypeMutex(const unsigned int& _n = 0)
{
static std::array<MutexTp, N> _mutex_array{};
return _mutex_array[_n % N];
}
} // namespace PTL
+6 -3
View File
@@ -25,10 +25,9 @@
#pragma once
#include "PTL/Globals.hh"
#include "PTL/Macros.hh"
#include "PTL/TaskSubQueue.hh"
#include "PTL/Threading.hh"
#include "PTL/VTask.hh"
#include "PTL/Types.hh"
#include "PTL/VUserTaskQueue.hh"
#include <atomic>
@@ -39,6 +38,10 @@
namespace PTL
{
class ThreadData;
class ThreadPool;
class VTask;
class UserTaskQueue : public VUserTaskQueue
{
public:
-402
View File
@@ -1,402 +0,0 @@
//
// MIT License
// Copyright (c) 2020 Jonathan R. Madsen
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED
// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// Global utility functions
//
#pragma once
#include <cctype>
#include <cstdlib>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <mutex>
#include <set>
#include <sstream> // IWYU pragma: keep
#include <string>
#include <tuple>
#include <utility>
namespace PTL
{
//--------------------------------------------------------------------------------------//
// use this function to get rid of "unused parameter" warnings
//
template <typename... Args>
void
ConsumeParameters(Args&&...)
{}
//--------------------------------------------------------------------------------------//
// a non-string environment option with a string identifier
template <typename Tp>
using EnvChoice = std::tuple<Tp, std::string, std::string>;
//--------------------------------------------------------------------------------------//
// list of environment choices with non-string and string identifiers
template <typename Tp>
using EnvChoiceList = std::set<EnvChoice<Tp>>;
//--------------------------------------------------------------------------------------//
class EnvSettings
{
public:
using mutex_t = std::mutex;
using string_t = std::string;
using env_map_t = std::multimap<string_t, string_t>;
using env_pair_t = std::pair<string_t, string_t>;
public:
static EnvSettings* GetInstance()
{
static EnvSettings* _instance = new EnvSettings();
return _instance;
}
public:
template <typename Tp>
void insert(const std::string& env_id, Tp val)
{
std::stringstream ss;
ss << std::boolalpha << val;
m_mutex.lock();
if(m_env.find(env_id) != m_env.end())
{
for(const auto& itr : m_env)
if(itr.first == env_id && itr.second == ss.str())
{
m_mutex.unlock();
return;
}
}
m_env.insert(env_pair_t(env_id, ss.str()));
m_mutex.unlock();
}
template <typename Tp>
void insert(const std::string& env_id, EnvChoice<Tp> choice)
{
Tp& val = std::get<0>(choice);
std::string& str_val = std::get<1>(choice);
std::string& descript = std::get<2>(choice);
std::stringstream ss, ss_long;
ss << std::boolalpha << val;
ss_long << std::boolalpha << std::setw(8) << std::left << val << " # (\""
<< str_val << "\") " << descript;
m_mutex.lock();
if(m_env.find(env_id) != m_env.end())
{
for(const auto& itr : m_env)
if(itr.first == env_id && itr.second == ss.str())
{
m_mutex.unlock();
return;
}
}
m_env.insert(env_pair_t(env_id, ss_long.str()));
m_mutex.unlock();
}
const env_map_t& get() const { return m_env; }
mutex_t& mutex() const { return m_mutex; }
friend std::ostream& operator<<(std::ostream& os, const EnvSettings& env)
{
std::stringstream filler;
filler.fill('#');
filler << std::setw(90) << "";
std::stringstream ss;
ss << filler.str() << "\n# Environment settings:\n";
env.mutex().lock();
for(const auto& itr : env.get())
{
ss << "# " << std::setw(35) << std::right << itr.first << "\t = \t"
<< std::left << itr.second << "\n";
}
env.mutex().unlock();
ss << filler.str();
os << ss.str() << std::endl;
return os;
}
private:
env_map_t m_env;
mutable mutex_t m_mutex;
};
//--------------------------------------------------------------------------------------//
// use this function to get an environment variable setting +
// a default if not defined, e.g.
// int num_threads =
// GetEnv<int>("FORCENUMBEROFTHREADS",
// std::thread::hardware_concurrency());
//
template <typename Tp>
Tp
GetEnv(const std::string& env_id, Tp _default = Tp())
{
char* env_var = std::getenv(env_id.c_str());
if(env_var)
{
std::string str_var = std::string(env_var);
std::istringstream iss(str_var);
Tp var = Tp();
iss >> var;
// record value defined by environment
EnvSettings::GetInstance()->insert<Tp>(env_id, var);
return var;
}
// record default value
EnvSettings::GetInstance()->insert<Tp>(env_id, _default);
// return default if not specified in environment
return _default;
}
//--------------------------------------------------------------------------------------//
// overload for boolean
//
template <>
inline bool
GetEnv(const std::string& env_id, bool _default)
{
char* env_var = std::getenv(env_id.c_str());
if(env_var)
{
std::string var = std::string(env_var);
bool val = true;
if(var.find_first_not_of("0123456789") == std::string::npos)
val = (bool) atoi(var.c_str());
else
{
for(auto& itr : var)
itr = (char)std::tolower(itr);
if(var == "off" || var == "false")
val = false;
}
// record value defined by environment
EnvSettings::GetInstance()->insert<bool>(env_id, val);
return val;
}
// record default value
EnvSettings::GetInstance()->insert<bool>(env_id, false);
// return default if not specified in environment
return _default;
}
//--------------------------------------------------------------------------------------//
// overload for GetEnv + message when set
//
template <typename Tp>
Tp
GetEnv(const std::string& env_id, Tp _default, const std::string& msg)
{
char* env_var = std::getenv(env_id.c_str());
if(env_var)
{
std::string str_var = std::string(env_var);
std::istringstream iss(str_var);
Tp var = Tp();
iss >> var;
std::cout << "Environment variable \"" << env_id << "\" enabled with "
<< "value == " << var << ". " << msg << std::endl;
// record value defined by environment
EnvSettings::GetInstance()->insert<Tp>(env_id, var);
return var;
}
// record default value
EnvSettings::GetInstance()->insert<Tp>(env_id, _default);
// return default if not specified in environment
return _default;
}
//--------------------------------------------------------------------------------------//
// use this function to get an environment variable setting from set of choices
//
// EnvChoiceList<int> choices =
// { EnvChoice<int>(NN, "NN", "nearest neighbor interpolation"),
// EnvChoice<int>(LINEAR, "LINEAR", "bilinear interpolation"),
// EnvChoice<int>(CUBIC, "CUBIC", "bicubic interpolation") };
//
// int eInterp = GetEnv<int>("INTERPOLATION", choices, CUBIC);
//
template <typename Tp>
Tp
GetEnv(const std::string& env_id, const EnvChoiceList<Tp>& _choices, Tp _default)
{
auto asupper = [](std::string var) {
for(auto& itr : var)
itr = (char)std::toupper(itr);
return var;
};
char* env_var = std::getenv(env_id.c_str());
if(env_var)
{
std::string str_var = std::string(env_var);
std::string upp_var = asupper(str_var);
Tp var = Tp();
// check to see if string matches a choice
for(const auto& itr : _choices)
{
if(asupper(std::get<1>(itr)) == upp_var)
{
// record value defined by environment
EnvSettings::GetInstance()->insert(env_id, itr);
return std::get<0>(itr);
}
}
std::istringstream iss(str_var);
iss >> var;
// check to see if string matches a choice
for(const auto& itr : _choices)
{
if(var == std::get<0>(itr))
{
// record value defined by environment
EnvSettings::GetInstance()->insert(env_id, itr);
return var;
}
}
// the value set in env did not match any choices
std::stringstream ss;
ss << "\n### Environment setting error @ " << __FUNCTION__ << " (line "
<< __LINE__ << ")! Invalid selection for \"" << env_id
<< "\". Valid choices are:\n";
for(const auto& itr : _choices)
ss << "\t\"" << std::get<0>(itr) << "\" or \"" << std::get<1>(itr) << "\" ("
<< std::get<2>(itr) << ")\n";
std::cerr << ss.str() << std::endl;
abort();
}
std::string _name = "???";
std::string _desc = "description not provided";
for(const auto& itr : _choices)
if(std::get<0>(itr) == _default)
{
_name = std::get<1>(itr);
_desc = std::get<2>(itr);
break;
}
// record default value
EnvSettings::GetInstance()->insert(env_id, EnvChoice<Tp>(_default, _name, _desc));
// return default if not specified in environment
return _default;
}
//--------------------------------------------------------------------------------------//
template <typename Tp>
Tp
GetChoice(const EnvChoiceList<Tp>& _choices, const std::string& str_var)
{
auto asupper = [](std::string var) {
for(auto& itr : var)
itr = (char)std::toupper(itr);
return var;
};
std::string upp_var = asupper(str_var);
Tp var = Tp();
// check to see if string matches a choice
for(const auto& itr : _choices)
{
if(asupper(std::get<1>(itr)) == upp_var)
{
// record value defined by environment
return std::get<0>(itr);
}
}
std::istringstream iss(str_var);
iss >> var;
// check to see if string matches a choice
for(const auto& itr : _choices)
{
if(var == std::get<0>(itr))
{
// record value defined by environment
return var;
}
}
// the value set in env did not match any choices
std::stringstream ss;
ss << "\n### Environment setting error @ " << __FUNCTION__ << " (line " << __LINE__
<< ")! Invalid selection \"" << str_var << "\". Valid choices are:\n";
for(const auto& itr : _choices)
ss << "\t\"" << std::get<0>(itr) << "\" or \"" << std::get<1>(itr) << "\" ("
<< std::get<2>(itr) << ")\n";
std::cerr << ss.str() << std::endl;
abort();
}
//--------------------------------------------------------------------------------------//
inline void
PrintEnv(std::ostream& os = std::cout)
{
os << (*EnvSettings::GetInstance());
}
//--------------------------------------------------------------------------------------//
struct ScopeDestructor
{
template <typename FuncT>
ScopeDestructor(FuncT&& _func)
: m_functor(std::forward<FuncT>(_func))
{}
// delete copy operations
ScopeDestructor(const ScopeDestructor&) = delete;
ScopeDestructor& operator=(const ScopeDestructor&) = delete;
// allow move operations
ScopeDestructor(ScopeDestructor&& rhs) noexcept
: m_functor(std::move(rhs.m_functor))
{
rhs.m_functor = []() {};
}
ScopeDestructor& operator=(ScopeDestructor&& rhs) noexcept
{
if(this != &rhs)
{
m_functor = std::move(rhs.m_functor);
rhs.m_functor = []() {};
}
return *this;
}
~ScopeDestructor() { m_functor(); }
private:
std::function<void()> m_functor = []() {};
};
//--------------------------------------------------------------------------------------//
} // namespace PTL
+2 -2
View File
@@ -27,8 +27,8 @@
#pragma once
#include "PTL/Globals.hh"
#include "PTL/Threading.hh"
#include "PTL/Macros.hh"
#include "PTL/Types.hh"
#include <atomic>
#include <cstdint>
@@ -19,48 +19,25 @@
#pragma once
#include <algorithm> // Retrieve definitions of min/max
#include "PTL/ConsumeParameters.hh"
// Include base types
#include "PTL/Types.hh"
// Global utility functions
#include "PTL/Utility.hh"
#include <initializer_list>
#include <cstddef>
#include <tuple>
#include <type_traits>
#include <utility>
#if !defined(PTL_NO_SANITIZE_THREAD)
// expect that sanitizer is from compiler which supports __has_attribute
# if defined(__has_attribute)
# if __has_attribute(no_sanitize)
# define PTL_NO_SANITIZE_THREAD __attribute__((no_sanitize("thread")))
# else
# define PTL_NO_SANITIZE_THREAD
# endif
# elif defined(__clang__) || defined(__GNUC__)
# define PTL_NO_SANITIZE_THREAD __attribute__((no_sanitize("thread")))
# else
// otherwise, make blank
# define PTL_NO_SANITIZE_THREAD
# endif
#endif
/// Backports of C++ language features for use with C++11 compilers
namespace PTL
{
// Convenience wrappers
template <typename T>
using decay_t = typename std::decay<T>::type;
template <bool B, typename T = void>
using enable_if_t = typename std::enable_if<B, T>::type;
// for pre-C++14 tuple expansion to arguments
namespace mpl
{
//--------------------------------------------------------------------------------------//
/// Provision of tuple expansion to arguments
namespace impl
{
//--------------------------------------------------------------------------------------//
@@ -130,13 +107,6 @@ using index_sequence = integer_sequence<size_t, Idx...>;
template <size_t NumT>
using make_index_sequence = make_integer_sequence<size_t, NumT>;
/// Alias template index_sequence_for
template <typename... Types>
using index_sequence_for = make_index_sequence<sizeof...(Types)>;
template <size_t Idx, typename Tup>
using index_type_t = decay_t<decltype(std::get<Idx>(std::declval<Tup>()))>;
template <typename FnT, typename TupleT, size_t... Idx>
static inline auto
apply(FnT&& _func, TupleT _args, impl::index_sequence<Idx...>)
@@ -158,30 +128,14 @@ apply(FnT&& _func, TupleT _args, impl::index_sequence<Idx...>)
//--------------------------------------------------------------------------------------//
/// Alias template index_sequence
template <size_t... Idx>
using index_sequence = impl::integer_sequence<size_t, Idx...>;
/// Alias template make_index_sequence
template <size_t NumT>
using make_index_sequence = impl::make_integer_sequence<size_t, NumT>;
/// Alias template index_sequence_for
template <typename... Types>
using index_sequence_for = impl::make_index_sequence<sizeof...(Types)>;
template <typename FnT, typename TupleT>
static inline void
apply(FnT&& _func, TupleT&& _args)
{
using tuple_type = typename std::decay<TupleT>::type;
using tuple_type = decay_t<TupleT>;
constexpr auto N = std::tuple_size<tuple_type>::value;
impl::apply(std::forward<FnT>(_func), std::forward<TupleT>(_args),
impl::make_index_sequence<N>{});
}
//--------------------------------------------------------------------------------------//
} // namespace mpl
} // namespace PTL