netlist: Performance improvement and refactoring. [Couriersud]

Kidniki now achieves up to 910% when run with static solvers and with
nltool. That is significant better than the 860% we have seen
previously.

This increase is driven by using a global memory pool in the solver
code.

In addition the following refactoring and code maintenance work is
included. Please excuse the large commit, some of this took interfered
with other work and the detail development steps were ugly.

- gsl support: This commit adds pgsl.h which implements a very limited
  number of the functionality of the gsl header described in the c++ core
  guidelines.
- clang-tidy fixes
- A significant refactoring of palloc.h. Aligned hints were removed,
  they added complexity without a significant performance gain. Vector
  operations should better be done on special spans/views.

The code has been tested on linux with g++-7, g++-9, clang-11.
On Windows mingw-10 and VS2019, OSX clang-11.
This commit is contained in:
couriersud 2020-06-13 15:49:35 +02:00
parent 75681d760c
commit e949e9c29d
67 changed files with 1138 additions and 871 deletions

View File

@ -53,6 +53,7 @@ project "netlist"
MAME_DIR .. "src/lib/netlist/plib/pconfig.h",
MAME_DIR .. "src/lib/netlist/plib/palloc.h",
MAME_DIR .. "src/lib/netlist/plib/pchrono.h",
MAME_DIR .. "src/lib/netlist/plib/pgsl.h",
MAME_DIR .. "src/lib/netlist/plib/penum.h",
MAME_DIR .. "src/lib/netlist/plib/pexception.cpp",
MAME_DIR .. "src/lib/netlist/plib/pexception.h",

View File

@ -127,7 +127,7 @@ protected:
netlist::host_arena::unique_ptr<plib::dynlib_base> static_solver_lib() const noexcept override
{
//return plib::make_unique<plib::dynlib_static>(nullptr);
return netlist::host_arena::make_unique<plib::dynlib_static>(nl_static_solver_syms);
return plib::make_unique<plib::dynlib_static, netlist::host_arena>(nl_static_solver_syms);
}
private:
@ -169,7 +169,7 @@ protected:
netlist::host_arena::unique_ptr<plib::dynlib_base> static_solver_lib() const noexcept override
{
return netlist::host_arena::make_unique<plib::dynlib_static>(nullptr);
return plib::make_unique<plib::dynlib_static, netlist::host_arena>(nullptr);
}
private:
@ -181,7 +181,7 @@ class netlist_mame_device::netlist_mame_t : public netlist::netlist_state_t
public:
netlist_mame_t(netlist_mame_device &parent, const pstring &name)
: netlist::netlist_state_t(name, netlist::host_arena::make_unique<netlist_mame_device::netlist_mame_callbacks_t>(parent))
: netlist::netlist_state_t(name, plib::make_unique<netlist_mame_device::netlist_mame_callbacks_t, netlist::host_arena>(parent))
, m_parent(parent)
{
}
@ -978,7 +978,8 @@ netlist::host_arena::unique_ptr<netlist::netlist_state_t> netlist_mame_device::b
{
try
{
auto lnetlist = netlist::host_arena::make_unique<netlist::netlist_state_t>("netlist", netlist::host_arena::make_unique<netlist_validate_callbacks_t>());
auto lnetlist = plib::make_unique<netlist::netlist_state_t, netlist::host_arena>("netlist",
plib::make_unique<netlist_validate_callbacks_t, netlist::host_arena>());
// enable validation mode
lnetlist->set_extended_validation(true);
common_dev_start(lnetlist.get());

View File

@ -415,8 +415,8 @@ namespace analog
else
{
// linear
const auto Sqr1(static_cast<nl_fptype>(plib::pow(Vdsat - Vds, 2)));
const auto Sqr2(static_cast<nl_fptype>(plib::pow(nlconst::two() * Vdsat - Vds, 2)));
const auto Sqr1(plib::narrow_cast<nl_fptype>(plib::pow(Vdsat - Vds, 2)));
const auto Sqr2(plib::narrow_cast<nl_fptype>(plib::pow(nlconst::two() * Vdsat - Vds, 2)));
Cgb = 0;
Cgs = m_CoxWL * (nlconst::one() - Sqr1 / Sqr2) * nlconst::two_thirds();
Cgd = m_CoxWL * (nlconst::one() - Vdsat * Vdsat / Sqr2) * nlconst::two_thirds();

View File

@ -115,7 +115,7 @@ namespace netlist
, m_VL(*this, "VL")
, m_VREF(*this, "VREF")
{
m_type = static_cast<int>(m_modacc.m_TYPE);
m_type = plib::narrow_cast<int>(m_modacc.m_TYPE);
if (m_type < 1 || m_type > 3)
{
log().fatal(MF_OPAMP_UNKNOWN_TYPE(m_type));

View File

@ -561,11 +561,11 @@ namespace analog
{
register_subalias("P", P());
register_subalias("N", N());
if (m_func() != "")
if (!m_func().empty())
m_compiled->compile(m_func(), std::vector<pstring>({{pstring("T")}}));
}
NETLIB_IS_TIMESTEP(m_func() != "")
NETLIB_IS_TIMESTEP(!m_func().empty())
NETLIB_TIMESTEPI()
{
@ -609,11 +609,11 @@ namespace analog
{
register_subalias("P", P());
register_subalias("N", N());
if (m_func() != "")
if (!m_func().empty())
m_compiled->compile(m_func(), std::vector<pstring>({{pstring("T")}}));
}
NETLIB_IS_TIMESTEP(m_func() != "")
NETLIB_IS_TIMESTEP(!m_func().empty())
NETLIB_TIMESTEPI()
{
m_t += step;

View File

@ -25,11 +25,13 @@ VSBUILD = $(SRC)/buildVS
DOC = $(SRC)/documentation
TIDY_FLAGSX = -checks=*,-google*,-hicpp*,readability*,-fuchsia*,cert-*,-android-*,
TIDY_FLAGSX += -llvm-header-guard,-cppcoreguidelines-pro-type-reinterpret-cast,
TIDY_FLAGSX += -llvm-header-guard,
# TIDY_FLAGSX += -cppcoreguidelines-pro-type-reinterpret-cast,
TIDY_FLAGSX += -cppcoreguidelines-pro-bounds-pointer-arithmetic,
#TIDY_FLAGSX += -cppcoreguidelines-owning-memory,
TIDY_FLAGSX += -modernize-use-default-member-init,-cppcoreguidelines-pro-bounds-constant-array-index,
TIDY_FLAGSX += -modernize-pass-by-value,-cppcoreguidelines-pro-type-static-cast-downcast,
TIDY_FLAGSX += -modernize-pass-by-value,
#TIDY_FLAGSX += -cppcoreguidelines-pro-type-static-cast-downcast,
TIDY_FLAGSX += -cppcoreguidelines-avoid-magic-numbers,
TIDY_FLAGSX += -cppcoreguidelines-macro-usage,
TIDY_FLAGSX += -cppcoreguidelines-non-private-member-variables-in-classes,-misc-non-private-member-variables-in-classes,
@ -37,7 +39,7 @@ TIDY_FLAGSX += -bugprone-macro-parentheses,
#TIDY_FLAGSX += -misc-macro-parentheses,
TIDY_FLAGSX += -bugprone-too-small-loop-variable,
TIDY_FLAGSX += -modernize-use-trailing-return-type,
TIDY_FLAGSX += -cppcoreguidelines-pro-bounds-array-to-pointer-decay,
#TIDY_FLAGSX += -cppcoreguidelines-pro-bounds-array-to-pointer-decay,
TIDY_FLAGSX += -readability-magic-numbers,-readability-braces-around-statements,
TIDY_FLAGSX += -readability-implicit-bool-conversion,
TIDY_FLAGSX += -readability-named-parameter,-readability-function-size,
@ -85,7 +87,7 @@ CC = g++
LD = @g++
MD = @mkdir
RM = @rm
CLANG_TIDY = clang-tidy-10
CLANG_TIDY = clang-tidy-11
DEPENDCC=$(CC)
@ -132,6 +134,8 @@ POBJS := \
PMAIN := $(POBJ)/pmain.o
NLOBJS := \
$(NLOBJ)/solver/nld_solver.o \
$(NLOBJ)/solver/nld_matrix_solver.o \
$(NLOBJ)/nl_base.o \
$(NLOBJ)/nl_parser.o \
$(NLOBJ)/nl_setup.o \
@ -142,8 +146,6 @@ NLOBJS := \
$(NLOBJ)/analog/nld_switches.o \
$(NLOBJ)/analog/nlid_twoterm.o \
$(NLOBJ)/analog/nld_opamps.o \
$(NLOBJ)/solver/nld_solver.o \
$(NLOBJ)/solver/nld_matrix_solver.o \
$(NLOBJ)/tools/nl_convert.o \
$(NLOBJ)/generated/static_solvers.o \
$(NLOBJ)/devices/nld_2102A.o \
@ -287,27 +289,32 @@ native:
$(MAKE) CEXTRAFLAGS="-march=native -msse4.2 -Wall -Wpedantic -Wsign-compare -Wextra "
gcc9:
$(MAKE) CC=g++-9 LD=g++-9 CEXTRAFLAGS="-march=native -fext-numeric-literals -Wall -pedantic -Wpedantic -Wsign-compare -Wextra" EXTRALIBS="-lquadmath"
$(MAKE) CC=g++-9 LD=g++-9 CEXTRAFLAGS="-march=native -Wall -pedantic -Wpedantic -fext-numeric-literals -Wsign-compare -Wextra" EXTRALIBS="-lquadmath"
clang:
#$(MAKE) CC=clang++-11 LD=clang++-11 OBJ=obj/clang CEXTRAFLAGS="-march=native -msse4.2 -Weverything -Wall -pedantic -Wpedantic -Wunused-private-field -Wno-padded -Wno-unused-template -Wno-missing-variable-declarations -Wno-float-equal -Wconversion -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-format-nonliteral -Wno-exit-time-destructors"
$(MAKE) CC=clang++-11 LD=clang++-11 OBJ=obj/clang CEXTRAFLAGS="-march=native \
-mllvm -inline-threshold=2000 \
-Wunknown-warning-option \
-Weverything -Wall -pedantic -Wpedantic -Wunused-private-field \
-Werror -Wno-padded -Wno-weak-vtables -Wno-weak-template-vtables -Wno-unused-template \
-Wno-missing-variable-declarations -Wno-float-equal -Wconversion \
-Wmissing-variable-declarations -Wno-float-equal -Wconversion \
-Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-format-nonliteral \
-Wno-exit-time-destructors -Winconsistent-missing-destructor-override"
-Wno-exit-time-destructors -Winconsistent-missing-destructor-override \
-Wno-return-std-move-in-c++11 -Wno-unreachable-code"
clang-libc:
#clang-11 currently broken
#$(MAKE) CC=clang++-11 LD=clang++-11 OBJ=obj/clang CEXTRAFLAGS="-march=native -msse4.2 -Weverything -Wall -pedantic -Wpedantic -Wunused-private-field -Wno-padded -Wno-unused-template -Wno-missing-variable-declarations -Wno-float-equal -Wconversion -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-format-nonliteral -Wno-exit-time-destructors"
$(MAKE) CC=clang++-11 LD=clang++-11 OBJ=obj/clang-libc CEXTRAFLAGS="-march=native \
$(MAKE) CC=clang++-10 LD=clang++-10 OBJ=obj/clang-libc CEXTRAFLAGS="-march=native \
-stdlib=libc++ -mllvm -inline-threshold=2000 \
-Wunknown-warning-option \
-Weverything -Wall -pedantic -Wpedantic -Wunused-private-field \
-Werror -Wno-padded -Wno-weak-vtables -Wno-weak-template-vtables -Wno-unused-template \
-Wno-missing-variable-declarations -Wno-float-equal -Wconversion \
-Wmissing-variable-declarations -Wno-float-equal -Wconversion \
-Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-format-nonliteral \
-Wno-exit-time-destructors -Winconsistent-missing-destructor-override" \
-Wno-exit-time-destructors -Winconsistent-missing-destructor-override \
-Wno-return-std-move-in-c++11 -Wno-unreachable-code"
LDEXTRAFLAGS=-stdlib=libc++
clang-5:

View File

@ -9,6 +9,8 @@
#include "nl_errstr.h"
#include "solver/nld_solver.h"
#include <array>
namespace netlist
{
namespace devices
@ -18,6 +20,8 @@ namespace netlist
// nld_base_proxy
// -----------------------------------------------------------------------------
static const std::array<std::pair<const char *, const char *>, 3> power_syms = {{ {"VCC", "VEE"}, {"VCC", "GND"}, {"VDD", "VSS"}}};
nld_base_proxy::nld_base_proxy(netlist_state_t &anetlist, const pstring &name,
const logic_t *inout_proxied)
: device_t(anetlist, name, inout_proxied->logic_family())
@ -29,16 +33,15 @@ namespace netlist
throw nl_exception(MF_NULLPTR_FAMILY_NP("nld_base_proxy"));
}
const std::vector<std::pair<pstring, pstring>> power_syms = { {"VCC", "VEE"}, {"VCC", "GND"}, {"VDD", "VSS"}};
bool f = false;
for (const auto & pwr_sym : power_syms)
{
pstring devname = inout_proxied->device().name();
auto *tp_ct(anetlist.setup().find_terminal(devname + "." + pwr_sym.first,
auto *tp_ct(anetlist.setup().find_terminal(devname + "." + pstring(pwr_sym.first),
/*detail::terminal_type::INPUT,*/ false));
auto *tp_cn(anetlist.setup().find_terminal(devname + "." + pwr_sym.second,
auto *tp_cn(anetlist.setup().find_terminal(devname + "." + pstring(pwr_sym.second),
/*detail::terminal_type::INPUT,*/ false));
if ((tp_ct != nullptr) && (tp_cn != nullptr))
{
@ -47,8 +50,8 @@ namespace netlist
if (!tp_cn->is_analog())
throw nl_exception(plib::pfmt("Not an analog terminal: {1}")(tp_cn->name()));
auto *tp_t = static_cast<analog_t* >(tp_ct);
auto *tn_t = static_cast<analog_t *>(tp_cn);
auto *tp_t = dynamic_cast<analog_t* >(tp_ct);
auto *tn_t = dynamic_cast<analog_t *>(tp_cn);
if (f && (tp_t != nullptr && tn_t != nullptr))
log().warning(MI_MULTIPLE_POWER_TERMINALS_ON_DEVICE(inout_proxied->device().name(),
m_tp->name(), m_tn->name(),

View File

@ -93,7 +93,7 @@ namespace devices
, m_compiled(*this, "m_compiled")
, m_funcparam({nlconst::zero()})
{
if (m_func() != "")
if (!m_func().empty())
m_compiled->compile(m_func(), std::vector<pstring>({{pstring("T")}}));
connect(m_feedback, m_Q);
}

View File

@ -440,7 +440,7 @@ namespace devices
if (!m_ttbl)
{
m_ttbl = pool.make_unique<typename nld_truthtable_t<m_NI, m_NO>::truthtable_t>();
m_ttbl = plib::make_unique<typename nld_truthtable_t<m_NI, m_NO>::truthtable_t>(pool);
truthtable_parser desc_s(m_NO, m_NI,
packed_int(m_ttbl->m_out_state.data(), sizeof(m_ttbl->m_out_state[0]) * 8),
m_ttbl->m_timing_index.data(), m_ttbl->m_timing_nt.data());
@ -448,7 +448,7 @@ namespace devices
desc_s.parse(m_desc);
}
return pool.make_unique<tt_type>(anetlist, name, m_family_name, *m_ttbl, m_desc);
return plib::make_unique<tt_type>(pool, anetlist, name, m_family_name, *m_ttbl, m_desc);
}
private:
device_arena::unique_ptr<typename nld_truthtable_t<m_NI, m_NO>::truthtable_t> m_ttbl;
@ -578,7 +578,7 @@ void truthtable_parser::parse(const std::vector<pstring> &truthtable)
for (int j=0; j < 16; j++)
m_timing_nt[j] = netlist_time::zero();
while (!(ttline == ""))
while (!ttline.empty())
{
std::vector<pstring> io(plib::psplit(ttline,"|"));
// checks
@ -670,7 +670,7 @@ namespace factory
#define ENTRYY(n, m, s) case (n * 100 + m): \
{ using xtype = devices::netlist_factory_truthtable_t<n, m>; \
auto cs=s; \
ret = host_arena::make_unique<xtype>(desc.name, std::move(cs)); } \
ret = plib::make_unique<xtype, host_arena>(desc.name, std::move(cs)); } \
break
#define ENTRY(n, s) ENTRYY(n, 1, s); ENTRYY(n, 2, s); ENTRYY(n, 3, s); \
@ -700,7 +700,7 @@ namespace factory
nl_assert_always(false, msg.c_str());
}
ret->m_desc = desc.desc;
ret->m_family_name = (desc.family != "" ? desc.family : pstring(config::DEFAULT_LOGIC_FAMILY()));
ret->m_family_name = (!desc.family.empty() ? desc.family : pstring(config::DEFAULT_LOGIC_FAMILY()));
return ret;
}

View File

@ -27,7 +27,7 @@ namespace netlist
host_arena::unique_ptr<plib::dynlib_base> callbacks_t:: static_solver_lib() const
{
return host_arena::make_unique<plib::dynlib_static>(nullptr);
return plib::make_unique<plib::dynlib_static, host_arena>(nullptr);
}
// ----------------------------------------------------------------------------------------
@ -129,9 +129,9 @@ namespace netlist
m_lib = m_callbacks->static_solver_lib();
m_setup = host_arena::make_unique<setup_t>(*this);
m_setup = plib::make_unique<setup_t, host_arena>(*this);
// create the run interface
m_netlist = m_pool.make_unique<netlist_t>(*this, name);
m_netlist = plib::make_unique<netlist_t>(m_pool, *this, name);
// Make sure save states are invalidated when a new version is deployed
@ -313,7 +313,7 @@ namespace netlist
case 0:
{
std::vector<core_device_t *> d;
std::vector<nldelegate *> t;
std::vector<const nldelegate *> t;
log().verbose("Using default startup strategy");
for (auto &n : m_nets)
for (auto & term : n->core_terms())
@ -402,7 +402,7 @@ namespace netlist
}
log().verbose("Total calls : {1:12} {2:12} {3:12}", total_count,
total_time, total_time / static_cast<decltype(total_time)>((total_count > 0) ? total_count : 1));
total_time, total_time / gsl::narrow<decltype(total_time)>((total_count > 0) ? total_count : 1));
log().verbose("Total loop {1:15}", si.m_stat_mainloop());
log().verbose("Total time {1:15}", total_time);
@ -424,8 +424,8 @@ namespace netlist
}
plib::pperftime_t<true>::type total_overhead = overhead()
* static_cast<plib::pperftime_t<true>::type>(total_count)
/ static_cast<plib::pperftime_t<true>::type>(200000);
* gsl::narrow<plib::pperftime_t<true>::type>(total_count)
/ gsl::narrow<plib::pperftime_t<true>::type>(200000);
log().verbose("Queue Pushes {1:15}", si.m_queue.m_prof_call());
log().verbose("Queue Moves {1:15}", si.m_queue.m_prof_sortmove());
@ -436,7 +436,7 @@ namespace netlist
log().verbose("Take the next lines with a grain of salt. They depend on the measurement implementation.");
log().verbose("Total overhead {1:15}", total_overhead);
plib::pperftime_t<true>::type overhead_per_pop = (si.m_stat_mainloop()-2*total_overhead - (total_time - total_overhead))
/ static_cast<plib::pperftime_t<true>::type>(si.m_queue.m_prof_call());
/ gsl::narrow<plib::pperftime_t<true>::type>(si.m_queue.m_prof_call());
log().verbose("Overhead per pop {1:11}", overhead_per_pop );
log().verbose("");
}
@ -450,7 +450,7 @@ namespace netlist
if (stats->m_stat_inc_active() > 3 * stats->m_stat_total_time.count()
&& stats->m_stat_inc_active() > trigger)
log().verbose("HINT({}, NO_DEACTIVATE) // {} {} {}", ep->name(),
static_cast<nl_fptype>(stats->m_stat_inc_active()) / static_cast<nl_fptype>(stats->m_stat_total_time.count()),
gsl::narrow<nl_fptype>(stats->m_stat_inc_active()) / gsl::narrow<nl_fptype>(stats->m_stat_total_time.count()),
stats->m_stat_inc_active(), stats->m_stat_total_time.count());
}
log().verbose("");
@ -856,14 +856,14 @@ namespace netlist
pstring param_t::get_initial(const core_device_t *dev, bool *found) const
{
pstring res = dev->state().setup().get_initial_param_val(this->name(), "");
*found = (res != "");
*found = (!res.empty());
return res;
}
param_str_t::param_str_t(core_device_t &device, const pstring &name, const pstring &val)
: param_t(device, name)
{
m_param = host_arena::make_unique<pstring>(val);
m_param = plib::make_unique<pstring, host_arena>(val);
*m_param = device.state().setup().get_initial_param_val(this->name(),val);
}
@ -871,7 +871,7 @@ namespace netlist
: param_t(name)
{
// deviceless parameter, no registration, owner is responsible
m_param = host_arena::make_unique<pstring>(val);
m_param = plib::make_unique<pstring, host_arena>(val);
*m_param = state.setup().get_initial_param_val(this->name(),val);
}

View File

@ -708,9 +708,8 @@ namespace netlist
#endif
void set_delegate(const nldelegate &delegate) noexcept { m_delegate = delegate; }
nldelegate &delegate() noexcept { return m_delegate; }
const nldelegate &delegate() const noexcept { return m_delegate; }
inline void run_delegate() noexcept { m_delegate(); }
inline void run_delegate() noexcept { return m_delegate(); }
private:
nldelegate m_delegate;
net_t * m_net;
@ -997,7 +996,7 @@ namespace netlist
{
public:
using list_t = std::vector<analog_net_t *>;
using list_t = plib::aligned_vector<analog_net_t *>;
analog_net_t(netlist_state_t &nl, const pstring &aname, detail::core_terminal_t *railterminal = nullptr);
@ -1209,7 +1208,7 @@ namespace netlist
pstring valstr() const override
{
return plib::pfmt("{}").e(static_cast<nl_fptype>(m_param));
return plib::pfmt("{}").e(gsl::narrow<nl_fptype>(m_param));
}
private:
@ -1309,7 +1308,7 @@ namespace netlist
public:
template <typename P, typename Y=T, typename DUMMY = std::enable_if_t<plib::is_arithmetic<Y>::value>>
value_base_t(P &param, const pstring &name)
: m_value(static_cast<T>(param.value(name)))
: m_value(gsl::narrow<T>(param.value(name)))
{
}
template <typename P, typename Y=T, std::enable_if_t<!plib::is_arithmetic<Y>::value, int> = 0>
@ -1513,7 +1512,8 @@ namespace netlist
~device_t() noexcept override = default;
nldelegate default_delegate() { return nldelegate(&device_t::update, this); }
//nldelegate default_delegate() { return nldelegate(&device_t::update, this); }
nldelegate default_delegate() { return { &device_t::update, this }; }
protected:
NETLIB_UPDATEI() { }
@ -1757,7 +1757,7 @@ namespace netlist
template<typename T, typename... Args>
device_arena::unique_ptr<T> make_pool_object(Args&&... args)
{
return m_pool.make_unique<T>(std::forward<Args>(args)...);
return plib::make_unique<T>(m_pool, std::forward<Args>(args)...);
}
// memory pool - still needed in some places
device_arena &pool() noexcept { return m_pool; }
@ -2302,6 +2302,7 @@ namespace netlist
inline void detail::net_t::remove_from_active_list(core_terminal_t &term) noexcept
{
gsl_Expects(!m_list_active.empty());
m_list_active.remove(&term);
if (m_list_active.empty())
railterminal().device().do_dec_active();
@ -2309,24 +2310,24 @@ namespace netlist
inline const analog_net_t & analog_t::net() const noexcept
{
return static_cast<const analog_net_t &>(core_terminal_t::net());
return plib::downcast<const analog_net_t &>(core_terminal_t::net());
}
inline analog_net_t & analog_t::net() noexcept
{
return static_cast<analog_net_t &>(core_terminal_t::net());
return plib::downcast<analog_net_t &>(core_terminal_t::net());
}
inline nl_fptype terminal_t::operator ()() const noexcept { return net().Q_Analog(); }
inline logic_net_t & logic_t::net() noexcept
{
return static_cast<logic_net_t &>(core_terminal_t::net());
return plib::downcast<logic_net_t &>(core_terminal_t::net());
}
inline const logic_net_t & logic_t::net() const noexcept
{
return static_cast<const logic_net_t &>(core_terminal_t::net());
return plib::downcast<const logic_net_t &>(core_terminal_t::net());
}
inline netlist_sig_t logic_input_t::operator()() const noexcept
@ -2516,7 +2517,7 @@ namespace netlist
if (plib::is_integral<T>::value)
if (plib::abs(valx - plib::trunc(valx)) > nlconst::magic(1e-6))
throw nl_exception(MF_INVALID_NUMBER_CONVERSION_1_2(device.name() + "." + name, p));
m_param = static_cast<T>(valx);
m_param = plib::narrow_cast<T>(valx);
}
device.state().save(*this, m_param, this->name(), "m_param");
@ -2599,7 +2600,7 @@ namespace netlist
state_container<C>::state_container(O &owner, const pstring &name,
const state_container<C>::value_type & value)
{
owner.state().save(owner, *static_cast<C *>(this), owner.name(), name);
owner.state().save(owner, static_cast<C &>(*this), owner.name(), name);
for (std::size_t i=0; i < this->size(); i++)
(*this)[i] = value;
}
@ -2610,7 +2611,7 @@ namespace netlist
std::size_t n, const state_container<C>::value_type & value)
: C(n, value)
{
owner.state().save(owner, *static_cast<C *>(this), owner.name(), name);
owner.state().save(owner, static_cast<C &>(*this), owner.name(), name);
}
extern template struct state_var<std::uint8_t>;

View File

@ -200,6 +200,12 @@ namespace netlist
///
using MAX_QUEUE_SIZE = std::integral_constant<std::size_t, 512>; // NOLINT
using use_float_matrix = std::integral_constant<bool, NL_USE_FLOAT_MATRIX>;
using use_long_double_matrix = std::integral_constant<bool, NL_USE_LONG_DOUBLE_MATRIX>;
using use_float128_matrix = std::integral_constant<bool, NL_USE_FLOAT128>;
using use_mempool = std::integral_constant<bool, NL_USE_MEMPOOL>;
/// \brief Floating point types used
///
/// nl_fptype is the floating point type used throughout the

View File

@ -76,7 +76,7 @@ namespace factory {
device_arena::unique_ptr<core_device_t> library_element_t::make_device(device_arena &pool, netlist_state_t &anetlist, const pstring &name)
{
return pool.make_unique<NETLIB_NAME(wrapper)>(anetlist, name);
return plib::make_unique<NETLIB_NAME(wrapper)>(pool, anetlist, name);
}

View File

@ -129,7 +129,7 @@ namespace factory {
netlist_state_t &anetlist,
const pstring &name, std::tuple<Args...>& args, std::index_sequence<Is...>)
{
return pool.make_unique<C>(anetlist, name, std::forward<Args>(std::get<Is>(args))...);
return plib::make_unique<C>(pool, anetlist, name, std::forward<Args>(std::get<Is>(args))...);
}
dev_uptr make_device(device_arena &pool,
@ -149,7 +149,7 @@ namespace factory {
static uptr create(const pstring &name, properties &&props, Args&&... args)
{
return host_arena::make_unique<device_element_t<C, Args...>>(name,
return plib::make_unique<device_element_t<C, Args...>, host_arena>(name,
std::move(props), std::forward<Args>(args)...);
}
private:
@ -194,7 +194,7 @@ namespace factory {
template <typename T>
element_t::uptr constructor_t(const pstring &name, properties &&props)
{
return host_arena::make_unique<device_element_t<T>>(name, std::move(props));
return plib::make_unique<device_element_t<T>, host_arena>(name, std::move(props));
}
// -----------------------------------------------------------------------------

View File

@ -83,7 +83,7 @@ bool parser_t::parse(const pstring &nlname)
require_token(m_tok_paren_left);
token_t name = get_token();
require_token(m_tok_paren_right);
if (name.str() == nlname || nlname == "")
if (name.str() == nlname || nlname.empty())
{
parse_netlist(name.str());
return true;
@ -164,8 +164,8 @@ void parser_t::net_truthtable_start(const pstring &nlname)
netlist::tt_desc desc;
desc.name = name;
desc.ni = static_cast<unsigned long>(ni);
desc.no = static_cast<unsigned long>(no);
desc.ni = gsl::narrow<unsigned long>(ni);
desc.no = gsl::narrow<unsigned long>(no);
desc.family = "";
while (true)

View File

@ -200,7 +200,7 @@ namespace netlist
|| plib::abs(value) > nlconst::magic(1e9))
register_param(param, plib::pfmt("{1:.9}").e(value));
else
register_param(param, plib::pfmt("{1}")(static_cast<long>(value)));
register_param(param, plib::pfmt("{1}")(gsl::narrow<long>(value)));
}
void nlparse_t::register_param(const pstring &param, const pstring &value)
@ -248,7 +248,7 @@ namespace netlist
void nlparse_t::register_lib_entry(const pstring &name, factory::properties &&props)
{
m_factory.add(host_arena::make_unique<factory::library_element_t>(name, std::move(props)));
m_factory.add(plib::make_unique<factory::library_element_t, host_arena>(name, std::move(props)));
}
void nlparse_t::register_frontier(const pstring &attach, const pstring &r_IN,
@ -508,7 +508,7 @@ pstring setup_t::resolve_alias(const pstring &name) const
ret = temp;
auto p = m_abstract.m_alias.find(ret);
temp = (p != m_abstract.m_alias.end() ? p->second : "");
} while (temp != "" && temp != ret);
} while (!temp.empty() && temp != ret);
log().debug("{1}==>{2}\n", name, ret);
return ret;
@ -532,7 +532,7 @@ pstring setup_t::de_alias(const pstring &alias) const
break;
}
}
} while (temp != "" && temp != ret);
} while (!temp.empty() && temp != ret);
log().debug("{1}==>{2}\n", alias, ret);
return ret;
@ -650,7 +650,7 @@ devices::nld_base_proxy *setup_t::get_d_a_proxy(const detail::core_terminal_t &o
{
nl_assert(out.is_logic());
const auto &out_cast = static_cast<const logic_output_t &>(out);
const auto &out_cast = dynamic_cast<const logic_output_t &>(out);
auto iter_proxy(m_proxies.find(&out));
if (iter_proxy != m_proxies.end())
@ -878,7 +878,7 @@ void setup_t::connect_terminals(detail::core_terminal_t &t1,detail::core_termina
{
log().debug("adding analog net ...\n");
// FIXME: Nets should have a unique name
auto anet = nlstate().pool().make_owned<analog_net_t>(m_nlstate,"net." + t1.name());
auto anet = plib::make_owned<analog_net_t>(nlstate().pool(), m_nlstate,"net." + t1.name());
auto *anetp = anet.get();
m_nlstate.register_net(std::move(anet));
t1.set_net(anetp);
@ -1043,7 +1043,7 @@ void setup_t::resolve_inputs()
detail::core_terminal_t *t1 = find_terminal(t1s);
detail::core_terminal_t *t2 = find_terminal(t2s);
if (connect(*t1, *t2))
m_abstract.m_links.erase(m_abstract.m_links.begin() + static_cast<std::ptrdiff_t>(i));
m_abstract.m_links.erase(m_abstract.m_links.begin() + plib::narrow_cast<std::ptrdiff_t>(i));
else
i++;
}
@ -1104,16 +1104,16 @@ void setup_t::resolve_inputs()
detail::core_terminal_t *term = i.second;
if (term->is_tristate_output())
{
const auto *tri(static_cast<tristate_output_t *>(term));
const auto &tri(dynamic_cast<tristate_output_t &>(*term));
// check if we are connected to a proxy
const auto iter_proxy(m_proxies.find(tri));
const auto iter_proxy(m_proxies.find(&tri));
if (iter_proxy == m_proxies.end() && !tri->is_force_logic())
if (iter_proxy == m_proxies.end() && !tri.is_force_logic())
{
log().error(ME_TRISTATE_NO_PROXY_FOUND_2(term->name(), term->device().name()));
err = true;
}
else if (iter_proxy != m_proxies.end() && tri->is_force_logic())
else if (iter_proxy != m_proxies.end() && tri.is_force_logic())
{
log().error(ME_TRISTATE_PROXY_FOUND_2(term->name(), term->device().name()));
err = true;
@ -1256,7 +1256,7 @@ nl_fptype models_t::model_t::value(const pstring &entity) const
pstring tmp = value_str(entity);
nl_fptype factor = nlconst::one();
auto p = std::next(tmp.begin(), static_cast<pstring::difference_type>(tmp.size() - 1));
auto p = std::next(tmp.begin(), plib::narrow_cast<pstring::difference_type>(tmp.size() - 1));
switch (*p)
{
case 'M': factor = nlconst::magic(1e6); break; // NOLINT
@ -1390,7 +1390,7 @@ const logic_family_desc_t *setup_t::family_from_model(const pstring &model)
if (it != m_nlstate.family_cache().end())
return it->second.get();
auto ret = host_arena::make_unique<logic_family_std_proxy_t>(ft);
auto ret = plib::make_unique<logic_family_std_proxy_t, host_arena>(ft);
ret->m_low_thresh_PCNT = modv.m_IVL();
ret->m_high_thresh_PCNT = modv.m_IVH();
@ -1434,7 +1434,7 @@ void setup_t::prepare_to_run()
{
pstring envlog = plib::util::environment("NL_LOGS", "");
if (envlog != "")
if (!envlog.empty())
{
std::vector<pstring> loglist(plib::psplit(envlog, ":"));
m_parser.register_dynamic_log_devices(loglist);
@ -1444,7 +1444,7 @@ void setup_t::prepare_to_run()
for (auto & e : m_abstract.m_defparams)
{
auto param(host_arena::make_unique<param_str_t>(nlstate(), e.first, e.second));
auto param(plib::make_unique<param_str_t, host_arena>(nlstate(), e.first, e.second));
register_param_t(*param);
m_defparam_lifetime.push_back(std::move(param));
}
@ -1597,7 +1597,7 @@ source_string_t::stream_ptr source_string_t::stream(const pstring &name)
plib::unused_var(name);
auto ret(std::make_unique<std::istringstream>(m_str));
ret->imbue(std::locale::classic());
return std::move(ret); // FIXME: for c++11 clang builds
return ret;
}
source_mem_t::stream_ptr source_mem_t::stream(const pstring &name)
@ -1605,7 +1605,7 @@ source_mem_t::stream_ptr source_mem_t::stream(const pstring &name)
plib::unused_var(name);
auto ret(std::make_unique<std::istringstream>(m_str, std::ios_base::binary));
ret->imbue(std::locale::classic());
return std::move(ret); // FIXME: for c++11 clang builds
return ret;
}
source_file_t::stream_ptr source_file_t::stream(const pstring &name)

View File

@ -307,10 +307,10 @@ namespace netlist
void register_param(const pstring &param, nl_fptype value);
template <typename T>
std::enable_if_t<plib::is_floating_point<T>::value || plib::is_integral<T>::value>
std::enable_if_t<plib::is_arithmetic<T>::value>
register_param_val(const pstring &param, T value)
{
register_param(param, static_cast<nl_fptype>(value));
register_param(param, plib::narrow_cast<nl_fptype>(value));
}
void register_lib_entry(const pstring &name, factory::properties &&props);

View File

@ -78,9 +78,9 @@ namespace netlist
/// \note This is not the right location yet.
///
using device_arena = std::conditional<NL_USE_MEMPOOL,
using device_arena = std::conditional_t<config::use_mempool::value,
plib::mempool_arena<plib::aligned_arena>,
plib::aligned_arena>::type;
plib::aligned_arena>;
using host_arena = plib::aligned_arena;
/// \brief Interface definition for netlist callbacks into calling code

View File

@ -38,9 +38,9 @@ namespace plib
mat_precondition_ILU(std::size_t size, std::size_t ilu_scale = 4
, std::size_t bw = plib::pmatrix_cr_t<FT, SIZE>::FILL_INFINITY)
: m_mat(static_cast<typename mat_type::index_type>(size))
, m_LU(static_cast<typename mat_type::index_type>(size))
, m_ILU_scale(static_cast<std::size_t>(ilu_scale))
: m_mat(narrow_cast<typename mat_type::index_type>(size))
, m_LU(narrow_cast<typename mat_type::index_type>(size))
, m_ILU_scale(narrow_cast<std::size_t>(ilu_scale))
, m_band_width(bw)
{
}
@ -103,7 +103,7 @@ namespace plib
if (m_mat.col_idx[k] == i && k < m_mat.row_idx[j+1])
nzcol[i].push_back(k);
}
nzcol[i].push_back(static_cast<std::size_t>(-1));
nzcol[i].push_back(narrow_cast<std::size_t>(-1));
}
}
@ -139,7 +139,7 @@ namespace plib
const auto &nz = nzcol[i];
std::size_t j;
while ((j = nz[nzcolp++])!=static_cast<std::size_t>(-1)) // NOLINT(bugprone-infinite-loop)
while ((j = nz[nzcolp++])!=narrow_cast<std::size_t>(-1)) // NOLINT(bugprone-infinite-loop)
{
v += m_mat.A[j] * m_mat.A[j];
}
@ -209,14 +209,12 @@ namespace plib
// FIXME: hardcoding RESTART to 20 becomes an issue on very large
// systems.
template <typename FT, int SIZE, int RESTART = 80>
template <typename FT, int SIZE, int RESTART = 16>
struct gmres_t
{
public:
using float_type = FT;
// FIXME: dirty hack to make this compile
static constexpr const std::size_t storage_N = plib::sizeabs<FT, SIZE>::ABS();
explicit gmres_t(std::size_t size)
: residual(size)
@ -236,7 +234,7 @@ namespace plib
g1 = s * g0_last + c * g1;
}
std::size_t size() const { return (SIZE<=0) ? m_size : static_cast<std::size_t>(SIZE); }
std::size_t size() const { return (SIZE<=0) ? m_size : narrow_cast<std::size_t>(SIZE); }
template <int k, typename OPS, typename VT>
bool do_k(OPS &ops, VT &x, std::size_t &itr_used, FT rho_delta, bool dummy)
@ -360,7 +358,7 @@ namespace plib
rho_delta = accuracy * rho_to_accuracy;
}
else
rho_delta = accuracy * plib::sqrt(static_cast<FT>(n));
rho_delta = accuracy * plib::sqrt(narrow_cast<FT>(n));
//
// Using
@ -407,8 +405,6 @@ namespace plib
private:
//typedef typename plib::mat_cr_t<FT, SIZE>::index_type mattype;
plib::parray<float_type, SIZE> residual;
plib::parray<float_type, SIZE> Ax;
@ -423,8 +419,6 @@ namespace plib
std::size_t m_size;
bool m_use_more_precise_stop_condition;
};
@ -454,7 +448,7 @@ namespace plib
{
}
std::size_t size() const { return (SIZE<=0) ? m_size : static_cast<std::size_t>(SIZE); }
std::size_t size() const { return (SIZE<=0) ? m_size : narrow_cast<std::size_t>(SIZE); }
template <typename OPS, typename VT, typename VRHS>
std::size_t solve(OPS &ops, VT &x0, const VRHS & rhs, const std::size_t iter_max, float_type accuracy)
@ -478,7 +472,7 @@ namespace plib
ops.calc_rhs(Ax, x);
vec_sub(size(), rhs, Ax, residual);
FT rho_delta = accuracy * std::sqrt(static_cast<FT>(size()));
FT rho_delta = accuracy * std::sqrt(narrow_cast<FT>(size()));
rho_delta = 1e-9;

View File

@ -73,7 +73,7 @@ namespace plib
~pmatrix_cr_t() = default;
constexpr std::size_t size() const noexcept { return (N>0) ? static_cast<std::size_t>(N) : m_size; }
constexpr std::size_t size() const noexcept { return (N>0) ? narrow_cast<std::size_t>(N) : m_size; }
void clear() noexcept
{
@ -132,9 +132,9 @@ namespace plib
row_idx[k] = nz;
for (std::size_t j=0; j < size(); j++)
if (f[k][j] <= max_fill && plib::abs(static_cast<int>(k)-static_cast<int>(j)) <= static_cast<int>(band_width))
if (f[k][j] <= max_fill && plib::abs(narrow_cast<int>(k)-narrow_cast<int>(j)) <= narrow_cast<int>(band_width))
{
col_idx[nz] = static_cast<C>(j);
col_idx[nz] = narrow_cast<C>(j);
if (j == k)
diag[k] = nz;
nz++;
@ -150,7 +150,7 @@ namespace plib
{
for (std::size_t j=k + 1; j < size(); j++)
if (f[j][k] < FILL_INFINITY)
nzbd[k].push_back(static_cast<C>(j));
nzbd[k].push_back(narrow_cast<C>(j));
nzbd[k].push_back(0); // end of sequence
}
@ -343,7 +343,7 @@ namespace plib
{
for (std::size_t i = 0; i < m_ge_par.size(); i++)
if (plib::container::contains( m_ge_par[i], k))
return static_cast<int>(i);
return narrow_cast<int>(i);
return -1;
}
@ -525,7 +525,7 @@ namespace plib
}
}
if (found)
ilu_rows[p++] = static_cast<index_type>(i);
ilu_rows[p++] = narrow_cast<index_type>(i);
}
ilu_rows[p] = 0; // end of array
this->build_from_fill_mat(fill, ilup); //, m_band_width); // ILU(2)

View File

@ -9,6 +9,7 @@
///
#include "pconfig.h"
#include "pgsl.h"
#include "pmath.h"
#include "pstring.h"
#include "ptypes.h"
@ -26,28 +27,52 @@
namespace plib {
//============================================================
// aligned types
//============================================================
#if 0
#if (PUSE_ALIGNED_HINTS)
template <typename T, std::size_t A>
using aligned_type __attribute__((aligned(A))) = T;
#else
template <typename T, std::size_t A>
using aligned_type = T;
#endif
template <typename T, std::size_t A>
using aligned_pointer = aligned_type<T, A> *;
template <typename T, std::size_t A>
using const_aligned_pointer = const aligned_type<T, A> *;
template <typename T, std::size_t A>
using aligned_reference = aligned_type<T, A> &;
template <typename T, std::size_t A>
using const_aligned_reference = const aligned_type<T, A> &;
#endif
//============================================================
// Standard arena_deleter
//============================================================
template <typename P, typename T, typename A = void>
struct arena_deleter
template <typename P, typename T, bool X>
struct arena_deleter_base
{
};
template <typename P, typename T>
struct arena_deleter<P, T, std::enable_if_t<!P::has_static_deallocator>>
struct arena_deleter_base<P, T, false>
{
using arena_storage_type = P;
constexpr arena_deleter(arena_storage_type *a = nullptr) noexcept
constexpr arena_deleter_base(arena_storage_type *a = nullptr) noexcept
: m_a(a) { }
template<typename U, typename =
std::enable_if_t<std::is_convertible< U*, T*>::value>>
arena_deleter(const arena_deleter<P, U> &rhs) noexcept
arena_deleter_base(const arena_deleter_base<P, U, false> &rhs) noexcept
: m_a(rhs.m_a) { }
void operator()(T *p) noexcept
@ -61,18 +86,18 @@ namespace plib {
};
template <typename P, typename T>
struct arena_deleter<P, T, std::enable_if_t<P::has_static_deallocator>>
struct arena_deleter_base<P, T, true>
{
using arena_storage_type = P;
constexpr arena_deleter(arena_storage_type *a = nullptr) noexcept
constexpr arena_deleter_base(arena_storage_type *a = nullptr) noexcept
{
plib::unused_var(a);
}
template<typename U, typename = typename
std::enable_if<std::is_convertible< U*, T*>::value>::type>
arena_deleter(const arena_deleter<P, U> &rhs) noexcept
arena_deleter_base(const arena_deleter_base<P, U, true> &rhs) noexcept
{
plib::unused_var(rhs);
}
@ -85,6 +110,13 @@ namespace plib {
}
};
template <typename P, typename T>
struct arena_deleter : public arena_deleter_base<P, T, P::has_static_deallocator>
{
using base_type = arena_deleter_base<P, T, P::has_static_deallocator>;
using base_type::base_type;
};
//============================================================
// owned_ptr: smart pointer with ownership information
//============================================================
@ -209,7 +241,8 @@ namespace plib {
{
public:
using value_type = T;
static constexpr const std::size_t align_size = ALIGN;
using pointer = T *;
static /*constexpr*/ const std::size_t align_size = ALIGN;
using arena_type = ARENA;
static_assert(align_size >= alignof(T) && (align_size % alignof(T)) == 0,
@ -237,14 +270,14 @@ namespace plib {
using other = arena_allocator<ARENA, U, ALIGN>;
};
T* allocate(std::size_t n)
pointer allocate(std::size_t n)
{
return reinterpret_cast<T *>(m_a.allocate(ALIGN, sizeof(T) * n)); //NOLINT
}
void deallocate(T* p, std::size_t n) noexcept
void deallocate(pointer p, std::size_t n) noexcept
{
m_a.deallocate(p, n);
m_a.deallocate(p, sizeof(T) * n);
}
template<typename U, typename... Args>
@ -296,171 +329,88 @@ namespace plib {
// The previous code compiled with gcc and clang on all platforms and
// compilers apart from MSVC.
template <typename P, bool HSD>
template <typename P, bool HSD, bool HSA>
struct arena_base;
template <typename P, bool HSD, bool HSA>
struct arena_core
{
static constexpr const bool has_static_deallocator = HSD;
static constexpr const bool has_static_allocator = HSA;
using size_type = std::size_t;
template <class T, size_type ALIGN = alignof(T)>
using allocator_type = arena_allocator<P, T, ALIGN>;
template <class T>
using deleter_type = arena_deleter<P, T>;
template <typename T>
using unique_ptr = std::unique_ptr<T, deleter_type<T>>;
template <typename T>
using owned_ptr = plib::owned_ptr<T, deleter_type<T>>;
static inline P &instance() noexcept
{
static P s_arena;
return s_arena;
}
size_type cur_alloc() const noexcept { return m_stat_cur_alloc(); } // NOLINT(readability-convert-member-functions-to-static)
size_type max_alloc() const noexcept { return m_stat_max_alloc(); } // NOLINT(readability-convert-member-functions-to-static)
protected:
static size_t &m_stat_cur_alloc() noexcept { static size_t val = 0; return val; }
static size_t &m_stat_max_alloc() noexcept { static size_t val = 0; return val; }
friend struct arena_base<P, HSD, HSA>;
private:
size_t m_stat_cur_alloc = 0;
size_t m_stat_max_alloc = 0;
};
template <typename P, bool HSD>
struct arena_hsd : public arena_core<P, HSD>
template <typename P, bool HSD, bool HSA>
struct arena_base : public arena_core<P, HSD, HSA>
{
template<typename T>
inline void free(T *ptr) noexcept
using base_type = arena_core<P, HSD, HSA>;
using size_type = typename base_type::size_type;
static size_type cur_alloc() noexcept { return base_type::instance().m_stat_cur_alloc; }
static size_type max_alloc() noexcept { return base_type::instance().m_stat_max_alloc; }
static inline void inc_alloc_stat(size_type size)
{
ptr->~T();
static_cast<P *>(this)->deallocate(ptr, sizeof(T));
auto &i = base_type::instance();
i.m_stat_cur_alloc += size;
if (i.m_stat_max_alloc <i.m_stat_cur_alloc)
i.m_stat_max_alloc = i.m_stat_cur_alloc;
}
static inline void dec_alloc_stat(size_type size)
{
base_type::instance().m_stat_cur_alloc -= size;
}
};
template <typename P>
struct arena_hsd<P, true> : public arena_core<P, true>
struct arena_base<P, false, false> : public arena_core<P, false, false>
{
template<typename T>
static inline void free(T *ptr) noexcept
using size_type = typename arena_core<P, false, false>::size_type;
size_type cur_alloc() const noexcept { return this->m_stat_cur_alloc; }
size_type max_alloc() const noexcept { return this->m_stat_max_alloc; }
inline void inc_alloc_stat(size_type size)
{
ptr->~T();
P::deallocate(ptr, sizeof(T));
this->m_stat_cur_alloc += size;
if (this->m_stat_max_alloc < this->m_stat_cur_alloc)
this->m_stat_max_alloc = this->m_stat_cur_alloc;
}
inline void dec_alloc_stat(size_type size)
{
this->m_stat_cur_alloc -= size;
}
};
template <typename P, bool HSD, bool HSA>
struct arena_base : public arena_hsd<P, HSD>
{
template <class T>
using deleter_type = arena_deleter<P, T>;
template <typename T>
using unique_ptr = std::unique_ptr<T, deleter_type<T>>;
template <typename T>
using owned_ptr = plib::owned_ptr<T, deleter_type<T>>;
template<typename T, typename... Args>
inline unique_ptr<T> make_unique(Args&&... args)
{
auto *mem = static_cast<P *>(this)->allocate(alignof(T), sizeof(T));
try
{
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
auto *mema = new (mem) T(std::forward<Args>(args)...);
return unique_ptr<T>(mema, deleter_type<T>());
}
catch (...)
{
static_cast<P *>(this)->deallocate(mem, sizeof(T));
throw;
}
}
template<typename T, typename... Args>
inline owned_ptr<T> make_owned(Args&&... args)
{
auto *mem = static_cast<P *>(this)->allocate(alignof(T), sizeof(T));
try
{
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
auto *mema = new (mem) T(std::forward<Args>(args)...);
return owned_ptr<T>(mema, true, deleter_type<T>());
}
catch (...)
{
static_cast<P *>(this)->deallocate(mem, sizeof(T));
throw;
}
}
template<typename T, typename... Args>
inline T * alloc(Args&&... args)
{
auto *p = static_cast<P *>(this)->allocate(alignof(T), sizeof(T));
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
return new(p) T(std::forward<Args>(args)...);
}
};
template <typename P, bool HSD>
struct arena_base<P, HSD, true> : public arena_hsd<P, HSD>
{
template <class T>
using deleter_type = arena_deleter<P, T>;
template <typename T>
using unique_ptr = std::unique_ptr<T, deleter_type<T>>;
template <typename T>
using owned_ptr = plib::owned_ptr<T, deleter_type<T>>;
template<typename T, typename... Args>
static inline unique_ptr<T> make_unique(Args&&... args)
{
auto *mem = P::allocate(alignof(T), sizeof(T));
try
{
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
auto *mema = new (mem) T(std::forward<Args>(args)...);
return unique_ptr<T>(mema, deleter_type<T>());
}
catch (...)
{
P::deallocate(mem, sizeof(T));
throw;
}
}
template<typename T, typename... Args>
static inline owned_ptr<T> make_owned(Args&&... args)
{
auto *mem = P::allocate(alignof(T), sizeof(T));
try
{
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
auto *mema = new (mem) T(std::forward<Args>(args)...);
return owned_ptr<T>(mema, true, deleter_type<T>());
}
catch (...)
{
P::deallocate(mem, sizeof(T));
throw;
}
}
template<typename T, typename... Args>
static inline T * alloc(Args&&... args)
{
auto *p = P::allocate(alignof(T), sizeof(T));
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
return new(p) T(std::forward<Args>(args)...);
}
};
struct aligned_arena : public arena_base<aligned_arena, true, true>
{
static inline void *allocate( size_t alignment, size_t size )
static inline gsl::owner<void *> allocate( size_t alignment, size_t size )
{
m_stat_cur_alloc() += size;
if (m_stat_max_alloc() < m_stat_cur_alloc())
m_stat_max_alloc() = m_stat_cur_alloc();
inc_alloc_stat(size);
#if (PUSE_ALIGNED_ALLOCATION)
#if defined(_WIN32) || defined(_WIN64) || defined(_MSC_VER)
@ -472,7 +422,7 @@ namespace plib {
}
return p;
#else
return aligned_alloc(alignment, size);
return static_cast<gsl::owner<void *>>(aligned_alloc(alignment, size));
#endif
#else
unused_var(alignment);
@ -480,10 +430,10 @@ namespace plib {
#endif
}
static inline void deallocate( void *ptr, size_t size ) noexcept
static inline void deallocate(gsl::owner<void *> ptr, size_t size ) noexcept
{
//unused_var(size);
m_stat_cur_alloc() -= size;
dec_alloc_stat(size);
#if (PUSE_ALIGNED_ALLOCATION)
// NOLINTNEXTLINE(cppcoreguidelines-no-malloc)
::free(ptr);
@ -504,14 +454,14 @@ namespace plib {
{
static inline void *allocate( size_t alignment, size_t size )
{
m_stat_cur_alloc() += size;
inc_alloc_stat(size);
unused_var(alignment);
return ::operator new(size);
}
static inline void deallocate( void *ptr, size_t size ) noexcept
{
m_stat_cur_alloc() -= size;
dec_alloc_stat(size);
::operator delete(ptr);
}
@ -522,31 +472,116 @@ namespace plib {
}
};
template <typename T, std::size_t ALIGN>
constexpr T *assume_aligned_ptr(T *p) noexcept
namespace detail
{
static_assert(ALIGN >= alignof(T), "Alignment must be greater or equal to alignof(T)");
static_assert(is_pow2(ALIGN), "Alignment must be a power of 2");
template<typename T, typename ARENA, typename... Args>
static inline T * alloc(Args&&... args)
{
auto *mem = ARENA::allocate(alignof(T), sizeof(T));
try
{
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
return new (mem) T(std::forward<Args>(args)...);
}
catch (...)
{
ARENA::deallocate(mem, sizeof(T));
throw;
}
}
#if (PUSE_ALIGNED_HINTS)
return reinterpret_cast<T *>(__builtin_assume_aligned(p, ALIGN));
#else
return p;
#endif
template<typename ARENA, typename T>
static inline void free(T *ptr) noexcept
{
ptr->~T();
ARENA::deallocate(ptr, sizeof(T));
}
template<typename T, typename ARENA, typename... Args>
static inline T * alloc(ARENA &arena, Args&&... args)
{
auto *mem = arena.allocate(alignof(T), sizeof(T));
try
{
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
return new (mem) T(std::forward<Args>(args)...);
}
catch (...)
{
arena.deallocate(mem, sizeof(T));
throw;
}
}
template<typename ARENA, typename T>
static inline void free(ARENA &arena, T *ptr) noexcept
{
ptr->~T();
arena.deallocate(ptr, sizeof(T));
}
} // namespace detail
template<typename T, typename ARENA, typename... Args>
static inline
std::enable_if_t<ARENA::has_static_allocator, typename ARENA::template unique_ptr<T>>
make_unique(Args&&... args)
{
using up_type = typename ARENA::template unique_ptr<T>;
using deleter_type = typename ARENA::template deleter_type<T>;
auto *mem = detail::alloc<T, ARENA>(std::forward<Args>(args)...);
return up_type(mem, deleter_type());
}
template <typename T, std::size_t ALIGN>
constexpr const T *assume_aligned_ptr(const T *p) noexcept
template<typename T, typename ARENA, typename... Args>
static inline
std::enable_if_t<!ARENA::has_static_allocator, typename ARENA::template unique_ptr<T>>
make_unique(Args&&... args)
{
static_assert(ALIGN >= alignof(T), "Alignment must be greater or equal to alignof(T)");
static_assert(is_pow2(ALIGN), "Alignment must be a power of 2");
#if (PUSE_ALIGNED_HINTS)
return reinterpret_cast<const T *>(__builtin_assume_aligned(p, ALIGN));
#else
return p;
#endif
return make_unique<T>(ARENA::instance(), std::forward<Args>(args)...);
}
template<typename T, typename ARENA, typename... Args>
static inline
typename ARENA::template unique_ptr<T>
make_unique(ARENA &arena, Args&&... args)
{
using up_type = typename ARENA::template unique_ptr<T>;
using deleter_type = typename ARENA::template deleter_type<T>;
auto *mem = detail::alloc<T>(arena, std::forward<Args>(args)...);
return up_type(mem, deleter_type(&arena));
}
template<typename T, typename ARENA, typename... Args>
static inline
std::enable_if_t<ARENA::has_static_allocator, typename ARENA::template owned_ptr<T>>
make_owned(Args&&... args)
{
using op_type = typename ARENA::template owned_ptr<T>;
using deleter_type = typename ARENA::template deleter_type<T>;
auto *mem = detail::alloc<T, ARENA>(std::forward<Args>(args)...);
return op_type(mem, true, deleter_type());
}
template<typename T, typename ARENA, typename... Args>
static inline
std::enable_if_t<!ARENA::has_static_allocator, typename ARENA::template owned_ptr<T>>
make_owned(Args&&... args)
{
return make_owned<T>(ARENA::instance(), std::forward<Args>(args)...);
}
template<typename T, typename ARENA, typename... Args>
static inline typename ARENA::template owned_ptr<T> make_owned(ARENA &arena, Args&&... args)
{
using op_type = typename ARENA::template owned_ptr<T>;
using deleter_type = typename ARENA::template deleter_type<T>;
auto *mem = detail::alloc<T>(arena, std::forward<Args>(args)...);
return op_type(mem, true, deleter_type(&arena));
}
template <class T, std::size_t ALIGN = alignof(T)>
using aligned_allocator = aligned_arena::allocator_type<T, ALIGN>;
@ -557,57 +592,72 @@ namespace plib {
PDEFINE_HAS_MEMBER(has_align, align_size);
template <typename T, typename X = void>
struct align_traits
template <typename T, bool X>
struct align_traits_base
{
static_assert(!has_align<T>::value, "no align");
static constexpr const std::size_t align_size = alignof(std::max_align_t);
static constexpr const std::size_t value_size = sizeof(typename T::value_type);
static constexpr const std::size_t stride_size = lcm(align_size, value_size) / value_size;
};
template <typename T>
struct align_traits<T, std::enable_if_t<has_align<T>::value, void>>
struct align_traits_base<T, true>
{
static_assert(has_align<T>::value, "no align");
static constexpr const std::size_t align_size = T::align_size;
static constexpr const std::size_t value_size = sizeof(typename T::value_type);
static constexpr const std::size_t stride_size = lcm(align_size, value_size) / value_size;
};
template <typename T>
struct align_traits : public align_traits_base<T, has_align<T>::value>
{};
template <typename BASEARENA = aligned_arena, std::size_t PAGESIZE = 1024>
class paged_arena : public arena_base<paged_arena<BASEARENA, PAGESIZE>, true, true>
{
public:
paged_arena()
{
}
PCOPYASSIGNMOVE(paged_arena, delete)
~paged_arena() = default;
static void *allocate(size_t align, size_t size)
{
plib::unused_var(align);
//size = ((size + PAGESIZE - 1) / PAGESIZE) * PAGESIZE;
return arena().allocate(PAGESIZE, size);
}
static void deallocate(void *ptr, size_t size) noexcept
{
//size = ((size + PAGESIZE - 1) / PAGESIZE) * PAGESIZE;
arena().deallocate(ptr, size);
}
bool operator ==(const paged_arena &rhs) const noexcept { return this == &rhs; }
static BASEARENA &arena() noexcept { static BASEARENA m_arena; return m_arena; }
private:
};
//============================================================
// Aligned vector
//============================================================
// FIXME: needs a separate file
template <typename T, std::size_t ALIGN = PALIGN_VECTOROPT, typename A = aligned_allocator<T, ALIGN>>
class aligned_vector : public std::vector<T, A>
template <typename T, std::size_t ALIGN = PALIGN_VECTOROPT, typename A = paged_arena<>>//aligned_arena>
class aligned_vector : public std::vector<T, typename A::template allocator_type<T, ALIGN>>
{
public:
using base = std::vector<T, A>;
using reference = typename base::reference;
using const_reference = typename base::const_reference;
using pointer = typename base::pointer;
using const_pointer = typename base::const_pointer;
using size_type = typename base::size_type;
using base = std::vector<T, typename A::template allocator_type<T, ALIGN>>;
using base::base;
base & as_base() noexcept { return *this; }
const base & as_base() const noexcept { return *this; }
constexpr reference operator[](size_type i) noexcept
{
return assume_aligned_ptr<T, ALIGN>(&(base::operator[](0)))[i];
}
constexpr const_reference operator[](size_type i) const noexcept
{
return assume_aligned_ptr<T, ALIGN>(&(base::operator[](0)))[i];
}
pointer data() noexcept { return assume_aligned_ptr<T, ALIGN>(base::data()); }
const_pointer data() const noexcept { return assume_aligned_ptr<T, ALIGN>(base::data()); }
};
} // namespace plib

View File

@ -21,19 +21,20 @@
namespace plib {
template <typename FT, int SIZE>
template <typename FT, int SIZE, typename ARENA>
struct sizeabs
{
static constexpr std::size_t ABS() noexcept { return (SIZE < 0) ? static_cast<std::size_t>(0 - SIZE) : static_cast<std::size_t>(SIZE); }
static constexpr std::size_t ABS() noexcept { return (SIZE < 0) ? narrow_cast<std::size_t>(0 - SIZE) : narrow_cast<std::size_t>(SIZE); }
using container = typename std::array<FT, ABS()> ;
};
template <typename FT>
struct sizeabs<FT, 0>
template <typename FT, typename ARENA>
struct sizeabs<FT, 0, ARENA>
{
static constexpr std::size_t ABS() noexcept { return 0; }
using allocator_type = typename ARENA::template allocator_type<FT, PALIGN_VECTOROPT>;
//using container = typename std::vector<FT, arena_allocator<mempool, FT, 64>>;
using container = typename std::vector<FT, aligned_allocator<FT, PALIGN_VECTOROPT>>;
using container = typename std::vector<FT, allocator_type>;
};
/// \brief Array with preallocated or dynamic allocation.
@ -51,17 +52,20 @@ namespace plib {
/// I consider > 10% performance difference to be a use case.
///
template <typename FT, int SIZE>
template <typename FT, int SIZE, typename ARENA = aligned_arena>
struct parray
{
public:
static constexpr std::size_t SIZEABS() noexcept { return sizeabs<FT, SIZE>::ABS(); }
static constexpr std::size_t SIZEABS() noexcept { return sizeabs<FT, SIZE, ARENA>::ABS(); }
using base_type = typename sizeabs<FT, SIZE>::container;
using base_type = typename sizeabs<FT, SIZE, ARENA>::container;
using size_type = typename base_type::size_type;
using reference = typename base_type::reference;
using const_reference = typename base_type::const_reference;
using value_type = typename base_type::value_type;
using value_type = FT;
using reference = FT &;
using const_reference = const FT &;
using pointer = FT *;
using const_pointer = const FT *;
template <int X = SIZE >
parray(size_type size, std::enable_if_t<(X==0), int> = 0)
@ -70,7 +74,7 @@ namespace plib {
}
template <int X = SIZE >
parray(size_type size, FT val, std::enable_if_t<(X==0), int> = 0)
parray(size_type size, const FT &val, std::enable_if_t<(X==0), int> = 0)
: m_a(size, val), m_size(size)
{
}
@ -85,7 +89,7 @@ namespace plib {
}
template <int X = SIZE >
parray(size_type size, FT val, std::enable_if_t<(X != 0), int> = 0) noexcept(false)
parray(size_type size, const FT &val, std::enable_if_t<(X != 0), int> = 0) noexcept(false)
: m_size(size)
{
if ((SIZE < 0 && size > SIZEABS())
@ -131,20 +135,19 @@ namespace plib {
constexpr reference operator[](size_type i) noexcept
{
return assume_aligned_ptr<FT, PALIGN_VECTOROPT>(&m_a[0])[i];
return data()[i];
}
constexpr const_reference operator[](size_type i) const noexcept
{
return assume_aligned_ptr<FT, PALIGN_VECTOROPT>(&m_a[0])[i];
return data()[i];
}
FT * data() noexcept { return assume_aligned_ptr<FT, PALIGN_VECTOROPT>(m_a.data()); }
const FT * data() const noexcept { return assume_aligned_ptr<FT, PALIGN_VECTOROPT>(m_a.data()); }
pointer data() noexcept { return m_a.data(); }
const_pointer data() const noexcept { return m_a.data(); }
private:
PALIGNAS_VECTOROPT()
base_type m_a;
PALIGNAS_CACHELINE()
size_type m_size;
};

View File

@ -9,6 +9,7 @@
///
#include "pconfig.h"
#include "pgsl.h"
#include "ptypes.h"
#include <chrono>
@ -212,8 +213,8 @@ namespace plib {
ctype count() const noexcept { return m_count; }
template <typename S>
S as_seconds() const noexcept { return static_cast<S>(total())
/ static_cast<S>(T::per_second()); }
S as_seconds() const noexcept { return narrow_cast<S>(total())
/ narrow_cast<S>(T::per_second()); }
guard_t guard() noexcept { return guard_t(*this); }
private:
@ -244,7 +245,7 @@ namespace plib {
constexpr type total() const noexcept { return 0; }
constexpr ctype count() const noexcept { return 0; }
template <typename S>
S as_seconds() const noexcept { return static_cast<S>(0.0); }
S as_seconds() const noexcept { return narrow_cast<S>(0); }
constexpr static bool enabled = false;
guard_t guard() { return guard_t(); }
};

View File

@ -72,10 +72,11 @@
#define PALIGNAS_CACHELINE() PALIGNAS(PALIGN_CACHELINE)
#define PALIGNAS_VECTOROPT() PALIGNAS(PALIGN_VECTOROPT)
// FIXME: Breaks mame build on windows due to -Wattribute
// FIXME: Breaks mame build on windows mingw due to -Wattribute
// also triggers -Wattribute on ARM
// This is fixed on mingw version 10
// FIXME: no error on cross-compile - need further checks
#if defined(__GNUC__) && (defined(_WIN32) || defined(__arm__) || defined(__ARMEL__))
#if defined(__GNUC__) && ((defined(_WIN32) && __GNUC__ < 10) || defined(__arm__) || defined(__ARMEL__))
#define PALIGNAS(x)
#else
#define PALIGNAS(x) alignas(x)
@ -83,7 +84,7 @@
/// \brief nvcc build flag.
///
/// Set this to 1 if you are building with NVIDIA nvcc
/// Set this to 101 if you are building with NVIDIA nvcc 10.1
///
#ifndef NVCCBUILD
#define NVCCBUILD (0)
@ -166,5 +167,15 @@ typedef __float128 FLOAT128;
#endif
#endif
#if (PUSE_FLOAT128)
#if defined(__has_include)
#if !__has_include(<quadmath.h>)
//#pragma message "disabling PUSE_FLOAT128 due to missing quadmath.h"
#undef PUSE_FLOAT128
#define PUSE_FLOAT128 (0)
#endif
#endif
#endif
#endif // PCONFIG_H_

View File

@ -31,6 +31,7 @@ namespace plib {
template <typename T>
T getsym(const pstring &name) const noexcept
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
return reinterpret_cast<T>(getsym_p(name));
}

View File

@ -24,7 +24,7 @@ namespace plib
// Implementation in putil.cpp.
// Putting the code here leads to a performance decrease.
static int from_string_int(const pstring &str, const pstring &x);
static pstring nthstr(int n, const pstring &str);
static pstring nthstr(std::size_t n, const pstring &str);
};
} // namespace plib
@ -43,7 +43,7 @@ namespace plib
constexpr bool operator==(const ename &rhs) const noexcept {return m_v == rhs.m_v;} \
constexpr bool operator==(const E &rhs) const noexcept {return m_v == rhs;} \
pstring name() const { \
return nthstr(static_cast<int>(m_v), strings()); \
return nthstr(m_v, strings()); \
} \
private: E m_v; \
static pstring strings() {\

View File

@ -5,8 +5,8 @@
#include "pfmtlog.h"
#include <cfenv>
#include <iostream>
#include <cfloat>
#include <iostream>
#if (defined(__x86_64__) || defined(__i386__)) && defined(__linux__)
#define HAS_FEENABLE_EXCEPT (1)

View File

@ -92,7 +92,7 @@ pfmt::rtype pfmt::setfmt(std::stringstream &strm, char32_t cfmt_spec)
// a.b format here ...
char32_t pend(0);
int width(0);
if (fmt != "" && pstring("duxofge").find(static_cast<pstring::value_type>(cfmt_spec)) != pstring::npos)
if (!fmt.empty() && pstring("duxofge").find(static_cast<pstring::value_type>(cfmt_spec)) != pstring::npos)
{
pend = static_cast<char32_t>(fmt.at(fmt.size() - 1));
if (pstring("duxofge").find(static_cast<pstring::value_type>(pend)) == pstring::npos)
@ -113,7 +113,7 @@ pfmt::rtype pfmt::setfmt(std::stringstream &strm, char32_t cfmt_spec)
strm << std::setprecision(pstonum_ne_def<int>(fmt.substr(pdot + 1), 6));
width = pstonum_ne_def<int>(left(fmt,pdot), 0);
}
else if (fmt != "")
else if (!fmt.empty())
width = pstonum_ne_def<int>(fmt, 0);
auto aw(plib::abs(width));

View File

@ -55,7 +55,7 @@ namespace plib {
static char32_t fmt_spec() { return 'f'; }
static inline void streamify(std::ostream &s, const FLOAT128 &v)
{
s << static_cast<long double>(v);
s << narrow_cast<long double>(v);
}
};
#endif
@ -322,7 +322,7 @@ namespace plib {
if (build_enabled && enabled && m_enabled)
{
pfmt pf(fmt);
static_cast<T *>(this)->vdowrite(xlog(pf, std::forward<Args>(args)...));
dynamic_cast<T &>(*this).vdowrite(xlog(pf, std::forward<Args>(args)...));
}
}
@ -332,7 +332,7 @@ namespace plib {
if (build_enabled && m_enabled)
{
pfmt pf(fmt);
static_cast<const T *>(this)->vdowrite(xlog(pf, std::forward<Args>(args)...));
static_cast<const T &>(*this).vdowrite(xlog(pf, std::forward<Args>(args)...));
}
}

View File

@ -25,26 +25,26 @@ namespace plib {
{
static std::map<pstring, F> units_si_stat =
{
//{ "Y", static_cast<F>(1e24) }, // NOLINT: Yotta
//{ "Z", static_cast<F>(1e21) }, // NOLINT: Zetta
//{ "E", static_cast<F>(1e18) }, // NOLINT: Exa
{ "P", static_cast<F>(1e15) }, // NOLINT: Peta
{ "T", static_cast<F>(1e12) }, // NOLINT: Tera
{ "G", static_cast<F>( 1e9) }, // NOLINT: Giga
{ "M", static_cast<F>( 1e6) }, // NOLINT: Mega
{ "k", static_cast<F>( 1e3) }, // NOLINT: Kilo
{ "h", static_cast<F>( 1e2) }, // NOLINT: Hekto
//{ "da", static_cast<F>(1e1) }, // NOLINT: Deka
{ "d", static_cast<F>(1e-1) }, // NOLINT: Dezi
{ "c", static_cast<F>(1e-2) }, // NOLINT: Zenti
{ "m", static_cast<F>(1e-3) }, // NOLINT: Milli
{ "μ", static_cast<F>(1e-6) }, // NOLINT: Mikro
{ "n", static_cast<F>(1e-9) }, // NOLINT: Nano
{ "p", static_cast<F>(1e-12) }, // NOLINT: Piko
{ "f", static_cast<F>(1e-15) }, // NOLINT: Femto
{ "a", static_cast<F>(1e-18) }, // NOLINT: Atto
{ "z", static_cast<F>(1e-21) }, // NOLINT: Zepto
{ "y", static_cast<F>(1e-24) }, // NOLINT: Yokto
//{ "Y", narrow_cast<F>(1e24) }, // NOLINT: Yotta
//{ "Z", narrow_cast<F>(1e21) }, // NOLINT: Zetta
//{ "E", narrow_cast<F>(1e18) }, // NOLINT: Exa
{ "P", narrow_cast<F>(1e15) }, // NOLINT: Peta
{ "T", narrow_cast<F>(1e12) }, // NOLINT: Tera
{ "G", narrow_cast<F>( 1e9) }, // NOLINT: Giga
{ "M", narrow_cast<F>( 1e6) }, // NOLINT: Mega
{ "k", narrow_cast<F>( 1e3) }, // NOLINT: Kilo
{ "h", narrow_cast<F>( 1e2) }, // NOLINT: Hekto
//{ "da", narrow_cast<F>(1e1) }, // NOLINT: Deka
{ "d", narrow_cast<F>(1e-1) }, // NOLINT: Dezi
{ "c", narrow_cast<F>(1e-2) }, // NOLINT: Zenti
{ "m", narrow_cast<F>(1e-3) }, // NOLINT: Milli
{ "μ", narrow_cast<F>(1e-6) }, // NOLINT: Mikro
{ "n", narrow_cast<F>(1e-9) }, // NOLINT: Nano
{ "p", narrow_cast<F>(1e-12) }, // NOLINT: Piko
{ "f", narrow_cast<F>(1e-15) }, // NOLINT: Femto
{ "a", narrow_cast<F>(1e-18) }, // NOLINT: Atto
{ "z", narrow_cast<F>(1e-21) }, // NOLINT: Zepto
{ "y", narrow_cast<F>(1e-24) }, // NOLINT: Yokto
};
return units_si_stat;
}
@ -105,7 +105,7 @@ namespace plib {
if (inputs[i] == cmd)
{
rc.m_cmd = PUSH_INPUT;
rc.m_param = static_cast<NT>(i);
rc.m_param = narrow_cast<NT>(i);
stk += 1;
break;
}
@ -128,7 +128,7 @@ namespace plib {
}
if (stk < 1)
throw pexception(plib::pfmt("pfunction: stack underflow on token <{1}> in <{2}>")(cmd)(expr));
if (stk >= static_cast<int>(MAX_STACK))
if (stk >= narrow_cast<int>(MAX_STACK))
throw pexception(plib::pfmt("pfunction: stack overflow on token <{1}> in <{2}>")(cmd)(expr));
m_precompiled.push_back(rc);
}
@ -286,7 +286,7 @@ namespace plib {
lfsr >>= 1;
if (lsb)
lfsr ^= 0xB400U; // NOLINT: taps 15, 13, 12, 10
return static_cast<NT>(lfsr) / static_cast<NT>(0xffffU); // NOLINT
return narrow_cast<NT>(lfsr) / narrow_cast<NT>(0xffffU); // NOLINT
}
template <typename NT>
@ -297,7 +297,7 @@ namespace plib {
lfsr >>= 1;
if (lsb)
lfsr ^= 0xB400U; // NOLINT: taps 15, 13, 12, 10
return static_cast<NT>(lfsr);
return narrow_cast<NT>(lfsr);
}
#define ST1 stack[ptr]
@ -333,7 +333,7 @@ namespace plib {
stack[ptr++] = lfsr_random<value_type>(m_lfsr);
break;
case PUSH_INPUT:
stack[ptr++] = values[static_cast<unsigned>(rc.m_param)];
stack[ptr++] = values[narrow_cast<unsigned>(rc.m_param)];
break;
case PUSH_CONST:
stack[ptr++] = rc.m_param;

105
src/lib/netlist/plib/pgsl.h Normal file
View File

@ -0,0 +1,105 @@
// license:GPL-2.0+
// copyright-holders:Couriersud
#ifndef PGSL_H_
#define PGSL_H_
///
/// \file pgsl.h
///
/// This core guidelines gsl implementation currently provides only enough
/// functionality to syntactically support a very limited number of the
/// gsl specification.
///
/// Going forward this approach may be extended.
///
#include "pconfig.h"
#include "pexception.h"
#include "ptypes.h"
#include <exception>
#include <type_traits>
#include <utility>
#if defined(__has_builtin) // clang and gcc 10
#if __has_builtin(__builtin_unreachable)
#define gsl_Expects(e) ((e) ? static_cast<void>(0) : __builtin_unreachable())
#endif
#elif defined(__GNUC__) && !(defined( __CUDACC__ ) && defined( __CUDA_ARCH__ ))
#define gsl_Expects(e) ((e) ? static_cast<void>(0) : __builtin_unreachable())
#elif defined(_MSC_VER)
#define gsl_Expects(e) __assume(e)
#else
#define gsl_Expects(e) ((e) ? static_cast<void>(0) : static_cast<void>(0))
#endif
#undef gsl_Expects
#define gsl_Expects(e) do {} while (0)
#define gsl_Ensures(e) gsl_Expects(e)
namespace plib {
namespace pgsl {
struct narrowing_error : public std::exception {};
template <typename T>
using owner = T;
template <typename T>
using not_null = T;
/// \brief perform a narrowing cast without checks
///
template <typename T, typename O>
inline constexpr T narrow_cast(O && v) noexcept
{
static_assert(plib::is_arithmetic<T>::value && std::is_convertible<std::remove_reference_t<O>, T>::value, "narrow cast expects conversion between arithmetic types");
return static_cast<T>(std::forward<O>(v));
}
/// \brief perform a narrowing cast terminating if loss of precision
///
/// The c++ core guidelines require the narrow function to raise an error
/// This will make narrow noexcept(false). This has shown to have a
/// measurable impact on performance and thus we deviate we deviate from
/// the standard here.
///
template <typename T, typename O>
inline T narrow(O && v) noexcept
{
static_assert(plib::is_arithmetic<T>::value && std::is_convertible<std::remove_reference_t<O>, T>::value, "narrow cast expects conversion between arithmetic types");
const auto val = static_cast<T>(std::forward<O>(v));
if( v == static_cast<std::remove_reference_t<O>>(val))
{
return val;
}
plib::terminate("narrowing_error");
// throw narrowing_error();
}
} // namespace pgsl
/// \brief downcast from base tpye to derived type
///
/// The cpp core guidelines require a very careful use of static cast
/// for downcast operations. This template is used to identify these uses
/// and later for debug builds use dynamic_cast.
///
template <typename D, typename B>
inline constexpr D downcast(B && b) noexcept
{
static_assert(std::is_pointer<D>::value || std::is_reference<D>::value, "downcast only supports pointers or reference for derived");
static_assert(std::is_pointer<B>::value || std::is_reference<B>::value, "downcast only supports pointers or reference for base");
return static_cast<D>(std::forward<B>(b));
}
using pgsl::narrow_cast;
} // namespace plib
//FIXME: This is the place to use more complete implementations
namespace gsl = plib::pgsl;
#endif // PGSL_H_

View File

@ -62,11 +62,13 @@ namespace plib {
reference operator[](size_type index) noexcept
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
return reinterpret_cast<reference>(m_buf[index]);
}
constexpr const_reference operator[](size_type index) const noexcept
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
return reinterpret_cast<const_reference>(m_buf[index]);
}
@ -78,13 +80,19 @@ namespace plib {
new (&m_buf[index]) C(std::forward<Args>(args)...);
}
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
iterator begin() const noexcept { return reinterpret_cast<iterator>(&m_buf[0]); }
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
iterator end() const noexcept { return reinterpret_cast<iterator>(&m_buf[N]); }
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
iterator begin() noexcept { return reinterpret_cast<iterator>(&m_buf[0]); }
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
iterator end() noexcept { return reinterpret_cast<iterator>(&m_buf[N]); }
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
const_iterator cbegin() const noexcept { return reinterpret_cast<const_iterator>(&m_buf[0]); }
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
const_iterator cend() const noexcept { return reinterpret_cast<const_iterator>(&m_buf[N]); }
protected:

View File

@ -29,8 +29,8 @@ namespace plib {
int app::main_utfX(int argc, char *argv[])
{
std::vector<putf8string> arg;
for (std::size_t i = 0; i < static_cast<std::size_t>(argc); i++)
arg.push_back(putf8string(argv[i]));
for (std::size_t i = 0; i < narrow_cast<std::size_t>(argc); i++)
arg.emplace_back(putf8string(argv[i]));
return main_utfX(arg);
}
@ -38,8 +38,8 @@ namespace plib {
int app::main_utfX(int argc, wchar_t *argv[])
{
std::vector<putf8string> arg;
for (std::size_t i = 0; i < static_cast<std::size_t>(argc); i++)
arg.push_back(putf8string(pwstring(argv[i])));
for (std::size_t i = 0; i < narrow_cast<std::size_t>(argc); i++)
arg.emplace_back(putf8string(pwstring(argv[i])));
return main_utfX(arg);
}

View File

@ -15,9 +15,7 @@
#include <cmath>
#include <type_traits>
#if (PUSE_FLOAT128)
#include <quadmath.h>
#endif
// quadmath.h included by ptypes.h
namespace plib
{

95
src/lib/netlist/plib/pmatrix2d.h Normal file → Executable file
View File

@ -17,70 +17,102 @@
namespace plib
{
template<typename T, typename A = aligned_allocator<T>>
template<typename T, typename A = aligned_arena>
class pmatrix2d
{
public:
using size_type = std::size_t;
using value_type = T;
using allocator_type = A;
using arena_type = A;
using allocator_type = typename A::template allocator_type<T>;
static constexpr const size_type align_size = align_traits<allocator_type>::align_size;
static constexpr const size_type stride_size = align_traits<allocator_type>::stride_size;
using value_type = T;
using reference = T &;
using const_reference = const T &;
using pointer = T *;
using const_pointer = const T *;
static constexpr const size_type align_size = align_traits<A>::align_size;
static constexpr const size_type stride_size = align_traits<A>::stride_size;
pmatrix2d() noexcept
: m_N(0), m_M(0), m_stride(8), m_v()
: m_N(0), m_M(0), m_stride(8), m_v(nullptr)
{
}
pmatrix2d(size_type N, size_type M)
: m_N(N), m_M(M), m_v()
{
gsl_Expects(N>0);
gsl_Expects(M>0);
m_stride = ((M + stride_size-1) / stride_size) * stride_size;
m_v.resize(N * m_stride);
m_v = m_a.allocate(N * m_stride);
for (std::size_t i = 0; i < N * m_stride; i++)
::new(&m_v[i]) T();
}
~pmatrix2d()
{
if (m_v != nullptr)
{
for (std::size_t i = 0; i < m_N * m_stride; i++)
(&m_v[i])->~T();
m_a.deallocate(m_v, m_N * m_stride);
}
}
void resize(size_type N, size_type M)
{
gsl_Expects(N>0);
gsl_Expects(M>0);
if (m_v != nullptr)
{
for (std::size_t i = 0; i < N * m_stride; i++)
(&m_v[i])->~T();
m_a.deallocate(m_v, N * m_stride);
}
m_N = N;
m_M = M;
m_stride = ((M + stride_size-1) / stride_size) * stride_size;
m_v.resize(N * m_stride);
m_v = m_a.allocate(N * m_stride);
for (std::size_t i = 0; i < N * m_stride; i++)
::new(&m_v[i]) T();
}
constexpr T * operator[] (size_type row) noexcept
constexpr pointer operator[] (size_type row) noexcept
{
return assume_aligned_ptr<T, align_size>(&m_v[m_stride * row]);
return &m_v[m_stride * row];
}
constexpr const T * operator[] (size_type row) const noexcept
constexpr const_pointer operator[] (size_type row) const noexcept
{
return assume_aligned_ptr<T, align_size>(&m_v[m_stride * row]);
return &m_v[m_stride * row];
}
T & operator()(size_type r, size_type c) noexcept
reference operator()(size_type r, size_type c) noexcept
{
return (*this)[r][c];
}
const T & operator()(size_type r, size_type c) const noexcept
const_reference operator()(size_type r, size_type c) const noexcept
{
return (*this)[r][c];
}
// for compatibility with vrl variant
void set(size_type r, size_type c, const T &v) noexcept
void set(size_type r, size_type c, const value_type &v) noexcept
{
(*this)[r][c] = v;
}
T * data() noexcept
pointer data() noexcept
{
return m_v.data();
return m_v;
}
const T * data() const noexcept
const_pointer data() const noexcept
{
return m_v.data();
return m_v;
}
size_type didx(size_type r, size_type c) const noexcept
@ -93,20 +125,23 @@ namespace plib
size_type m_M;
size_type m_stride;
std::vector<T, A> m_v;
T * __restrict m_v;
allocator_type m_a;
};
// variable row length matrix
template<typename T, typename A = aligned_allocator<T>>
template<typename T, typename A = aligned_arena>
class pmatrix2d_vrl
{
public:
using size_type = std::size_t;
using value_type = T;
using allocator_type = A;
using arena_type = A;
using allocator_type = typename A::template allocator_type<T>;
static constexpr const size_type align_size = align_traits<A>::align_size;
static constexpr const size_type stride_size = align_traits<A>::stride_size;
static constexpr const size_type align_size = align_traits<allocator_type>::align_size;
static constexpr const size_type stride_size = align_traits<allocator_type>::stride_size;
pmatrix2d_vrl() noexcept
: m_N(0), m_M(0), m_v()
{
@ -139,24 +174,24 @@ namespace plib
return &(m_v[m_row[row]]);
}
#if 0
//FIXME: no check!
T & operator()(size_type r, size_type c) noexcept
{
return (*this)[r][c];
}
#else
void set(size_type r, size_type c, const T &v) noexcept
{
if (c + m_row[r] >= m_row[r + 1])
{
m_v.insert(m_v.begin() + m_row[r+1], v);
m_v.insert(m_v.begin() + narrow_cast<std::ptrdiff_t>(m_row[r+1]), v);
for (size_type i = r + 1; i <= m_N; i++)
m_row[i] = m_row[i] + 1;
}
else
(*this)[r][c] = v;
}
#endif
//FIXME: no check!
const T & operator()(size_type r, size_type c) const noexcept
{
@ -184,8 +219,8 @@ namespace plib
size_type m_N;
size_type m_M;
std::vector<size_type, A> m_row;
std::vector<T, A> m_v;
std::vector<size_type, typename A::template allocator_type<size_type>> m_row;
std::vector<T, allocator_type> m_v;
};

View File

@ -40,31 +40,26 @@ namespace plib {
mempool_arena(size_t min_alloc = (1<<21), size_t min_align = PALIGN_CACHELINE)
: m_min_alloc(min_alloc)
, m_min_align(min_align)
, m_block_align(1024)
, m_blocks(base_allocator_type<block *>(m_arena))
{
icount()++;
}
PCOPYASSIGNMOVE(mempool_arena, delete)
~mempool_arena()
{
for (auto & b : m_blocks)
{
if (b->m_num_alloc != 0)
{
plib::perrlogger("Found {} info blocks\n", sinfo().size());
plib::perrlogger("Found {} info blocks\n", m_info.size());
plib::perrlogger("Found block with {} dangling allocations\n", b->m_num_alloc);
}
m_arena.free(b);
//::operator delete(b->m_data);
}
if (icount()-- == 1)
{
if (!sinfo().empty())
plib::perrlogger("Still found {} info blocks after last mempool deleted\n", sinfo().size());
detail::free(m_arena, b);
}
if (!m_info.empty())
plib::perrlogger("Still found {} info blocks after mempool deleted\n", m_info.size());
}
void *allocate(size_t align, size_t size)
@ -92,21 +87,18 @@ namespace plib {
void *ret = reinterpret_cast<void *>(b->m_data + b->m_cur);
auto capacity(rs);
ret = std::align(align, size, ret, capacity);
sinfo().insert({ ret, info(b, b->m_cur)});
m_info.insert({ ret, info(b, b->m_cur)});
rs -= (capacity - size);
b->m_cur += rs;
base_type::m_stat_cur_alloc() += size;
if (base_type::m_stat_max_alloc() < base_type::m_stat_cur_alloc())
base_type::m_stat_max_alloc() = base_type::m_stat_cur_alloc();
this->inc_alloc_stat(size);
return ret;
}
/*static */ void deallocate(void *ptr, size_t size) noexcept
void deallocate(void *ptr, size_t size) noexcept
{
auto it = sinfo().find(ptr);
if (it == sinfo().end())
auto it = m_info.find(ptr);
if (it == m_info.end())
plib::terminate("mempool::free - pointer not found");
block *b = it->second.m_block;
if (b->m_num_alloc == 0)
@ -115,7 +107,7 @@ namespace plib {
{
mempool_arena &mp = b->m_mempool;
b->m_num_alloc--;
mp.m_stat_cur_alloc() -= size;
mp.dec_alloc_stat(size);
if (b->m_num_alloc == 0)
{
auto itb = std::find(mp.m_blocks.begin(), mp.m_blocks.end(), b);
@ -123,14 +115,15 @@ namespace plib {
plib::terminate("mempool::free - block not found");
mp.m_blocks.erase(itb);
m_arena.free(b);
detail::free(mp.base_arena(), b);
}
sinfo().erase(it);
m_info.erase(it);
}
}
bool operator ==(const mempool_arena &rhs) const noexcept { return this == &rhs; }
BASEARENA &base_arena() noexcept { return m_arena; }
private:
struct block
{
@ -142,17 +135,19 @@ namespace plib {
{
min_bytes = std::max(mp.m_min_alloc, min_bytes);
m_free = min_bytes;
size_type alloc_bytes = (min_bytes + mp.m_min_align); // - 1); // & ~(mp.m_min_align - 1);
m_bytes_allocated = (min_bytes + mp.m_block_align); // - 1); // & ~(mp.m_min_align - 1);
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
m_data_allocated = new std::uint8_t[alloc_bytes];
//m_data_allocated = new std::uint8_t[alloc_bytes];
m_data_allocated = static_cast<std::uint8_t *>(mp.base_arena().allocate(mp.m_block_align, m_bytes_allocated));
void *r = m_data_allocated;
std::align(mp.m_min_align, min_bytes, r, alloc_bytes);
std::align(mp.m_block_align, min_bytes, r, m_bytes_allocated);
m_data = reinterpret_cast<std::uint8_t *>(r);
}
~block()
{
//::operator delete(m_data_allocated);
delete [] m_data_allocated;
//delete [] m_data_allocated;
m_mempool.base_arena().deallocate(m_data_allocated, m_bytes_allocated);
}
block(const block &) = delete;
@ -163,6 +158,7 @@ namespace plib {
size_type m_num_alloc;
size_type m_free;
size_type m_cur;
size_type m_bytes_allocated;
std::uint8_t *m_data;
std::uint8_t *m_data_allocated;
mempool_arena &m_mempool;
@ -180,27 +176,20 @@ namespace plib {
block * new_block(size_type min_bytes)
{
auto *b = m_arena.template alloc<block>(*this, min_bytes);
auto *b = detail::alloc<block>(m_arena, *this, min_bytes);
m_blocks.push_back(b);
return b;
}
static std::unordered_map<void *, info> &sinfo()
{
static std::unordered_map<void *, info> spinfo;
return spinfo;
}
static std::size_t &icount()
{
static std::size_t count = 0;
return count;
}
size_t m_min_alloc;
size_t m_min_align;
size_t m_block_align;
BASEARENA m_arena;
using base_allocator_typex = typename BASEARENA::template allocator_type<std::pair<void * const, info>>;
std::unordered_map<void *, info, std::hash<void *>, std::equal_to<void *>,
base_allocator_typex> m_info;
// std::unordered_map<void *, info> m_info;
std::vector<block *, typename BASEARENA::template allocator_type<block *>> m_blocks;
};

View File

@ -68,7 +68,7 @@ namespace plib {
auto *o = dynamic_cast<option *>(opt);
if (o != nullptr)
{
if (o->short_opt() == "" && o->long_opt() == "")
if (o->short_opt().empty() && o->long_opt().empty())
{
auto *ov = dynamic_cast<option_args *>(o);
if (ov != nullptr)
@ -103,7 +103,7 @@ namespace plib {
if (!seen_other_args && plib::startsWith(arg, "--"))
{
auto v = psplit(arg.substr(2),"=");
if (!v.empty() && v[0] != "")
if (!v.empty() && !v[0].empty())
{
opt = getopt_long(v[0]);
has_equal_arg = (v.size() > 1);
@ -210,11 +210,11 @@ namespace plib {
if (auto * const opt = dynamic_cast<option *>(optbase))
{
pstring line = "";
if (opt->short_opt() != "")
if (!opt->short_opt().empty())
line += " -" + opt->short_opt();
if (opt->long_opt() != "")
if (!opt->long_opt().empty())
{
if (line != "")
if (!line.empty())
line += ", ";
else
line = " ";
@ -248,7 +248,8 @@ namespace plib {
else if (auto *grp = dynamic_cast<option_group *>(optbase))
{
ret += "\n" + grp->group() + ":\n";
if (grp->help() != "") ret += split_paragraphs(grp->help(), width, 4, 4) + "\n\n";
if (!grp->help().empty())
ret += split_paragraphs(grp->help(), width, 4, 4) + "\n\n";
}
}
// FIXME: other help ...
@ -274,7 +275,7 @@ namespace plib {
for (const auto & optbase : m_opts)
{
auto *opt = dynamic_cast<option *>(optbase);
if (opt != nullptr && arg != "" && opt->short_opt() == arg)
if (opt != nullptr && !arg.empty() && opt->short_opt() == arg)
return opt;
}
return nullptr;
@ -284,7 +285,7 @@ namespace plib {
for (const auto & optbase : m_opts)
{
auto *opt = dynamic_cast<option *>(optbase);
if (opt != nullptr && arg !="" && opt->long_opt() == arg)
if (opt != nullptr && !arg.empty() && opt->long_opt() == arg)
return opt;
}
return nullptr;

View File

@ -136,7 +136,7 @@ namespace plib {
if (raw != plib::container::npos)
{
m_val = static_cast<T>(raw);
m_val = narrow_cast<T>(raw);
return 0;
}

View File

@ -159,32 +159,43 @@ namespace plib {
if (PMFINTERNAL == 1)
{
// apply the "this" delta to the object first
// NOLINTNEXTLINE(clang-analyzer-core.UndefinedBinaryOperatorResult)
// NOLINTNEXTLINE(clang-analyzer-core.UndefinedBinaryOperatorResult,cppcoreguidelines-pro-type-reinterpret-cast)
generic_class *o_p_delta = reinterpret_cast<generic_class *>(reinterpret_cast<std::uint8_t *>(object) + m_this_delta);
// if the low bit of the vtable index is clear, then it is just a raw function pointer
if ((m_function & 1) == 0)
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
func = reinterpret_cast<generic_function>(m_function);
}
else
{
// otherwise, it is the byte index into the vtable where the actual function lives
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
std::uint8_t *vtable_base = *reinterpret_cast<std::uint8_t **>(o_p_delta);
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
func = *reinterpret_cast<generic_function *>(vtable_base + m_function - 1);
}
object = o_p_delta;
}
else if (PMFINTERNAL == 2)
{
if ((m_this_delta & 1) == 0) {
if ((m_this_delta & 1) == 0)
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
object = reinterpret_cast<generic_class *>(reinterpret_cast<std::uint8_t *>(object) + m_this_delta);
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
func = reinterpret_cast<generic_function>(m_function);
}
else
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
object = reinterpret_cast<generic_class *>(reinterpret_cast<std::uint8_t *>(object));
// otherwise, it is the byte index into the vtable where the actual function lives
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
std::uint8_t *vtable_base = *reinterpret_cast<std::uint8_t **>(object);
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
func = *reinterpret_cast<generic_function *>(vtable_base + m_function + m_this_delta - 1);
}
}
@ -192,8 +203,10 @@ namespace plib {
{
const int SINGLE_MEMFUNCPTR_SIZE = sizeof(void (generic_class::*)());
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
func = reinterpret_cast<generic_function>(m_function);
if (m_size == SINGLE_MEMFUNCPTR_SIZE + sizeof(int))
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
object = reinterpret_cast<generic_class *>(reinterpret_cast<std::uint8_t *>(object) + m_this_delta);
}
}
@ -231,8 +244,10 @@ namespace plib {
{
raw_type mfpo(mftp);
generic_function_storage rfunc(nullptr);
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
auto *robject = reinterpret_cast<generic_class *>(object);
mfpo.convert_to_generic(rfunc, robject);
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
return std::make_pair(reinterpret_cast<FunctionType>(rfunc), reinterpret_cast<ObjectType *>(robject));
}
template<typename O>
@ -259,6 +274,7 @@ namespace plib {
template<typename FunctionType, typename MemberFunctionType, typename ObjectType>
static std::pair<FunctionType, ObjectType *> get(MemberFunctionType mftp, ObjectType *object)
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
return std::make_pair(reinterpret_cast<FunctionType>(mftp), reinterpret_cast<ObjectType *>(object));
}
@ -286,6 +302,7 @@ namespace plib {
template<typename FunctionType, typename MemberFunctionType, typename ObjectType>
static std::pair<FunctionType, ObjectType *> get(MemberFunctionType mftp, ObjectType *object)
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
return std::make_pair(reinterpret_cast<FunctionType>(object->*mftp), reinterpret_cast<ObjectType *>(object));
}
template<typename O>
@ -315,6 +332,7 @@ namespace plib {
pmfp_base()
: m_obj(nullptr)
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
auto *s = reinterpret_cast<std::uint8_t *>(&m_resolved);
std::fill(s, s + sizeof(m_resolved), 0);
}
@ -323,6 +341,7 @@ namespace plib {
pmfp_base(specific_member_function<O> mftp, O *object)
: m_obj(nullptr)
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
auto *s = reinterpret_cast<std::uint8_t *>(&m_resolved);
std::fill(s, s + sizeof(m_resolved), 0);
bind(object, &mftp);
@ -351,6 +370,7 @@ namespace plib {
//auto pFunc = *reinterpret_cast<specific_member_function<O> *>(fraw); // mftp;
specific_member_function<O> pFunc;
static_assert(sizeof(pFunc) >= sizeof(MF), "size error");
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
*reinterpret_cast<MF *>(&pFunc) = *fraw;
auto r = helper::template get<member_abi_function<O>>(pFunc, object);
@ -360,18 +380,21 @@ namespace plib {
//*reinterpret_cast<member_abi_function<O> *>(&m_resolved) = r.first;
reinterpret_copy(r.first, m_resolved);
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
m_obj = reinterpret_cast<generic_class *>(r.second);
}
template<typename O>
R call(O *obj, Targs&&... args) const noexcept(true)
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
return helper::call(reinterpret_cast<member_abi_function<O> *>(&m_resolved),
obj, std::forward<Targs>(args)...);
}
R call(Targs&&... args) const noexcept(true)
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
return helper::call(reinterpret_cast<const member_abi_function<generic_class> *>(&m_resolved),
m_obj, std::forward<Targs>(args)...);
}
@ -414,12 +437,13 @@ namespace plib {
using static_creator = return_type (*)(const generic_member_function *, generic_class *);
late_pmfp() {}
late_pmfp() = default;
template<typename O>
late_pmfp(specific_member_function<O> mftp)
{
static_assert(sizeof(m_raw) >= sizeof(specific_member_function<O>), "size issue");
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
*reinterpret_cast<specific_member_function<O> *>(&m_raw) = mftp;
m_creator = creator<O>;
}
@ -427,6 +451,7 @@ namespace plib {
template<typename O>
return_type operator()(O *object) const
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
return m_creator(&m_raw, reinterpret_cast<generic_class *>(object));
}
@ -435,7 +460,9 @@ namespace plib {
template <typename O>
static return_type creator(const generic_member_function *raw, generic_class *obj)
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
auto p = reinterpret_cast<const specific_member_function<O> *>(raw);
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
auto o = reinterpret_cast<O *>(obj);
return return_type(*p, o);
}

View File

@ -461,7 +461,7 @@ namespace plib {
m_if_level++;
lt = replace_macros(lt);
simple_iter<ppreprocessor> t(this, tokenize(lt.substr(3), m_expr_sep, true, true));
auto val = static_cast<int>(prepro_expr(t, 255));
auto val = narrow_cast<int>(prepro_expr(t, 255));
t.skip_ws();
if (!t.eod())
error("found unprocessed content at end of line");
@ -489,7 +489,7 @@ namespace plib {
m_if_flag ^= (1 << m_if_level);
lt = replace_macros(lt);
simple_iter<ppreprocessor> t(this, tokenize(lt.substr(5), m_expr_sep, true, true));
auto val = static_cast<int>(prepro_expr(t, 255));
auto val = narrow_cast<int>(prepro_expr(t, 255));
t.skip_ws();
if (!t.eod())
error("found unprocessed content at end of line");
@ -559,7 +559,7 @@ namespace plib {
auto *prevdef = get_define(n);
if (lti.size() == 2)
{
if (prevdef != nullptr && prevdef->m_replace != "")
if (prevdef != nullptr && !prevdef->m_replace.empty())
error("redefinition of " + n);
m_defines.insert({n, define_t(n, "")});
}

View File

@ -95,14 +95,14 @@ namespace plib {
if (this->gptr() == this->egptr())
{
// clang reports sign error - weird
std::size_t bytes = m_strm->m_outbuf.size() - static_cast<std::size_t>(m_strm->m_pos);
std::size_t bytes = m_strm->m_outbuf.size() - narrow_cast<std::size_t>(m_strm->m_pos);
if (bytes > m_buf.size())
bytes = m_buf.size();
std::copy(m_strm->m_outbuf.c_str() + m_strm->m_pos, m_strm->m_outbuf.c_str() + m_strm->m_pos + bytes, m_buf.data());
this->setg(m_buf.data(), m_buf.data(), m_buf.data() + bytes);
m_strm->m_pos += static_cast<long>(bytes);
m_strm->m_pos += narrow_cast<long>(bytes);
}
return this->gptr() == this->egptr()

View File

@ -9,6 +9,7 @@
///
#include "pconfig.h"
#include "pgsl.h"
#include "pmath.h"
#include "ptypes.h"
@ -50,7 +51,7 @@ namespace plib
seed(5489);
}
static constexpr T min() noexcept { return static_cast<T>(0); }
static constexpr T min() noexcept { return T(0); }
static constexpr T max() noexcept { return ~T(0) >> (sizeof(T)*8 - w); }
template <typename ST>
@ -103,7 +104,7 @@ namespace plib
void twist()
{
const T lowest_w(~T(0) >> (sizeof(T)*8 - w));
const T lower_mask((static_cast<T>(1) << r) - 1); // That is, the binary number of r 1's
const T lower_mask((T(1) << r) - 1); // That is, the binary number of r 1's
const T upper_mask((~lower_mask) & lowest_w);
for (std::size_t i=0; i<N; i++)
@ -122,10 +123,10 @@ namespace plib
template <typename FT, typename T>
FT normalize_uniform(T &p, FT m = constants<FT>::one(), FT b = constants<FT>::zero())
{
const auto mmin(static_cast<FT>(p.min()));
const auto mmax(static_cast<FT>(p.max()));
const auto mmin(narrow_cast<FT>(p.min()));
const auto mmax(narrow_cast<FT>(p.max()));
// -> 0 to a
return (static_cast<FT>(p())- mmin) / (mmax - mmin) * m - b;
return (narrow_cast<FT>(p())- mmin) / (mmax - mmin) * m - b;
}
template<typename FT>

View File

@ -10,6 +10,7 @@
#include "pconfig.h"
#include "pexception.h"
#include "pgsl.h"
#include "pmath.h" // for pstonum
#include "pstring.h"
@ -36,9 +37,9 @@ namespace plib
if (ss >> x)
{
auto pos(ss.tellg());
if (pos == static_cast<decltype(pos)>(-1))
if (pos == decltype(pos)(-1))
pos = len;
*idx = static_cast<std::size_t>(pos);
*idx = narrow_cast<std::size_t>(pos);
}
else
*idx = constants<std::size_t>::zero();
@ -88,7 +89,7 @@ namespace plib
template <typename S>
FLOAT128 operator()(std::locale loc, const S &arg, std::size_t *idx)
{
return static_cast<FLOAT128>(pstonum_locale<long double>(loc, arg, idx));
return narrow_cast<FLOAT128>(pstonum_locale<long double>(loc, arg, idx));
}
};
#endif
@ -100,8 +101,8 @@ namespace plib
std::size_t idx(0);
auto ret = pstonum_helper<T>()(loc, cstr, &idx);
using ret_type = decltype(ret);
if (ret >= static_cast<ret_type>(plib::numeric_limits<T>::lowest())
&& ret <= static_cast<ret_type>(plib::numeric_limits<T>::max()))
if (ret >= narrow_cast<ret_type>(plib::numeric_limits<T>::lowest())
&& ret <= narrow_cast<ret_type>(plib::numeric_limits<T>::max()))
{
if (cstr[idx] != 0)
throw pexception(pstring("Continuation after numeric value ends: ") + pstring(cstr));
@ -110,7 +111,7 @@ namespace plib
{
throw pexception(pstring("Out of range: ") + pstring(cstr));
}
return static_cast<T>(ret);
return narrow_cast<T>(ret);
}
template<typename R, typename T>

View File

@ -18,10 +18,10 @@
#include <array>
#include <fstream>
#include <fstream>
#include <ios>
#include <iostream>
#include <sstream>
#include <fstream>
#include <type_traits>
#include <vector>
@ -204,7 +204,7 @@ public:
{
const auto sz(static_cast<std::streamsize>(val.size()));
write(sz);
m_strm.write(reinterpret_cast<const std::ostream::char_type *>(val.data()), sz * static_cast<std::streamsize>(sizeof(T)));
m_strm.write(reinterpret_cast<const std::ostream::char_type *>(val.data()), sz * gsl::narrow<std::streamsize>(sizeof(T)));
}
private:
@ -225,7 +225,7 @@ public:
template <typename T>
void read(T &val)
{
m_strm.read(reinterpret_cast<std::istream::char_type *>(&val), sizeof(T));
m_strm.read(reinterpret_cast<std::istream::char_type *>(&val), gsl::narrow<std::streamsize>(sizeof(T)));
}
void read( pstring &s)
@ -244,7 +244,7 @@ public:
std::size_t sz = 0;
read(sz);
val.resize(sz);
m_strm.read(reinterpret_cast<std::istream::char_type *>(val.data()), static_cast<std::streamsize>(sizeof(T) * sz));
m_strm.read(reinterpret_cast<std::istream::char_type *>(val.data()), gsl::narrow<std::streamsize>(sizeof(T) * sz));
}
private:

View File

@ -27,7 +27,7 @@ int pstring_t<F>::compare(const pstring_t &right) const noexcept
}
if (si != this->end() && ri != right.end())
return static_cast<int>(*si) - static_cast<int>(*ri);
return plib::narrow_cast<int>(*si) - plib::narrow_cast<int>(*ri);
if (this->mem_t_size() > right.mem_t_size())
return 1;
if (this->mem_t_size() < right.mem_t_size())
@ -45,8 +45,8 @@ pstring_t<F> pstring_t<F>::substr(size_type start, size_type nlen) const
{
if (nlen == npos || start + nlen > l)
nlen = l - start;
auto ps = std::next(begin(), static_cast<difference_type>(start));
auto pe = std::next(ps, static_cast<difference_type>(nlen));
auto ps = std::next(begin(), plib::narrow_cast<difference_type>(start));
auto pe = std::next(ps, plib::narrow_cast<difference_type>(nlen));
ret.m_str.assign(ps.p, pe.p);
}
return ret;

View File

@ -8,6 +8,7 @@
/// \file pstrutil.h
///
#include "pgsl.h"
#include "pstring.h"
#include "ptypes.h"
@ -157,13 +158,13 @@ namespace plib
template<typename T, typename TA>
bool startsWith(const T &str, const TA &arg)
{
return startsWith(str, static_cast<pstring>(arg));
return startsWith(str, static_cast<T>(arg));
}
template<typename T, typename TA>
bool endsWith(const T &str, const TA &arg)
{
return endsWith(str, static_cast<pstring>(arg));
return endsWith(str, static_cast<T>(arg));
}
template<typename T>
@ -172,7 +173,7 @@ namespace plib
const T *p = str;
while (*p != 0)
p++;
return static_cast<std::size_t>(p - str);
return narrow_cast<std::size_t>(p - str);
}
template<typename T>

View File

@ -210,7 +210,7 @@ namespace plib {
// save state support & mame disasm
const T *listptr() const noexcept { return &m_list[1]; }
std::size_t size() const noexcept { return static_cast<std::size_t>(m_end - &m_list[1]); }
std::size_t size() const noexcept { return narrow_cast<std::size_t>(m_end - &m_list[1]); }
const T & operator[](std::size_t index) const noexcept { return m_list[ 1 + index]; }
private:
using mutex_type = pspin_mutex<TS>;

View File

@ -15,8 +15,12 @@
#include <type_traits>
#if (PUSE_FLOAT128)
#if defined(__has_include)
#if __has_include(<quadmath.h>)
#include <quadmath.h>
#endif
#endif
#endif
// noexcept on move operator -> issue with macosx clang
#define PCOPYASSIGNMOVE(name, def) \
@ -273,7 +277,7 @@ namespace plib
template <typename T> class name \
{ \
template <typename U> static long test(decltype(&U:: member)); \
template <typename U> static char test(...); \
template <typename U> static char test(...); \
public: \
static constexpr const bool value = sizeof(test<T>(nullptr)) == sizeof(long); \
}

View File

@ -3,9 +3,9 @@
#include "putil.h"
#include "penum.h"
#include "pstream.h"
#include "pstrutil.h"
#include "ptypes.h"
#include "pstream.h"
#include <algorithm>
#include <cstdlib> // needed for getenv ...
@ -22,7 +22,7 @@ namespace plib
{
auto p=find_last_of(filename, pstring(PATH_SEPS));
pstring ret = (p == pstring::npos) ? filename : filename.substr(p+1);
if (suffix != "" && endsWith(ret, suffix))
if (!suffix.empty() && endsWith(ret, suffix))
return ret.substr(0, ret.length() - suffix.length());
return ret;
}
@ -49,7 +49,7 @@ namespace plib
pstring ret = "";
for( const auto &elem : list )
{
if (ret == "")
if (ret.empty())
ret = elem;
else
ret += (PATH_SEP + elem);
@ -126,7 +126,7 @@ namespace plib
auto i = str.begin();
while (i != str.end())
{
auto p = static_cast<std::size_t>(-1);
auto p = pstring::npos;
for (std::size_t j=0; j < onstrl.size(); j++)
{
if (std::equal(onstrl[j].begin(), onstrl[j].end(), i))
@ -135,14 +135,14 @@ namespace plib
break;
}
}
if (p != static_cast<std::size_t>(-1))
if (p != pstring::npos)
{
if (col != "")
if (!col.empty())
ret.push_back(col);
col = "";
ret.push_back(onstrl[p]);
i = std::next(i, static_cast<pstring::difference_type>(onstrl[p].length()));
i = std::next(i, narrow_cast<pstring::difference_type>(onstrl[p].length()));
}
else
{
@ -151,7 +151,7 @@ namespace plib
i++;
}
}
if (col != "")
if (!col.empty())
ret.push_back(col);
return ret;
@ -170,8 +170,8 @@ namespace plib
return -1;
}
pstring penum_base::nthstr(int n, const pstring &str)
pstring penum_base::nthstr(std::size_t n, const pstring &str)
{
return psplit(str, ",", false)[static_cast<std::size_t>(n)];
return psplit(str, ",", false)[n];
}
} // namespace plib

View File

@ -14,8 +14,8 @@
#include <algorithm>
#include <initializer_list>
#include <vector>
#include <sstream>
#include <vector>
#define PSTRINGIFY_HELP(y) # y
#define PSTRINGIFY(x) PSTRINGIFY_HELP(x)
@ -262,7 +262,9 @@ namespace plib
void reinterpret_copy(S &s, D &d)
{
static_assert(sizeof(D) >= sizeof(S), "size mismatch");
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
auto *dp = reinterpret_cast<std::uint8_t *>(&d);
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
const auto *sp = reinterpret_cast<std::uint8_t *>(&s);
std::copy(sp, sp + sizeof(S), dp);
}
@ -290,14 +292,14 @@ namespace plib
{
auto it = std::find(con.begin(), con.end(), elem);
if (it != con.end())
return static_cast<std::size_t>(it - con.begin());
return narrow_cast<std::size_t>(it - con.begin());
return npos;
}
template <class C>
void insert_at(C &con, const std::size_t index, const typename C::value_type &elem)
{
con.insert(con.begin() + static_cast<std::ptrdiff_t>(index), elem);
con.insert(con.begin() + narrow_cast<std::ptrdiff_t>(index), elem);
}
template <class C>
@ -336,7 +338,7 @@ namespace plib
{
std::size_t result = 5381; // NOLINT
for (const T* p = buf; p != buf + size; p++)
result = ((result << 5) + result ) ^ (result >> (32 - 5)) ^ static_cast<std::size_t>(*p); // NOLINT
result = ((result << 5) + result ) ^ (result >> (32 - 5)) ^ narrow_cast<std::size_t>(*p); // NOLINT
return result;
}

View File

@ -206,7 +206,7 @@ public:
return stream_ptr(nullptr);
strm->imbue(std::locale::classic());
return std::move(strm); // FIXME: for c++11 clang builds;
return strm;
}
private:
@ -225,14 +225,14 @@ public:
netlist::host_arena::unique_ptr<plib::dynlib_base> static_solver_lib() const override
{
if (m_boostlib == "builtin")
return netlist::host_arena::make_unique<plib::dynlib_static>(nl_static_solver_syms);
return plib::make_unique<plib::dynlib_static, netlist::host_arena>(nl_static_solver_syms);
if (m_boostlib == "generic")
return netlist::host_arena::make_unique<plib::dynlib_static>(nullptr);
return plib::make_unique<plib::dynlib_static, netlist::host_arena>(nullptr);
if (NL_DISABLE_DYNAMIC_LOAD)
throw netlist::nl_exception("Dynamic library loading not supported due to project security concerns.");
//pstring libpath = plib::util::environment("NL_BOOSTLIB", plib::util::buildpath({".", "nlboost.so"}));
return netlist::host_arena::make_unique<plib::dynlib>(m_boostlib);
return plib::make_unique<plib::dynlib, netlist::host_arena>(m_boostlib);
}
private:
@ -245,7 +245,7 @@ class netlist_tool_t : public netlist::netlist_state_t
public:
netlist_tool_t(tool_app_t &app, const pstring &name, const pstring &boostlib)
: netlist::netlist_state_t(name, netlist::host_arena::make_unique<netlist_tool_callbacks_t>(app, boostlib))
: netlist::netlist_state_t(name, plib::make_unique<netlist_tool_callbacks_t, netlist::host_arena>(app, boostlib))
{
}
@ -364,13 +364,13 @@ struct input_t
case netlist::param_t::POINTER:
throw netlist::nl_exception(plib::pfmt("param {1} is not numeric\n")(m_param.param().name()));
case netlist::param_t::DOUBLE:
static_cast<netlist::param_fp_t*>(&m_param.param())->set(m_value);
plib::downcast<netlist::param_fp_t &>(m_param.param()).set(m_value);
break;
case netlist::param_t::INTEGER:
static_cast<netlist::param_int_t*>(&m_param.param())->set(static_cast<int>(m_value));
plib::downcast<netlist::param_int_t &>(m_param.param()).set(static_cast<int>(m_value));
break;
case netlist::param_t::LOGIC:
static_cast<netlist::param_logic_t*>(&m_param.param())->set(static_cast<bool>(m_value));
plib::downcast<netlist::param_logic_t &>(m_param.param()).set(static_cast<bool>(m_value));
break;
}
}
@ -383,7 +383,7 @@ struct input_t
static std::vector<input_t> read_input(const netlist::setup_t &setup, const pstring &fname)
{
std::vector<input_t> ret;
if (fname != "")
if (!fname.empty())
{
plib::putf8_reader r = plib::putf8_reader(std::make_unique<plib::ifstream>(plib::filesystem::u8path(fname)));
if (r.stream().fail())
@ -392,7 +392,7 @@ static std::vector<input_t> read_input(const netlist::setup_t &setup, const pstr
pstring l;
while (r.readline(l))
{
if (l != "")
if (!l.empty())
{
input_t inp(setup, l);
ret.push_back(inp);
@ -724,7 +724,7 @@ static doc_ext read_docsrc(const pstring &fname, const pstring &id)
if (plib::startsWith(l, "//-"))
{
l = plib::trim(l.substr(3));
if (l != "")
if (!l.empty())
{
auto a(plib::psplit(l, ":", true));
if (a.empty() || (a.size() > 2))
@ -821,7 +821,7 @@ void tool_app_t::header_entry(const netlist::factory::element_t *e)
avs += ", " + s.substr(1);
mac_out("// usage : " + e->name() + "(name" + vs + ")", false);
if (avs != "")
if (!avs.empty())
mac_out("// auto connect: " + avs.substr(2), false);
mac_out("#define " + e->name() + "(...)");
@ -945,7 +945,7 @@ void tool_app_t::create_docheader()
{
auto d(read_docsrc(e->source().file_name(), e->name()));
if (d.id != "")
if (!d.id.empty())
{
pout("//! [{1} csynopsis]\n", e->name());
header_entry(e.get());
@ -967,7 +967,7 @@ void tool_app_t::create_docheader()
{
//auto d(read_docsrc(e->source().file_name(), e->name()));
if (d.id != "")
if (!d.id.empty())
{
poutprefix("///", "");
@ -1020,7 +1020,7 @@ void tool_app_t::create_docheader()
poutprefix("///", "");
poutprefix("///", " @section {}_4 Function Table", d.id);
poutprefix("///", "");
if (d.functiontable == "")
if (!d.functiontable.empty())
poutprefix("///", " Please refer to the datasheet.");
else
poutprefix("///", " {}", d.functiontable);

View File

@ -655,10 +655,10 @@ void nlwav_app::convert_wav(std::ostream &ostrm, wav_t::format fmt)
double dt = plib::reciprocal(static_cast<double>(opt_rate()));
auto nchan = m_instrms.size();
auto wo = arena::make_unique<wavwriter>(ostrm, opt_out() != "-", fmt, nchan, opt_rate(), opt_amp());
auto ago = arena::make_unique<aggregator>(nchan, dt, aggregator::callback_type(&wavwriter::process, wo.get()));
auto fgo_hp = arena::make_unique<filter_hp>(opt_highpass(), opt_hpboost(), nchan, filter_hp::callback_type(&aggregator::process, ago.get()));
auto fgo_lp = arena::make_unique<filter_lp>(opt_lowpass(), nchan, filter_lp::callback_type(&filter_hp::process, fgo_hp.get()));
auto wo = plib::make_unique<wavwriter, arena>(ostrm, opt_out() != "-", fmt, nchan, opt_rate(), opt_amp());
auto ago = plib::make_unique<aggregator, arena>(nchan, dt, aggregator::callback_type(&wavwriter::process, wo.get()));
auto fgo_hp = plib::make_unique<filter_hp, arena>(opt_highpass(), opt_hpboost(), nchan, filter_hp::callback_type(&aggregator::process, ago.get()));
auto fgo_lp = plib::make_unique<filter_lp, arena>(opt_lowpass(), nchan, filter_lp::callback_type(&filter_hp::process, fgo_hp.get()));
auto topcb = log_processor::callback_type(&filter_lp::process, fgo_lp.get());
@ -680,7 +680,7 @@ void nlwav_app::convert_wav(std::ostream &ostrm, wav_t::format fmt)
void nlwav_app::convert_vcd(std::ostream &ostrm, vcdwriter::format_e format)
{
arena::unique_ptr<vcdwriter> wo = arena::make_unique<vcdwriter>(ostrm, opt_args(),
arena::unique_ptr<vcdwriter> wo = plib::make_unique<vcdwriter, arena>(ostrm, opt_args(),
format, opt_high(), opt_low());
log_processor::callback_type agcb = log_processor::callback_type(&vcdwriter::process, wo.get());
@ -702,7 +702,7 @@ void nlwav_app::convert_vcd(std::ostream &ostrm, vcdwriter::format_e format)
void nlwav_app::convert_tab(std::ostream &ostrm)
{
auto wo = arena::make_unique<tabwriter>(ostrm, opt_args(),
auto wo = plib::make_unique<tabwriter, arena>(ostrm, opt_args(),
opt_start(), opt_inc(), opt_samples());
log_processor::callback_type agcb = log_processor::callback_type(&tabwriter::process, wo.get());

View File

@ -121,7 +121,7 @@ namespace solver
{
pstring nname(this->name() + "." + pstring(plib::pfmt("m{1}")(m_inps.size())));
nl_assert(p->net().is_analog());
auto net_proxy_output_u = state().make_pool_object<proxied_analog_output_t>(*this, nname, static_cast<analog_net_t *>(&p->net()));
auto net_proxy_output_u = state().make_pool_object<proxied_analog_output_t>(*this, nname, &dynamic_cast<analog_net_t &>(p->net()));
net_proxy_output = net_proxy_output_u.get();
m_inps.emplace_back(std::move(net_proxy_output_u));
}
@ -432,7 +432,7 @@ namespace solver
void matrix_solver_t::step(netlist_time delta) noexcept
{
const auto dd(delta.as_fp<nl_fptype>());
const auto dd(delta.as_fp<fptype>());
for (auto &d : m_step_funcs)
d(dd);
}
@ -489,7 +489,7 @@ namespace solver
if (m_params.m_dynamic_ts)
return compute_next_timestep(delta.as_fp<nl_fptype>(), m_params.m_max_timestep);
return compute_next_timestep(delta.as_fp<fptype>(), m_params.m_max_timestep);
return netlist_time::from_fp(m_params.m_max_timestep);
}
@ -534,7 +534,7 @@ namespace solver
return {colmax, colmin};
}
nl_fptype matrix_solver_t::get_weight_around_diag(std::size_t row, std::size_t diag)
matrix_solver_t::fptype matrix_solver_t::get_weight_around_diag(std::size_t row, std::size_t diag)
{
{
//
@ -543,7 +543,7 @@ namespace solver
std::vector<bool> touched(1024, false); // FIXME!
nl_fptype weight = nlconst::zero();
fptype weight = nlconst::zero();
auto &term = m_terms[row];
for (std::size_t i = 0; i < term.count(); i++)
{
@ -556,7 +556,7 @@ namespace solver
if (colu==row) colu = static_cast<unsigned>(diag);
else if (colu==diag) colu = static_cast<unsigned>(row);
weight = weight + plib::abs(static_cast<nl_fptype>(colu) - static_cast<nl_fptype>(diag));
weight = weight + plib::abs(static_cast<fptype>(colu) - static_cast<fptype>(diag));
touched[colu] = true;
}
}
@ -596,14 +596,14 @@ namespace solver
log().verbose(" has {1} dynamic elements", this->dynamic_device_count());
log().verbose(" has {1} timestep elements", this->timestep_device_count());
log().verbose(" {1:6.3} average newton raphson loops",
static_cast<nl_fptype>(this->m_stat_newton_raphson) / static_cast<nl_fptype>(this->m_stat_vsolver_calls));
static_cast<fptype>(this->m_stat_newton_raphson) / static_cast<fptype>(this->m_stat_vsolver_calls));
log().verbose(" {1:10} invocations ({2:6.0} Hz) {3:10} gs fails ({4:6.2} %) {5:6.3} average",
this->m_stat_calculations,
static_cast<nl_fptype>(this->m_stat_calculations) / this->exec().time().as_fp<nl_fptype>(),
static_cast<fptype>(this->m_stat_calculations) / this->exec().time().as_fp<fptype>(),
this->m_iterative_fail,
nlconst::hundred() * static_cast<nl_fptype>(this->m_iterative_fail)
/ static_cast<nl_fptype>(this->m_stat_calculations),
static_cast<nl_fptype>(this->m_iterative_total) / static_cast<nl_fptype>(this->m_stat_calculations));
nlconst::hundred() * static_cast<fptype>(this->m_iterative_fail)
/ static_cast<fptype>(this->m_stat_calculations),
static_cast<fptype>(this->m_iterative_total) / static_cast<fptype>(this->m_stat_calculations));
}
}

View File

@ -14,6 +14,7 @@
#include "netlist/plib/palloc.h"
#include "netlist/plib/penum.h"
#include "netlist/plib/pmatrix2d.h"
#include "netlist/plib/pmempool.h"
#include "netlist/plib/putil.h"
#include "netlist/plib/vector_ops.h"
@ -183,6 +184,8 @@ namespace solver
{
public:
using list_t = std::vector<matrix_solver_t *>;
using fptype = nl_fptype;
using arena_type = plib::mempool_arena<plib::aligned_arena>;
// after every call to solve, update inputs must be called.
// this can be done as well as a batch to ease parallel processing.
@ -259,58 +262,32 @@ namespace solver
}
// return number of floating point operations for solve
std::size_t ops() const { return m_ops; }
constexpr std::size_t ops() const { return m_ops; }
protected:
template <typename T>
using aligned_alloc = plib::aligned_allocator<T, PALIGN_VECTOROPT>;
matrix_solver_t(netlist_state_t &anetlist, const pstring &name,
const analog_net_t::list_t &nets,
const solver_parameters_t *params);
virtual void vsolve_non_dynamic() = 0;
virtual netlist_time compute_next_timestep(nl_fptype cur_ts, nl_fptype max_ts) = 0;
virtual bool check_err() = 0;
virtual netlist_time compute_next_timestep(fptype cur_ts, fptype max_ts) = 0;
virtual bool check_err() const = 0;
virtual void store() = 0;
#if 0
plib::pmatrix2d<nl_fptype, aligned_alloc<nl_fptype>> m_gonn;
plib::pmatrix2d<nl_fptype, aligned_alloc<nl_fptype>> m_gtn;
plib::pmatrix2d<nl_fptype, aligned_alloc<nl_fptype>> m_Idrn;
plib::pmatrix2d<nl_fptype *, aligned_alloc<nl_fptype *>> m_connected_net_Vn;
#else
plib::pmatrix2d_vrl<nl_fptype, aligned_alloc<nl_fptype>> m_gonn;
plib::pmatrix2d_vrl<nl_fptype, aligned_alloc<nl_fptype>> m_gtn;
plib::pmatrix2d_vrl<nl_fptype, aligned_alloc<nl_fptype>> m_Idrn;
plib::pmatrix2d_vrl<nl_fptype *, aligned_alloc<nl_fptype *>> m_connected_net_Vn;
#endif
plib::aligned_vector<terms_for_net_t> m_terms;
plib::pmatrix2d_vrl<fptype, arena_type> m_gonn;
plib::pmatrix2d_vrl<fptype, arena_type> m_gtn;
plib::pmatrix2d_vrl<fptype, arena_type> m_Idrn;
plib::pmatrix2d_vrl<fptype *, arena_type> m_connected_net_Vn;
const solver_parameters_t &m_params;
state_var<std::size_t> m_iterative_fail;
state_var<std::size_t> m_iterative_total;
plib::aligned_vector<terms_for_net_t> m_terms; // setup only
private:
plib::aligned_vector<terms_for_net_t> m_rails_temp;
std::vector<device_arena::unique_ptr<proxied_analog_output_t>> m_inps;
state_var<std::size_t> m_stat_calculations;
state_var<std::size_t> m_stat_newton_raphson;
state_var<std::size_t> m_stat_vsolver_calls;
state_var<netlist_time_ext> m_last_step;
plib::aligned_vector<nldelegate_ts> m_step_funcs;
plib::aligned_vector<nldelegate_dyn> m_dynamic_funcs;
logic_input_t m_fb_sync;
logic_output_t m_Q_sync;
std::size_t m_ops;
// base setup - called from constructor
void setup_base(setup_t &setup, const analog_net_t::list_t &nets) noexcept(false);
@ -321,7 +298,7 @@ namespace solver
int get_net_idx(const analog_net_t *net) const noexcept;
std::pair<int, int> get_left_right_of_diag(std::size_t irow, std::size_t idiag);
nl_fptype get_weight_around_diag(std::size_t row, std::size_t diag);
fptype get_weight_around_diag(std::size_t row, std::size_t diag);
void add_term(std::size_t net_idx, terminal_t *term) noexcept(false);
@ -332,272 +309,21 @@ namespace solver
analog_net_t *get_connected_net(terminal_t *term);
};
state_var<std::size_t> m_stat_calculations;
state_var<std::size_t> m_stat_newton_raphson;
state_var<std::size_t> m_stat_vsolver_calls;
template <typename FT, int SIZE>
class matrix_solver_ext_t: public matrix_solver_t
{
public:
state_var<netlist_time_ext> m_last_step;
plib::aligned_vector<nldelegate_ts> m_step_funcs;
plib::aligned_vector<nldelegate_dyn> m_dynamic_funcs;
plib::aligned_vector<device_arena::unique_ptr<proxied_analog_output_t>> m_inps;
using float_type = FT;
logic_input_t m_fb_sync;
logic_output_t m_Q_sync;
matrix_solver_ext_t(netlist_state_t &anetlist, const pstring &name,
const analog_net_t::list_t &nets,
const solver_parameters_t *params, const std::size_t size)
: matrix_solver_t(anetlist, name, nets, params)
, m_dim(size)
, m_new_V(size)
, m_RHS(size)
, m_mat_ptr(size, this->max_railstart() + 1)
, m_last_V(size, nlconst::zero())
, m_DD_n_m_1(size, nlconst::zero())
, m_h_n_m_1(size, nlconst::magic(1e-6)) // we need a non zero value here
{
//
// save states
//
state().save(*this, m_last_V.as_base(), this->name(), "m_last_V");
state().save(*this, m_DD_n_m_1.as_base(), this->name(), "m_DD_n_m_1");
state().save(*this, m_h_n_m_1.as_base(), this->name(), "m_h_n_m_1");
}
std::size_t m_ops;
private:
const std::size_t m_dim;
protected:
static constexpr const std::size_t SIZEABS = plib::parray<FT, SIZE>::SIZEABS();
static constexpr const std::size_t m_pitch_ABS = (((SIZEABS + 0) + 7) / 8) * 8;
PALIGNAS_VECTOROPT()
plib::parray<float_type, SIZE> m_new_V;
PALIGNAS_VECTOROPT()
plib::parray<float_type, SIZE> m_RHS;
PALIGNAS_VECTOROPT()
plib::pmatrix2d<float_type *> m_mat_ptr;
// FIXME: below should be private
// state - variable time_stepping
PALIGNAS_VECTOROPT()
plib::parray<nl_fptype, SIZE> m_last_V;
PALIGNAS_VECTOROPT()
plib::parray<nl_fptype, SIZE> m_DD_n_m_1;
PALIGNAS_VECTOROPT()
plib::parray<nl_fptype, SIZE> m_h_n_m_1;
std::size_t max_railstart() const noexcept
{
std::size_t max_rail = 0;
for (std::size_t k = 0; k < m_terms.size(); k++)
max_rail = std::max(max_rail, m_terms[k].railstart());
return max_rail;
}
template <typename T, typename M>
void log_fill(const T &fill, M &mat)
{
const std::size_t iN = fill.size();
// FIXME: Not yet working, mat_cr.h needs some more work
#if 0
auto mat_GE = dynamic_cast<plib::pGEmatrix_cr_t<typename M::base> *>(&mat);
#else
plib::unused_var(mat);
#endif
std::vector<unsigned> levL(iN, 0);
std::vector<unsigned> levU(iN, 0);
// parallel scheme for L x = y
for (std::size_t k = 0; k < iN; k++)
{
unsigned lm=0;
for (std::size_t j = 0; j<k; j++)
if (fill[k][j] < M::FILL_INFINITY)
lm = std::max(lm, levL[j]);
levL[k] = 1+lm;
}
// parallel scheme for U x = y
for (std::size_t k = iN; k-- > 0; )
{
unsigned lm=0;
for (std::size_t j = iN; --j > k; )
if (fill[k][j] < M::FILL_INFINITY)
lm = std::max(lm, levU[j]);
levU[k] = 1+lm;
}
for (std::size_t k = 0; k < iN; k++)
{
unsigned fm = 0;
pstring ml = "";
for (std::size_t j = 0; j < iN; j++)
{
ml += fill[k][j] == 0 ? 'X' : fill[k][j] < M::FILL_INFINITY ? '+' : '.';
if (fill[k][j] < M::FILL_INFINITY)
if (fill[k][j] > fm)
fm = fill[k][j];
}
#if 0
this->log().verbose("{1:4} {2} {3:4} {4:4} {5:4} {6:4}", k, ml,
levL[k], levU[k], mat_GE ? mat_GE->get_parallel_level(k) : 0, fm);
#else
this->log().verbose("{1:4} {2} {3:4} {4:4} {5:4} {6:4}", k, ml,
levL[k], levU[k], 0, fm);
#endif
}
}
constexpr std::size_t size() const noexcept
{
return (SIZE > 0) ? static_cast<std::size_t>(SIZE) : m_dim;
}
#if 1
void store() override
{
const std::size_t iN = size();
for (std::size_t i = 0; i < iN; i++)
this->m_terms[i].setV(static_cast<nl_fptype>(m_new_V[i]));
}
#else
// global tanh damping (4.197)
// partially cures the symptoms but not the cause
void store() override
{
const std::size_t iN = size();
for (std::size_t i = 0; i < iN; i++)
{
auto oldV = this->m_terms[i].template getV<nl_fptype>();
this->m_terms[i].setV(oldV + 0.02 * plib::tanh((m_new_V[i]-oldV)*50.0));
}
}
#endif
bool check_err() override
{
// NOTE: Ideally we should also include currents (RHS) here. This would
// need a reevaluation of the right hand side after voltages have been updated
// and thus belong into a different calculation. This applies to all solvers.
const std::size_t iN = size();
const auto reltol(static_cast<float_type>(m_params.m_reltol));
const auto vntol(static_cast<float_type>(m_params.m_vntol));
for (std::size_t i = 0; i < iN; i++)
{
const auto vold(static_cast<float_type>(this->m_terms[i].getV()));
const auto vnew(m_new_V[i]);
const auto tol(vntol + reltol * std::max(plib::abs(vnew),plib::abs(vold)));
if (plib::abs(vnew - vold) > tol)
return true;
}
return false;
}
netlist_time compute_next_timestep(nl_fptype cur_ts, nl_fptype max_ts) override
{
nl_fptype new_solver_timestep(max_ts);
for (std::size_t k = 0; k < size(); k++)
{
const auto &t = m_terms[k];
const auto v(static_cast<nl_fptype>(t.getV()));
// avoid floating point exceptions
const nl_fptype DD_n = std::max(-fp_constants<nl_fptype>::TIMESTEP_MAXDIFF(),
std::min(+fp_constants<nl_fptype>::TIMESTEP_MAXDIFF(),(v - m_last_V[k])));
m_last_V[k] = v;
const nl_fptype hn = cur_ts;
nl_fptype DD2 = (DD_n / hn - m_DD_n_m_1[k] / m_h_n_m_1[k]) / (hn + m_h_n_m_1[k]);
nl_fptype new_net_timestep(0);
m_h_n_m_1[k] = hn;
m_DD_n_m_1[k] = DD_n;
if (plib::abs(DD2) > fp_constants<nl_fptype>::TIMESTEP_MINDIV()) // avoid div-by-zero
new_net_timestep = plib::sqrt(m_params.m_dynamic_lte / plib::abs(nlconst::half()*DD2));
else
new_net_timestep = m_params.m_max_timestep;
new_solver_timestep = std::min(new_net_timestep, new_solver_timestep);
}
new_solver_timestep = std::max(new_solver_timestep, m_params.m_min_timestep);
// FIXME: Factor 2 below is important. Without, we get timing issues. This must be a bug elsewhere.
return std::max(netlist_time::from_fp(new_solver_timestep), netlist_time::quantum() * 2);
}
template <typename M>
void build_mat_ptr(M &mat)
{
const std::size_t iN = size();
for (std::size_t k=0; k<iN; k++)
{
std::size_t cnt(0);
// build pointers into the compressed row format matrix for each terminal
for (std::size_t j=0; j< this->m_terms[k].railstart();j++)
{
int other = this->m_terms[k].m_connected_net_idx[j];
if (other >= 0)
{
m_mat_ptr[k][j] = &(mat[k][static_cast<std::size_t>(other)]);
cnt++;
}
}
nl_assert_always(cnt == this->m_terms[k].railstart(), "Count and railstart mismatch");
m_mat_ptr[k][this->m_terms[k].railstart()] = &(mat[k][k]);
}
}
template <typename M>
void clear_square_mat(M &m)
{
const std::size_t n = size();
for (std::size_t k=0; k < n; k++)
{
auto *p = &(m[k][0]);
using mat_elem_type = typename std::decay<decltype(*p)>::type;
for (std::size_t i=0; i < n; i++)
p[i] = plib::constants<mat_elem_type>::zero();
}
}
void fill_matrix_and_rhs()
{
const std::size_t N = size();
for (std::size_t k = 0; k < N; k++)
{
auto &net = m_terms[k];
auto **tcr_r = &(m_mat_ptr[k][0]);
using source_type = typename decltype(m_gtn)::value_type;
const std::size_t term_count = net.count();
const std::size_t railstart = net.railstart();
const auto &go = m_gonn[k];
const auto &gt = m_gtn[k];
const auto &Idr = m_Idrn[k];
const auto &cnV = m_connected_net_Vn[k];
// FIXME: gonn, gtn and Idr - which float types should they have?
auto gtot_t = std::accumulate(gt, gt + term_count, plib::constants<source_type>::zero());
// update diagonal element ...
*tcr_r[railstart] = static_cast<FT>(gtot_t); //mat.A[mat.diag[k]] += gtot_t;
for (std::size_t i = 0; i < railstart; i++)
*tcr_r[i] += static_cast<FT>(go[i]);
auto RHS_t(std::accumulate(Idr, Idr + term_count, plib::constants<source_type>::zero()));
for (std::size_t i = railstart; i < term_count; i++)
RHS_t += (- go[i]) * *cnV[i];
m_RHS[k] = static_cast<FT>(RHS_t);
}
}
plib::aligned_vector<terms_for_net_t> m_rails_temp; // setup only
};

View File

@ -0,0 +1,288 @@
// license:GPL-2.0+
// copyright-holders:Couriersud
#ifndef NLD_MATRIX_SOLVER_EXT_H_
#define NLD_MATRIX_SOLVER_EXT_H_
///
/// \file nld_matrix_solver.h
///
#include "nld_matrix_solver.h"
#include <numeric>
namespace netlist
{
namespace solver
{
template <typename FT, int SIZE>
class matrix_solver_ext_t: public matrix_solver_t
{
public:
using float_type = FT;
matrix_solver_ext_t(netlist_state_t &anetlist, const pstring &name,
const analog_net_t::list_t &nets,
const solver_parameters_t *params, const std::size_t size)
: matrix_solver_t(anetlist, name, nets, params)
, m_new_V(size)
, m_RHS(size)
, m_mat_ptr(size, this->max_railstart() + 1)
, m_last_V(size, nlconst::zero())
, m_DD_n_m_1(size, nlconst::zero())
, m_h_n_m_1(size, nlconst::magic(1e-6)) // we need a non zero value here
, m_dim(size)
{
//
// save states
//
state().save(*this, m_last_V.as_base(), this->name(), "m_last_V");
state().save(*this, m_DD_n_m_1.as_base(), this->name(), "m_DD_n_m_1");
state().save(*this, m_h_n_m_1.as_base(), this->name(), "m_h_n_m_1");
}
protected:
static constexpr const std::size_t SIZEABS = plib::parray<FT, SIZE>::SIZEABS();
static constexpr const std::size_t m_pitch_ABS = (((SIZEABS + 0) + 7) / 8) * 8;
//PALIGNAS_VECTOROPT() parrays define alignment already
plib::parray<float_type, SIZE> m_new_V;
//PALIGNAS_VECTOROPT() parrays define alignment already
plib::parray<float_type, SIZE> m_RHS;
//PALIGNAS_VECTOROPT() parrays define alignment already
plib::pmatrix2d<float_type *> m_mat_ptr;
std::size_t max_railstart() const noexcept
{
std::size_t max_rail = 0;
for (std::size_t k = 0; k < m_terms.size(); k++)
max_rail = std::max(max_rail, m_terms[k].railstart());
return max_rail;
}
template <typename T, typename M>
void log_fill(const T &fill, M &mat)
{
const std::size_t iN = fill.size();
// FIXME: Not yet working, mat_cr.h needs some more work
#if 0
auto mat_GE = dynamic_cast<plib::pGEmatrix_cr_t<typename M::base> *>(&mat);
#else
plib::unused_var(mat);
#endif
std::vector<unsigned> levL(iN, 0);
std::vector<unsigned> levU(iN, 0);
// parallel scheme for L x = y
for (std::size_t k = 0; k < iN; k++)
{
unsigned lm=0;
for (std::size_t j = 0; j<k; j++)
if (fill[k][j] < M::FILL_INFINITY)
lm = std::max(lm, levL[j]);
levL[k] = 1+lm;
}
// parallel scheme for U x = y
for (std::size_t k = iN; k-- > 0; )
{
unsigned lm=0;
for (std::size_t j = iN; --j > k; )
if (fill[k][j] < M::FILL_INFINITY)
lm = std::max(lm, levU[j]);
levU[k] = 1+lm;
}
for (std::size_t k = 0; k < iN; k++)
{
unsigned fm = 0;
pstring ml = "";
for (std::size_t j = 0; j < iN; j++)
{
ml += fill[k][j] == 0 ? 'X' : fill[k][j] < M::FILL_INFINITY ? '+' : '.';
if (fill[k][j] < M::FILL_INFINITY)
if (fill[k][j] > fm)
fm = fill[k][j];
}
#if 0
this->log().verbose("{1:4} {2} {3:4} {4:4} {5:4} {6:4}", k, ml,
levL[k], levU[k], mat_GE ? mat_GE->get_parallel_level(k) : 0, fm);
#else
this->log().verbose("{1:4} {2} {3:4} {4:4} {5:4} {6:4}", k, ml,
levL[k], levU[k], 0, fm);
#endif
}
}
constexpr std::size_t size() const noexcept
{
return (SIZE > 0) ? static_cast<std::size_t>(SIZE) : m_dim;
}
#if 1
void store() override
{
const std::size_t iN = size();
for (std::size_t i = 0; i < iN; i++)
this->m_terms[i].setV(static_cast<fptype>(m_new_V[i]));
}
#else
// global tanh damping (4.197)
// partially cures the symptoms but not the cause
void store() override
{
const std::size_t iN = size();
for (std::size_t i = 0; i < iN; i++)
{
auto oldV = this->m_terms[i].template getV<fptype>();
this->m_terms[i].setV(oldV + 0.02 * plib::tanh((m_new_V[i]-oldV)*50.0));
}
}
#endif
bool check_err() const override
{
// NOTE: Ideally we should also include currents (RHS) here. This would
// need a reevaluation of the right hand side after voltages have been updated
// and thus belong into a different calculation. This applies to all solvers.
const std::size_t iN = size();
const auto reltol(static_cast<float_type>(m_params.m_reltol));
const auto vntol(static_cast<float_type>(m_params.m_vntol));
for (std::size_t i = 0; i < iN; i++)
{
const auto vold(static_cast<float_type>(this->m_terms[i].getV()));
const auto vnew(m_new_V[i]);
const auto tol(vntol + reltol * std::max(plib::abs(vnew),plib::abs(vold)));
if (plib::abs(vnew - vold) > tol)
return true;
}
return false;
}
netlist_time compute_next_timestep(fptype cur_ts, fptype max_ts) override
{
fptype new_solver_timestep(max_ts);
for (std::size_t k = 0; k < size(); k++)
{
const auto &t = m_terms[k];
const auto v(static_cast<fptype>(t.getV()));
// avoid floating point exceptions
const fptype DD_n = std::max(-fp_constants<fptype>::TIMESTEP_MAXDIFF(),
std::min(+fp_constants<fptype>::TIMESTEP_MAXDIFF(),(v - m_last_V[k])));
m_last_V[k] = v;
const fptype hn = cur_ts;
fptype DD2 = (DD_n / hn - m_DD_n_m_1[k] / m_h_n_m_1[k]) / (hn + m_h_n_m_1[k]);
fptype new_net_timestep(0);
m_h_n_m_1[k] = hn;
m_DD_n_m_1[k] = DD_n;
if (plib::abs(DD2) > fp_constants<fptype>::TIMESTEP_MINDIV()) // avoid div-by-zero
new_net_timestep = plib::sqrt(m_params.m_dynamic_lte / plib::abs(nlconst::half()*DD2));
else
new_net_timestep = m_params.m_max_timestep;
new_solver_timestep = std::min(new_net_timestep, new_solver_timestep);
}
new_solver_timestep = std::max(new_solver_timestep, m_params.m_min_timestep);
// FIXME: Factor 2 below is important. Without, we get timing issues. This must be a bug elsewhere.
return std::max(netlist_time::from_fp(new_solver_timestep), netlist_time::quantum() * 2);
}
template <typename M>
void build_mat_ptr(M &mat)
{
const std::size_t iN = size();
for (std::size_t k=0; k<iN; k++)
{
std::size_t cnt(0);
// build pointers into the compressed row format matrix for each terminal
for (std::size_t j=0; j< this->m_terms[k].railstart();j++)
{
int other = this->m_terms[k].m_connected_net_idx[j];
if (other >= 0)
{
m_mat_ptr[k][j] = &(mat[k][static_cast<std::size_t>(other)]);
cnt++;
}
}
nl_assert_always(cnt == this->m_terms[k].railstart(), "Count and railstart mismatch");
m_mat_ptr[k][this->m_terms[k].railstart()] = &(mat[k][k]);
}
}
template <typename M>
void clear_square_mat(M &m)
{
const std::size_t n = size();
for (std::size_t k=0; k < n; k++)
{
auto *p = &(m[k][0]);
using mat_elem_type = typename std::decay<decltype(*p)>::type;
for (std::size_t i=0; i < n; i++)
p[i] = plib::constants<mat_elem_type>::zero();
}
}
void fill_matrix_and_rhs()
{
const std::size_t N = size();
for (std::size_t k = 0; k < N; k++)
{
auto &net = m_terms[k];
auto **tcr_r = &(m_mat_ptr[k][0]);
using source_type = typename decltype(m_gtn)::value_type;
const std::size_t term_count = net.count();
const std::size_t railstart = net.railstart();
const auto &go = m_gonn[k];
const auto &gt = m_gtn[k];
const auto &Idr = m_Idrn[k];
const auto &cnV = m_connected_net_Vn[k];
// FIXME: gonn, gtn and Idr - which float types should they have?
auto gtot_t = std::accumulate(gt, gt + term_count, plib::constants<source_type>::zero());
// update diagonal element ...
*tcr_r[railstart] = static_cast<FT>(gtot_t); //mat.A[mat.diag[k]] += gtot_t;
for (std::size_t i = 0; i < railstart; i++)
*tcr_r[i] += static_cast<FT>(go[i]);
auto RHS_t(std::accumulate(Idr, Idr + term_count, plib::constants<source_type>::zero()));
for (std::size_t i = railstart; i < term_count; i++)
RHS_t += (- go[i]) * *cnV[i];
m_RHS[k] = static_cast<FT>(RHS_t);
}
}
private:
// state - variable time_stepping
//PALIGNAS_VECTOROPT() parrays define alignment already
plib::parray<fptype, SIZE> m_last_V;
// PALIGNAS_VECTOROPT() parrays define alignment already
plib::parray<fptype, SIZE> m_DD_n_m_1;
// PALIGNAS_VECTOROPT() parrays define alignment already
plib::parray<fptype, SIZE> m_h_n_m_1;
const std::size_t m_dim;
};
} // namespace solver
} // namespace netlist
#endif // NLD_MATRIX_SOLVER_EXT_H_

View File

@ -13,6 +13,8 @@
#include "plib/parray.h"
#include "plib/vector_ops.h"
#include "nld_matrix_solver_ext.h"
#include <algorithm>
namespace netlist
@ -49,7 +51,7 @@ namespace solver
template <typename T>
void LE_back_subst(T & x);
PALIGNAS_VECTOROPT()
// PALIGNAS_VECTOROPT() parrays define alignment already
plib::parray2D<FT, SIZE, m_pitch_ABS> m_A;
};

View File

@ -8,6 +8,7 @@
/// \file nld_ms_direct1.h
///
#include "nld_matrix_solver_ext.h"
#include "nld_ms_direct.h"
#include "nld_solver.h"

View File

@ -8,6 +8,7 @@
/// \file nld_ms_direct2.h
///
#include "nld_matrix_solver_ext.h"
#include "nld_ms_direct.h"
#include "nld_solver.h"

View File

@ -12,7 +12,8 @@
#include "plib/mat_cr.h"
#include "nld_ms_direct.h"
//#include "nld_ms_direct.h"
#include "nld_matrix_solver_ext.h"
#include "nld_solver.h"
#include "plib/pdynlib.h"
#include "plib/pstream.h"
@ -31,6 +32,8 @@ namespace solver
public:
using mat_type = plib::pGEmatrix_cr_t<plib::pmatrix_cr_t<FT, SIZE>>;
using base_type = matrix_solver_ext_t<FT, SIZE>;
using fptype = typename base_type::fptype;
matrix_solver_GCR_t(netlist_state_t &anetlist, const pstring &name,
const analog_net_t::list_t &nets,
@ -85,9 +88,9 @@ namespace solver
anetlist.log().verbose("maximum fill: {1}", gr.first);
anetlist.log().verbose("Post elimination occupancy ratio: {2} Ops: {1}", gr.second,
static_cast<nl_fptype>(mat.nz_num) / static_cast<nl_fptype>(iN * iN));
static_cast<fptype>(mat.nz_num) / static_cast<fptype>(iN * iN));
anetlist.log().verbose(" Pre elimination occupancy ratio: {2}",
static_cast<nl_fptype>(raw_elements) / static_cast<nl_fptype>(iN * iN));
static_cast<fptype>(raw_elements) / static_cast<fptype>(iN * iN));
// FIXME: Move me
//
@ -123,7 +126,7 @@ namespace solver
pstring static_compile_name();
mat_type mat;
plib::dynproc<void, FT *, nl_fptype *, nl_fptype *, nl_fptype *, nl_fptype ** > m_proc;
plib::dynproc<void, FT *, fptype *, fptype *, fptype *, fptype ** > m_proc;
};
@ -273,7 +276,7 @@ namespace solver
pstring matrix_solver_GCR_t<FT, SIZE>::static_compile_name()
{
pstring str_floattype(fp_constants<FT>::name());
pstring str_fptype(fp_constants<nl_fptype>::name());
pstring str_fptype(fp_constants<fptype>::name());
std::stringstream t;
t.imbue(std::locale::classic());
plib::putf8_fmt_writer w(&t);
@ -290,7 +293,7 @@ namespace solver
plib::putf8_fmt_writer strm(&t);
pstring name = static_compile_name();
pstring str_floattype(fp_constants<FT>::name());
pstring str_fptype(fp_constants<nl_fptype>::name());
pstring str_fptype(fp_constants<fptype>::name());
pstring extqual;
if (target == CXX_EXTERNAL_C)

View File

@ -8,6 +8,7 @@
/// \file nld_ms_gmres.h
///
#include "nld_matrix_solver_ext.h"
#include "nld_ms_direct.h"
#include "nld_solver.h"
#include "plib/gmres.h"

View File

@ -33,6 +33,7 @@
///
#include "nld_matrix_solver.h"
#include "nld_matrix_solver_ext.h"
#include "nld_solver.h"
#include "plib/vector_ops.h"

View File

@ -12,8 +12,8 @@
/// Fow w==1 we will do the classic Gauss-Seidel approach.
///
#include "nld_matrix_solver_ext.h"
#include "nld_ms_direct.h"
#include "nld_solver.h"
#include <algorithm>
@ -70,16 +70,19 @@ namespace solver
for (std::size_t k = 0; k < iN; k++)
{
nl_fptype gtot_t = nlconst::zero();
nl_fptype gabs_t = nlconst::zero();
nl_fptype RHS_t = nlconst::zero();
const std::size_t term_count = this->m_terms[k].count();
const nl_fptype * const gt = this->m_gtn[k];
const nl_fptype * const go = this->m_gonn[k];
const nl_fptype * const Idr = this->m_Idrn[k];
const auto * const gt = this->m_gtn[k];
const auto * const go = this->m_gonn[k];
const auto * const Idr = this->m_Idrn[k];
auto other_cur_analog = this->m_connected_net_Vn[k];
using fpaggtype = std::remove_reference_t<std::remove_cv_t<decltype(this->m_gtn[0][0])>>;
fpaggtype gtot_t = nlconst_base<fpaggtype>::zero();
fpaggtype gabs_t = nlconst_base<fpaggtype>::zero();
fpaggtype RHS_t = nlconst_base<fpaggtype>::zero();
this->m_new_V[k] = static_cast<float_type>(this->m_terms[k].getV());
for (std::size_t i = 0; i < term_count; i++)
@ -126,7 +129,7 @@ namespace solver
{
const int * net_other = this->m_terms[k].m_connected_net_idx.data();
const std::size_t railstart = this->m_terms[k].railstart();
const nl_fptype * go = this->m_gonn[k];
const auto * go = this->m_gonn[k];
float_type Idrive = plib::constants<float_type>::zero();
for (std::size_t i = 0; i < railstart; i++)

View File

@ -12,9 +12,8 @@
/// For w==1 we will do the classic Gauss-Seidel approach
///
#include "nld_matrix_solver.h"
#include "nld_matrix_solver_ext.h"
#include "nld_ms_direct.h"
#include "nld_solver.h"
#include <algorithm>

View File

@ -40,8 +40,7 @@
/// introduces numerical instability.
///
#include "nld_matrix_solver.h"
#include "nld_solver.h"
#include "nld_matrix_solver_ext.h"
#include "plib/vector_ops.h"
#include <algorithm>

View File

@ -87,7 +87,7 @@ namespace devices
analog_net_t::list_t &nets,
solver::solver_parameters_t &params, std::size_t size)
{
return host_arena::make_unique<C>(nl, name, nets, &params, size);
return plib::make_unique<C, host_arena>(nl, name, nets, &params, size);
}
template <typename FT, int SIZE>
@ -136,29 +136,21 @@ namespace devices
switch (net_count)
{
case 1:
return host_arena::make_unique<solver::matrix_solver_direct1_t<FT>>(state(), sname, nets, &m_params);
break;
return plib::make_unique<solver::matrix_solver_direct1_t<FT>, host_arena>(state(), sname, nets, &m_params);
case 2:
return host_arena::make_unique<solver::matrix_solver_direct2_t<FT>>(state(), sname, nets, &m_params);
break;
return plib::make_unique<solver::matrix_solver_direct2_t<FT>, host_arena>(state(), sname, nets, &m_params);
case 3:
return create_solver<FT, 3>(3, sname, nets);
break;
case 4:
return create_solver<FT, 4>(4, sname, nets);
break;
case 5:
return create_solver<FT, 5>(5, sname, nets);
break;
case 6:
return create_solver<FT, 6>(6, sname, nets);
break;
case 7:
return create_solver<FT, 7>(7, sname, nets);
break;
case 8:
return create_solver<FT, 8>(8, sname, nets);
break;
default:
log().info(MI_NO_SPECIFIC_SOLVER(net_count));
if (net_count <= 16)
@ -186,7 +178,6 @@ namespace devices
return create_solver<FT, -512>(net_count, sname, nets);
}
return create_solver<FT, 0>(net_count, sname, nets);
break;
}
}
@ -201,7 +192,7 @@ namespace devices
{
netlist.log().verbose(" ==> not a rail net");
// Must be an analog net
auto &n = *static_cast<analog_net_t *>(net.get());
auto &n = dynamic_cast<analog_net_t &>(*net);
if (!already_processed(n))
{
groupspre.emplace_back(analog_net_t::list_t());
@ -273,9 +264,9 @@ namespace devices
// only process analog terminals
if (term->is_type(detail::terminal_type::TERMINAL))
{
auto *pt = static_cast<terminal_t *>(term);
auto &pt = dynamic_cast<terminal_t &>(*term);
// check the connected terminal
analog_net_t &connected_net = netlist.setup().get_connected_terminal(*pt)->net();
analog_net_t &connected_net = netlist.setup().get_connected_terminal(pt)->net();
netlist.log().verbose(" Connected net {}", connected_net.name());
if (!check_if_processed_and_join(connected_net))
process_net(netlist, connected_net);
@ -306,17 +297,17 @@ namespace devices
switch (m_params.m_fp_type())
{
case solver::matrix_fp_type_e::FLOAT:
if (!NL_USE_FLOAT_MATRIX)
if (!config::use_float_matrix())
log().info("FPTYPE {1} not supported. Using DOUBLE", m_params.m_fp_type().name());
ms = create_solvers<std::conditional_t<NL_USE_FLOAT_MATRIX,float, double>>(sname, grp);
ms = create_solvers<std::conditional_t<config::use_float_matrix::value, float, double>>(sname, grp);
break;
case solver::matrix_fp_type_e::DOUBLE:
ms = create_solvers<double>(sname, grp);
break;
case solver::matrix_fp_type_e::LONGDOUBLE:
if (!NL_USE_LONG_DOUBLE_MATRIX)
if (!config::use_long_double_matrix())
log().info("FPTYPE {1} not supported. Using DOUBLE", m_params.m_fp_type().name());
ms = create_solvers<std::conditional_t<NL_USE_LONG_DOUBLE_MATRIX, long double, double>>(sname, grp);
ms = create_solvers<std::conditional_t<config::use_long_double_matrix::value, long double, double>>(sname, grp);
break;
case solver::matrix_fp_type_e::FLOATQ128:
#if (NL_USE_FLOAT128)
@ -355,7 +346,7 @@ namespace devices
for (auto & s : m_mat_solvers)
{
auto r = s->create_solver_code(target);
if (r.first != "") // ignore solvers not supporting static compile
if (!r.first.empty()) // ignore solvers not supporting static compile
mp.push_back(r);
}
return mp;

View File

@ -39,7 +39,7 @@ namespace devices
void post_start();
void stop();
nl_fptype gmin() const { return m_params.m_gmin(); }
auto gmin() const -> decltype(solver::solver_parameters_t::m_gmin()) { return m_params.m_gmin(); }
solver::static_compile_container create_solver_code(solver::static_compile_target target);

View File

@ -112,7 +112,7 @@ nl_convert_base_t::~nl_convert_base_t()
void nl_convert_base_t::add_pin_alias(const pstring &devname, const pstring &name, const pstring &alias)
{
pstring pname = devname + "." + name;
m_pins.emplace(pname, arena::make_unique<pin_alias_t>(pname, devname + "." + alias));
m_pins.emplace(pname, plib::make_unique<pin_alias_t, arena>(pname, devname + "." + alias));
}
void nl_convert_base_t::add_ext_alias(const pstring &alias)
@ -138,15 +138,15 @@ void nl_convert_base_t::add_device(arena::unique_ptr<dev_t> dev)
void nl_convert_base_t::add_device(const pstring &atype, const pstring &aname, const pstring &amodel)
{
add_device(arena::make_unique<dev_t>(atype, aname, amodel));
add_device(plib::make_unique<dev_t, arena>(atype, aname, amodel));
}
void nl_convert_base_t::add_device(const pstring &atype, const pstring &aname, double aval)
{
add_device(arena::make_unique<dev_t>(atype, aname, aval));
add_device(plib::make_unique<dev_t, arena>(atype, aname, aval));
}
void nl_convert_base_t::add_device(const pstring &atype, const pstring &aname)
{
add_device(arena::make_unique<dev_t>(atype, aname));
add_device(plib::make_unique<dev_t, arena>(atype, aname));
}
void nl_convert_base_t::add_term(const pstring &netname, const pstring &termname)
@ -161,7 +161,7 @@ void nl_convert_base_t::add_term(const pstring &netname, const pstring &termname
net = m_nets[netname].get();
else
{
auto nets = arena::make_unique<net_t>(netname);
auto nets = plib::make_unique<net_t, arena>(netname);
net = nets.get();
m_nets.emplace(netname, std::move(nets));
}
@ -245,6 +245,7 @@ void nl_convert_base_t::dump_nl()
}
std::vector<size_t> sorted;
sorted.reserve(m_devs.size());
for (size_t i=0; i < m_devs.size(); i++)
sorted.push_back(i);
std::sort(sorted.begin(), sorted.end(),
@ -436,7 +437,7 @@ static int npoly(const pstring &s)
void nl_convert_spice_t::process_line(const pstring &line)
{
if (line != "")
if (!line.empty())
{
//printf("// %s\n", line.c_str());
std::vector<pstring> tt(plib::psplit(line, " ", true));
@ -976,7 +977,7 @@ void nl_convert_rinf_t::convert(const pstring &contents)
pstring sim = attr["Simulation"];
pstring val = attr["Value"];
pstring com = attr["Comment"];
if (val == "")
if (val.empty())
val = com;
if (sim == "CAP")