mirror of
https://github.com/holub/mame
synced 2025-04-16 13:34:55 +03:00
Netlist: code maintenance and bug fixes. (nw)
- solver now uses dynamic allocation on systems larger than 512x512 - fixed osx build - moved nl_lists.h classes to plists.h - fixed netlist makefile clint section - readability and typos
This commit is contained in:
parent
da35541e84
commit
db318046c4
5
3rdparty/bgfx/src/renderer_gl.cpp
vendored
5
3rdparty/bgfx/src/renderer_gl.cpp
vendored
@ -5579,7 +5579,10 @@ BX_TRACE("%d, %d, %d, %s", _array, _srgb, _mipAutogen, getName(_format) );
|
||||
|
||||
version = 0 == bx::strCmp(code, "#version 430", 12) ? 430 : version;
|
||||
|
||||
bx::write(&writer, &err, "#version %d\n", version);
|
||||
if (version < 130)
|
||||
bx::write(&writer, &err, "#version %d\n", 130);
|
||||
else
|
||||
bx::write(&writer, &err, "#version %d\n", version);
|
||||
|
||||
if (430 > version && usesTextureLod)
|
||||
{
|
||||
|
4
3rdparty/bgfx/src/renderer_vk.cpp
vendored
4
3rdparty/bgfx/src/renderer_vk.cpp
vendored
@ -3935,8 +3935,8 @@ VK_IMPORT_DEVICE
|
||||
{
|
||||
attachments[mrt].colorAttachment = mrt;
|
||||
attachments[mrt].aspectMask = 0;
|
||||
attachments[mrt].aspectMask |= (_clear.m_flags & BGFX_CLEAR_DEPTH ) ? VK_IMAGE_ASPECT_DEPTH_BIT : 0;
|
||||
attachments[mrt].aspectMask |= (_clear.m_flags & BGFX_CLEAR_STENCIL) ? VK_IMAGE_ASPECT_STENCIL_BIT : 0;
|
||||
//attachments[mrt].aspectMask |= (_clear.m_flags & BGFX_CLEAR_DEPTH ) ? VK_IMAGE_ASPECT_DEPTH_BIT : 0;
|
||||
//attachments[mrt].aspectMask |= (_clear.m_flags & BGFX_CLEAR_STENCIL) ? VK_IMAGE_ASPECT_STENCIL_BIT : 0;
|
||||
|
||||
attachments[mrt].clearValue.depthStencil.stencil = _clear.m_stencil;
|
||||
attachments[mrt].clearValue.depthStencil.depth = _clear.m_depth;
|
||||
|
@ -43,7 +43,6 @@ project "netlist"
|
||||
MAME_DIR .. "src/lib/netlist/nl_dice_compat.h",
|
||||
MAME_DIR .. "src/lib/netlist/nl_factory.cpp",
|
||||
MAME_DIR .. "src/lib/netlist/nl_factory.h",
|
||||
MAME_DIR .. "src/lib/netlist/nl_lists.h",
|
||||
MAME_DIR .. "src/lib/netlist/nl_parser.cpp",
|
||||
MAME_DIR .. "src/lib/netlist/nl_parser.h",
|
||||
MAME_DIR .. "src/lib/netlist/nl_setup.cpp",
|
||||
|
@ -23,10 +23,9 @@ 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,
|
||||
TIDY_FLAGSX += -bugprone-macro-parentheses,-misc-macro-parentheses,
|
||||
TIDY_FLAGSX += -modernize-use-trailing-return-type
|
||||
TIDY_FLAGSX += -bugprone-too-small-loop-variable
|
||||
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 += -modernize-use-trailing-return-type
|
||||
|
||||
space :=
|
||||
space +=
|
||||
@ -60,7 +59,7 @@ LD = @g++
|
||||
MD = @mkdir
|
||||
RM = @rm
|
||||
DOXYGEN = @doxygen
|
||||
CLANG_TIDY = clang-tidy-10
|
||||
CLANG_TIDY = clang-tidy-9
|
||||
|
||||
TARGETS = nltool nlwav
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -16,15 +16,15 @@
|
||||
#include "plib/palloc.h" // owned_ptr
|
||||
#include "plib/pdynlib.h"
|
||||
#include "plib/pfmtlog.h"
|
||||
#include "plib/plists.h"
|
||||
#include "plib/pmempool.h"
|
||||
#include "plib/ppmf.h"
|
||||
#include "plib/pstate.h"
|
||||
#include "plib/pstream.h"
|
||||
#include "plib/ptime.h"
|
||||
|
||||
#include "nl_errstr.h"
|
||||
#include "nl_lists.h"
|
||||
#include "nltypes.h"
|
||||
#include "plib/ptime.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
@ -311,7 +311,6 @@ namespace netlist
|
||||
* state_var<unsigned> m_var;
|
||||
* }
|
||||
*/
|
||||
|
||||
template <typename T>
|
||||
struct state_var
|
||||
{
|
||||
@ -591,14 +590,14 @@ namespace netlist
|
||||
|
||||
nldelegate m_delegate;
|
||||
#if USE_COPY_INSTEAD_OF_REFERENCE
|
||||
void set_copied_input(netlist_sig_t val)
|
||||
void set_copied_input(netlist_sig_t val) noexcept
|
||||
{
|
||||
m_Q = val;
|
||||
}
|
||||
|
||||
state_var_sig m_Q;
|
||||
#else
|
||||
void set_copied_input(netlist_sig_t val) const { plib::unused_var(val); }
|
||||
void set_copied_input(netlist_sig_t val) const noexcept { plib::unused_var(val); }
|
||||
#endif
|
||||
|
||||
private:
|
||||
@ -669,13 +668,13 @@ namespace netlist
|
||||
|
||||
std::vector<core_terminal_t *> &core_terms() { return m_core_terms; }
|
||||
#if USE_COPY_INSTEAD_OF_REFERENCE
|
||||
void update_inputs()
|
||||
void update_inputs() noexcept
|
||||
{
|
||||
for (auto & term : m_core_terms)
|
||||
term->m_Q = m_cur_Q;
|
||||
}
|
||||
#else
|
||||
void update_inputs() const
|
||||
void update_inputs() const noexcept
|
||||
{
|
||||
/* nothing needs to be done */
|
||||
}
|
||||
@ -810,9 +809,9 @@ namespace netlist
|
||||
logic_t(core_device_t &dev, const pstring &aname,
|
||||
const state_e state, nldelegate delegate = nldelegate());
|
||||
|
||||
bool has_proxy() const { return (m_proxy != nullptr); }
|
||||
devices::nld_base_proxy *get_proxy() const { return m_proxy; }
|
||||
void set_proxy(devices::nld_base_proxy *proxy) { m_proxy = proxy; }
|
||||
bool has_proxy() const noexcept { return (m_proxy != nullptr); }
|
||||
devices::nld_base_proxy *get_proxy() const noexcept { return m_proxy; }
|
||||
void set_proxy(devices::nld_base_proxy *proxy) noexcept { m_proxy = proxy; }
|
||||
|
||||
logic_net_t & net() NL_NOEXCEPT;
|
||||
const logic_net_t & net() const NL_NOEXCEPT;
|
||||
@ -901,13 +900,13 @@ namespace netlist
|
||||
|
||||
analog_net_t(netlist_state_t &nl, const pstring &aname, detail::core_terminal_t *mr = nullptr);
|
||||
|
||||
nl_double Q_Analog() const NL_NOEXCEPT { return m_cur_Analog; }
|
||||
void set_Q_Analog(const nl_double v) NL_NOEXCEPT { m_cur_Analog = v; }
|
||||
nl_double Q_Analog() const noexcept { return m_cur_Analog; }
|
||||
void set_Q_Analog(const nl_double v) noexcept { m_cur_Analog = v; }
|
||||
nl_double *Q_Analog_state_ptr() NL_NOEXCEPT { return m_cur_Analog.ptr(); }
|
||||
|
||||
//FIXME: needed by current solver code
|
||||
devices::matrix_solver_t *solver() const NL_NOEXCEPT { return m_solver; }
|
||||
void set_solver(devices::matrix_solver_t *solver) NL_NOEXCEPT { m_solver = solver; }
|
||||
devices::matrix_solver_t *solver() const noexcept { return m_solver; }
|
||||
void set_solver(devices::matrix_solver_t *solver) noexcept { m_solver = solver; }
|
||||
|
||||
private:
|
||||
state_var<nl_double> m_cur_Analog;
|
||||
@ -1200,9 +1199,9 @@ namespace netlist
|
||||
struct stats_t
|
||||
{
|
||||
// NL_KEEP_STATISTICS
|
||||
nperftime_t<true> m_stat_total_time;
|
||||
nperfcount_t<true> m_stat_call_count;
|
||||
nperfcount_t<true> m_stat_inc_active;
|
||||
plib::pperftime_t<true> m_stat_total_time;
|
||||
plib::pperfcount_t<true> m_stat_call_count;
|
||||
plib::pperfcount_t<true> m_stat_inc_active;
|
||||
};
|
||||
|
||||
unique_pool_ptr<stats_t> m_stats;
|
||||
@ -1245,8 +1244,8 @@ namespace netlist
|
||||
|
||||
~device_t() noexcept override = default;
|
||||
|
||||
setup_t &setup();
|
||||
const setup_t &setup() const;
|
||||
setup_t &setup() noexcept;
|
||||
const setup_t &setup() const noexcept;
|
||||
|
||||
template<class C, typename... Args>
|
||||
void create_and_register_subdevice(const pstring &name, unique_pool_ptr<C> &dev, Args&&... args)
|
||||
@ -1283,6 +1282,16 @@ namespace netlist
|
||||
family_setter_t(core_device_t &dev, const logic_family_desc_t *desc);
|
||||
};
|
||||
|
||||
template <class T, bool TS>
|
||||
using timed_queue = plib::timed_queue_linear<T, TS>;
|
||||
|
||||
/* Use timed_queue_heap to use stdc++ heap functions instead of linear processing.
|
||||
* This slows down processing by about 25% on a Kaby Lake.
|
||||
*/
|
||||
|
||||
//template <class T, bool TS>
|
||||
//using timed_queue = timed_queue_heap<T, TS>;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// queue_t
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -1292,13 +1301,13 @@ namespace netlist
|
||||
*/
|
||||
class detail::queue_t :
|
||||
//public timed_queue<pqentry_t<net_t *, netlist_time>, false, NL_KEEP_STATISTICS>,
|
||||
public timed_queue<pqentry_t<net_t *, netlist_time>, false>,
|
||||
public timed_queue<plib::pqentry_t<net_t *, netlist_time>, false>,
|
||||
public detail::netlist_ref,
|
||||
public plib::state_manager_t::callback_t
|
||||
{
|
||||
public:
|
||||
using base_queue = timed_queue<pqentry_t<net_t *, netlist_time>, false>;
|
||||
using entry_t = pqentry_t<net_t *, netlist_time>;
|
||||
using base_queue = timed_queue<plib::pqentry_t<net_t *, netlist_time>, false>;
|
||||
using entry_t = plib::pqentry_t<net_t *, netlist_time>;
|
||||
explicit queue_t(netlist_state_t &nl);
|
||||
virtual ~queue_t() noexcept = default;
|
||||
|
||||
@ -1342,7 +1351,7 @@ namespace netlist
|
||||
friend class netlist_t; // allow access to private members
|
||||
|
||||
template<class C>
|
||||
static bool check_class(core_device_t *p)
|
||||
static bool check_class(core_device_t *p) noexcept
|
||||
{
|
||||
return dynamic_cast<C *>(p) != nullptr;
|
||||
}
|
||||
@ -1385,12 +1394,12 @@ namespace netlist
|
||||
|
||||
/* logging and name */
|
||||
|
||||
pstring name() const { return m_name; }
|
||||
pstring name() const noexcept { return m_name; }
|
||||
|
||||
log_type & log() { return m_log; }
|
||||
const log_type &log() const { return m_log; }
|
||||
log_type & log() noexcept { return m_log; }
|
||||
const log_type &log() const noexcept { return m_log; }
|
||||
|
||||
plib::dynlib &lib() { return *m_lib; }
|
||||
plib::dynlib &lib() const noexcept { return *m_lib; }
|
||||
|
||||
netlist_t &exec() { return m_netlist; }
|
||||
const netlist_t &exec() const { return m_netlist; }
|
||||
@ -1486,16 +1495,19 @@ namespace netlist
|
||||
}
|
||||
}
|
||||
|
||||
setup_t &setup() NL_NOEXCEPT { return *m_setup; }
|
||||
const setup_t &setup() const NL_NOEXCEPT { return *m_setup; }
|
||||
setup_t &setup() noexcept { return *m_setup; }
|
||||
const setup_t &setup() const noexcept { return *m_setup; }
|
||||
|
||||
// FIXME: make a postload member and include code there
|
||||
void rebuild_lists(); /* must be called after post_load ! */
|
||||
|
||||
static void compile_defines(std::vector<std::pair<pstring, pstring>> &defs);
|
||||
|
||||
nets_collection_type & nets() { return m_nets; }
|
||||
devices_collection_type & devices() { return m_devices; }
|
||||
nets_collection_type & nets() noexcept { return m_nets; }
|
||||
const nets_collection_type & nets() const noexcept { return m_nets; }
|
||||
|
||||
devices_collection_type & devices() noexcept { return m_devices; }
|
||||
const devices_collection_type & devices() const noexcept { return m_devices; }
|
||||
|
||||
/* sole use is to manage lifetime of family objects */
|
||||
std::unordered_map<pstring, plib::unique_ptr<logic_family_desc_t>> m_family_cache;
|
||||
@ -1549,12 +1561,13 @@ namespace netlist
|
||||
|
||||
const detail::queue_t &queue() const NL_NOEXCEPT { return m_queue; }
|
||||
|
||||
void qpush(detail::queue_t::entry_t && e) noexcept
|
||||
template <typename E>
|
||||
void qpush(E && e) noexcept
|
||||
{
|
||||
if (!USE_QUEUE_STATS || !m_use_stats)
|
||||
m_queue.push<false>(std::move(e)); // NOLINT(performance-move-const-arg)
|
||||
m_queue.push<false>(std::forward<E>(e)); // NOLINT(performance-move-const-arg)
|
||||
else
|
||||
m_queue.push<true>(std::move(e)); // NOLINT(performance-move-const-arg)
|
||||
m_queue.push<true>(std::forward<E>(e)); // NOLINT(performance-move-const-arg)
|
||||
}
|
||||
|
||||
template <class R>
|
||||
@ -1573,10 +1586,10 @@ namespace netlist
|
||||
|
||||
/* state handling */
|
||||
|
||||
plib::state_manager_t &run_state_manager() { return m_state->run_state_manager(); }
|
||||
plib::state_manager_t &run_state_manager() noexcept { return m_state->run_state_manager(); }
|
||||
|
||||
/* only used by nltool to create static c-code */
|
||||
devices::NETLIB_NAME(solver) *solver() const NL_NOEXCEPT { return m_solver; }
|
||||
devices::NETLIB_NAME(solver) *solver() const noexcept { return m_solver; }
|
||||
|
||||
/* force late type resolution */
|
||||
template <typename X = devices::NETLIB_NAME(solver)>
|
||||
@ -1586,21 +1599,21 @@ namespace netlist
|
||||
return static_cast<X *>(m_solver)->gmin();
|
||||
}
|
||||
|
||||
netlist_state_t &nlstate() NL_NOEXCEPT { return *m_state; }
|
||||
const netlist_state_t &nlstate() const { return *m_state; }
|
||||
netlist_state_t &nlstate() noexcept { return *m_state; }
|
||||
const netlist_state_t &nlstate() const noexcept { return *m_state; }
|
||||
|
||||
log_type & log() { return m_state->log(); }
|
||||
const log_type &log() const { return m_state->log(); }
|
||||
log_type & log() NL_NOEXCEPT { return m_state->log(); }
|
||||
const log_type &log() const NL_NOEXCEPT { return m_state->log(); }
|
||||
|
||||
void print_stats() const;
|
||||
void print_stats() const NL_NOEXCEPT;
|
||||
|
||||
bool stats_enabled() const { return m_use_stats; }
|
||||
void enable_stats(bool val) { m_use_stats = val; }
|
||||
bool stats_enabled() const noexcept { return m_use_stats; }
|
||||
void enable_stats(bool val) noexcept { m_use_stats = val; }
|
||||
|
||||
private:
|
||||
|
||||
template <bool KEEP_STATS>
|
||||
void process_queue_stats(netlist_time delta) NL_NOEXCEPT;
|
||||
template <bool KEEP_STATS, typename MCT>
|
||||
void process_queue_stats(netlist_time delta, MCT *mainclock) NL_NOEXCEPT;
|
||||
|
||||
plib::unique_ptr<netlist_state_t> m_state;
|
||||
devices::NETLIB_NAME(solver) * m_solver;
|
||||
@ -1615,8 +1628,8 @@ namespace netlist
|
||||
bool m_use_stats;
|
||||
|
||||
// performance
|
||||
nperftime_t<true> m_stat_mainloop;
|
||||
nperfcount_t<true> m_perf_out_processed;
|
||||
plib::pperftime_t<true> m_stat_mainloop;
|
||||
plib::pperfcount_t<true> m_perf_out_processed;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -1782,7 +1795,7 @@ namespace netlist
|
||||
if (m_next_scheduled_time > exec().time())
|
||||
{
|
||||
m_in_queue = queue_status::QUEUED; /* pending */
|
||||
exec().qpush({m_next_scheduled_time, this});
|
||||
exec().qpush(detail::queue_t::entry_t(m_next_scheduled_time, this));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1904,6 +1917,106 @@ namespace netlist
|
||||
for (std::size_t i=0; i<N; i++)
|
||||
(*this)[i] = value;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Hot section
|
||||
//
|
||||
// Any changes below will impact performance.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
template <bool KEEP_STATS, typename T>
|
||||
inline void detail::net_t::process(const T mask, netlist_sig_t sig)
|
||||
{
|
||||
m_cur_Q = sig;
|
||||
|
||||
if (KEEP_STATS)
|
||||
{
|
||||
for (auto & p : m_list_active)
|
||||
{
|
||||
p.set_copied_input(sig);
|
||||
auto *stats = p.device().m_stats.get();
|
||||
stats->m_stat_call_count.inc();
|
||||
if ((p.terminal_state() & mask))
|
||||
{
|
||||
auto g(stats->m_stat_total_time.guard());
|
||||
p.m_delegate();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto &p : m_list_active)
|
||||
{
|
||||
p.set_copied_input(sig);
|
||||
if ((p.terminal_state() & mask))
|
||||
p.m_delegate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <bool KEEP_STATS>
|
||||
inline void detail::net_t::update_devs() NL_NOEXCEPT
|
||||
{
|
||||
nl_assert(this->isRailNet());
|
||||
|
||||
m_in_queue = queue_status::DELIVERED; /* mark as taken ... */
|
||||
if (m_new_Q ^ m_cur_Q)
|
||||
process<KEEP_STATS>((m_new_Q << core_terminal_t::INP_LH_SHIFT)
|
||||
| (m_cur_Q << core_terminal_t::INP_HL_SHIFT), m_new_Q);
|
||||
}
|
||||
|
||||
template <bool KEEP_STATS, typename MCT>
|
||||
inline void netlist_t::process_queue_stats(const netlist_time delta, MCT *mainclock) NL_NOEXCEPT
|
||||
{
|
||||
netlist_time stop(m_time + delta);
|
||||
|
||||
qpush(detail::queue_t::entry_t(stop, nullptr));
|
||||
|
||||
if (m_mainclock == nullptr)
|
||||
{
|
||||
detail::queue_t::entry_t e(m_queue.pop());
|
||||
m_time = e.m_exec_time;
|
||||
while (e.m_object != nullptr)
|
||||
{
|
||||
e.m_object->template update_devs<KEEP_STATS>();
|
||||
if (KEEP_STATS)
|
||||
m_perf_out_processed.inc();
|
||||
e = m_queue.pop();
|
||||
m_time = e.m_exec_time;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logic_net_t &mc_net(mainclock->m_Q.net());
|
||||
const netlist_time inc(mainclock->m_inc);
|
||||
netlist_time mc_time(mc_net.next_scheduled_time());
|
||||
|
||||
do
|
||||
{
|
||||
while (m_queue.top().m_exec_time > mc_time)
|
||||
{
|
||||
m_time = mc_time;
|
||||
mc_net.toggle_new_Q();
|
||||
mc_net.update_devs<KEEP_STATS>();
|
||||
mc_time += inc;
|
||||
}
|
||||
|
||||
detail::queue_t::entry_t e(m_queue.pop());
|
||||
m_time = e.m_exec_time;
|
||||
if (e.m_object != nullptr)
|
||||
{
|
||||
e.m_object->template update_devs<KEEP_STATS>();
|
||||
if (KEEP_STATS)
|
||||
m_perf_out_processed.inc();
|
||||
}
|
||||
else
|
||||
break;
|
||||
} while (true); //while (e.m_object != nullptr);
|
||||
mc_net.set_next_scheduled_time(mc_time);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace netlist
|
||||
|
||||
namespace plib
|
||||
|
@ -14,7 +14,7 @@
|
||||
#define PERRMSG(name, str) \
|
||||
struct name \
|
||||
{ \
|
||||
operator pstring() const { return str; } \
|
||||
operator pstring() const noexcept { return str; } \
|
||||
};
|
||||
|
||||
#define PERRMSGV(name, narg, str) \
|
||||
@ -23,7 +23,7 @@
|
||||
template<typename... Args> name(Args&&... args) \
|
||||
: m_m(plib::pfmt(str)(std::forward<Args>(args)...)) \
|
||||
{ static_assert(narg == sizeof...(args), "Argument count mismatch"); } \
|
||||
operator pstring() const { return m_m; } \
|
||||
operator pstring() const noexcept { return m_m; } \
|
||||
pstring m_m; \
|
||||
};
|
||||
|
||||
|
@ -1,335 +0,0 @@
|
||||
// license:GPL-2.0+
|
||||
// copyright-holders:Couriersud
|
||||
/*
|
||||
* nllists.h
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NLLISTS_H_
|
||||
#define NLLISTS_H_
|
||||
|
||||
#include "plib/pchrono.h"
|
||||
#include "plib/plists.h"
|
||||
#include "plib/ptypes.h"
|
||||
#include "plib/parray.h"
|
||||
|
||||
#include "nl_config.h"
|
||||
#include "nltypes.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// timed queue
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
namespace netlist
|
||||
{
|
||||
//FIXME: move to an appropriate place
|
||||
template<bool enabled_ = true>
|
||||
class pspin_mutex
|
||||
{
|
||||
public:
|
||||
pspin_mutex() noexcept = default;
|
||||
void lock() noexcept{ while (m_lock.test_and_set(std::memory_order_acquire)) { } }
|
||||
void unlock() noexcept { m_lock.clear(std::memory_order_release); }
|
||||
private:
|
||||
PALIGNAS_CACHELINE()
|
||||
std::atomic_flag m_lock = ATOMIC_FLAG_INIT;
|
||||
};
|
||||
|
||||
template<>
|
||||
class pspin_mutex<false>
|
||||
{
|
||||
public:
|
||||
void lock() const noexcept { }
|
||||
void unlock() const noexcept { }
|
||||
};
|
||||
|
||||
template <class Element, class Time>
|
||||
struct pqentry_t final
|
||||
{
|
||||
constexpr pqentry_t() noexcept : m_exec_time(), m_object(nullptr) { }
|
||||
constexpr pqentry_t(const Time t, const Element o) noexcept : m_exec_time(t), m_object(o) { }
|
||||
#if 0
|
||||
~pqentry_t() = default;
|
||||
constexpr pqentry_t(const pqentry_t &e) noexcept = default;
|
||||
constexpr pqentry_t(pqentry_t &&e) noexcept = default;
|
||||
pqentry_t& operator=(pqentry_t && other) noexcept = default;
|
||||
pqentry_t& operator=(const pqentry_t &other) noexcept = default;
|
||||
|
||||
void swap(pqentry_t &other) noexcept
|
||||
{
|
||||
std::swap(m_exec_time, other.m_exec_time);
|
||||
std::swap(m_object, other.m_object);
|
||||
}
|
||||
#endif
|
||||
inline bool operator ==(const pqentry_t &rhs) const noexcept
|
||||
{
|
||||
return m_object == rhs.m_object;
|
||||
}
|
||||
|
||||
inline bool operator ==(const Element &rhs) const noexcept
|
||||
{
|
||||
return m_object == rhs;
|
||||
}
|
||||
|
||||
inline bool operator <=(const pqentry_t &rhs) const noexcept
|
||||
{
|
||||
return (m_exec_time <= rhs.m_exec_time);
|
||||
}
|
||||
|
||||
inline bool operator <(const pqentry_t &rhs) const noexcept
|
||||
{
|
||||
return (m_exec_time < rhs.m_exec_time);
|
||||
}
|
||||
|
||||
inline static constexpr pqentry_t never() noexcept { return pqentry_t(Time::never(), nullptr); }
|
||||
|
||||
Time m_exec_time;
|
||||
Element m_object;
|
||||
};
|
||||
|
||||
/* Use TS = true for a threadsafe queue */
|
||||
template <class T, bool TS>
|
||||
class timed_queue_linear : plib::nocopyassignmove
|
||||
{
|
||||
public:
|
||||
|
||||
explicit timed_queue_linear(const std::size_t list_size)
|
||||
: m_list(list_size)
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
std::size_t capacity() const noexcept { return m_list.capacity() - 1; }
|
||||
bool empty() const noexcept { return (m_end == &m_list[1]); }
|
||||
|
||||
template<bool KEEPSTAT>
|
||||
void push(T && e) noexcept
|
||||
{
|
||||
/* Lock */
|
||||
lock_guard_type lck(m_lock);
|
||||
T * i(m_end-1);
|
||||
for (; *i < e; --i)
|
||||
{
|
||||
*(i+1) = *(i);
|
||||
if (KEEPSTAT)
|
||||
m_prof_sortmove.inc();
|
||||
}
|
||||
*(i+1) = std::move(e);
|
||||
++m_end;
|
||||
if (KEEPSTAT)
|
||||
m_prof_call.inc();
|
||||
}
|
||||
|
||||
T pop() noexcept { return *(--m_end); }
|
||||
const T &top() const noexcept { return *(m_end-1); }
|
||||
|
||||
template <bool KEEPSTAT, class R>
|
||||
void remove(const R &elem) noexcept
|
||||
{
|
||||
/* Lock */
|
||||
lock_guard_type lck(m_lock);
|
||||
if (KEEPSTAT)
|
||||
m_prof_remove.inc();
|
||||
for (T * i = m_end - 1; i > &m_list[0]; --i)
|
||||
{
|
||||
// == operator ignores time!
|
||||
if (*i == elem)
|
||||
{
|
||||
std::copy(i+1, m_end--, i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <bool KEEPSTAT, class R>
|
||||
void retime(R && elem) noexcept
|
||||
{
|
||||
/* Lock */
|
||||
lock_guard_type lck(m_lock);
|
||||
if (KEEPSTAT)
|
||||
m_prof_retime.inc();
|
||||
|
||||
for (R * i = m_end - 1; i > &m_list[0]; --i)
|
||||
{
|
||||
if (*i == elem) // partial equal!
|
||||
{
|
||||
*i = std::move(elem);
|
||||
while (*(i-1) < *i)
|
||||
{
|
||||
std::swap(*(i-1), *i);
|
||||
--i;
|
||||
}
|
||||
while (i < m_end && *i < *(i+1))
|
||||
{
|
||||
std::swap(*(i+1), *i);
|
||||
++i;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void clear() noexcept
|
||||
{
|
||||
lock_guard_type lck(m_lock);
|
||||
m_end = &m_list[0];
|
||||
/* put an empty element with maximum time into the queue.
|
||||
* the insert algo above will run into this element and doesn't
|
||||
* need a comparison with queue start.
|
||||
*/
|
||||
m_list[0] = T::never();
|
||||
m_end++;
|
||||
}
|
||||
|
||||
// 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]); }
|
||||
const T & operator[](const std::size_t index) const noexcept { return m_list[ 1 + index]; }
|
||||
private:
|
||||
using mutex_type = pspin_mutex<TS>;
|
||||
using lock_guard_type = std::lock_guard<mutex_type>;
|
||||
|
||||
mutex_type m_lock;
|
||||
PALIGNAS_CACHELINE()
|
||||
T * m_end;
|
||||
plib::aligned_vector<T> m_list;
|
||||
|
||||
public:
|
||||
// profiling
|
||||
nperfcount_t<true> m_prof_sortmove;
|
||||
nperfcount_t<true> m_prof_call;
|
||||
nperfcount_t<true> m_prof_remove;
|
||||
nperfcount_t<true> m_prof_retime;
|
||||
};
|
||||
|
||||
template <class T, bool TS>
|
||||
class timed_queue_heap : plib::nocopyassignmove
|
||||
{
|
||||
public:
|
||||
|
||||
struct compare
|
||||
{
|
||||
constexpr bool operator()(const T &a, const T &b) const { return b <= a; }
|
||||
};
|
||||
|
||||
explicit timed_queue_heap(const std::size_t list_size)
|
||||
: m_list(list_size)
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
std::size_t capacity() const noexcept { return m_list.capacity(); }
|
||||
bool empty() const noexcept { return &m_list[0] == m_end; }
|
||||
|
||||
template <bool KEEPSTAT>
|
||||
void push(T &&e) noexcept
|
||||
{
|
||||
/* Lock */
|
||||
lock_guard_type lck(m_lock);
|
||||
*m_end++ = e;
|
||||
std::push_heap(&m_list[0], m_end, compare());
|
||||
if (KEEPSTAT)
|
||||
m_prof_call.inc();
|
||||
}
|
||||
|
||||
T pop() noexcept
|
||||
{
|
||||
T ret(m_list[0]);
|
||||
std::pop_heap(&m_list[0], m_end, compare());
|
||||
m_end--;
|
||||
return ret;
|
||||
}
|
||||
|
||||
const T &top() const noexcept { return m_list[0]; }
|
||||
|
||||
template <bool KEEPSTAT, class R>
|
||||
void remove(const R &elem) noexcept
|
||||
{
|
||||
/* Lock */
|
||||
lock_guard_type lck(m_lock);
|
||||
if (KEEPSTAT)
|
||||
m_prof_remove.inc();
|
||||
for (T * i = m_end - 1; i >= &m_list[0]; i--)
|
||||
{
|
||||
if (*i == elem)
|
||||
{
|
||||
m_end--;
|
||||
for (;i < m_end; i++)
|
||||
*i = std::move(*(i+1));
|
||||
std::make_heap(&m_list[0], m_end, compare());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <bool KEEPSTAT>
|
||||
void retime(const T &elem) noexcept
|
||||
{
|
||||
/* Lock */
|
||||
lock_guard_type lck(m_lock);
|
||||
if (KEEPSTAT)
|
||||
m_prof_retime.inc();
|
||||
for (T * i = m_end - 1; i >= &m_list[0]; i--)
|
||||
{
|
||||
if (*i == elem) // partial equal!
|
||||
{
|
||||
*i = elem;
|
||||
std::make_heap(&m_list[0], m_end, compare());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
lock_guard_type lck(m_lock);
|
||||
m_list.clear();
|
||||
m_end = &m_list[0];
|
||||
}
|
||||
|
||||
// save state support & mame disasm
|
||||
|
||||
constexpr const T *listptr() const { return &m_list[0]; }
|
||||
constexpr std::size_t size() const noexcept { return m_list.size(); }
|
||||
constexpr const T & operator[](const std::size_t index) const { return m_list[ 0 + index]; }
|
||||
private:
|
||||
using mutex_type = pspin_mutex<TS>;
|
||||
using lock_guard_type = std::lock_guard<mutex_type>;
|
||||
|
||||
mutex_type m_lock;
|
||||
std::vector<T> m_list;
|
||||
T *m_end;
|
||||
|
||||
public:
|
||||
// profiling
|
||||
nperfcount_t<true> m_prof_sortmove;
|
||||
nperfcount_t<true> m_prof_call;
|
||||
nperfcount_t<true> m_prof_remove;
|
||||
nperfcount_t<true> m_prof_retime;
|
||||
};
|
||||
|
||||
template <class T, bool TS>
|
||||
using timed_queue = timed_queue_linear<T, TS>;
|
||||
|
||||
/*
|
||||
* Use timed_queue_heap to use stdc++ heap functions instead of linear processing.
|
||||
*
|
||||
* This slows down processing by about 25% on a Kaby Lake.
|
||||
*/
|
||||
|
||||
//template <class T, bool TS>
|
||||
//using timed_queue = timed_queue_heap<T, TS>;
|
||||
|
||||
} // namespace netlist
|
||||
|
||||
#endif /* NLLISTS_H_ */
|
@ -68,17 +68,6 @@ namespace netlist
|
||||
|
||||
using log_type = plib::plog_base<callbacks_t, NL_DEBUG>;
|
||||
|
||||
|
||||
//============================================================
|
||||
// Performance tracking
|
||||
//============================================================
|
||||
|
||||
template<bool enabled_>
|
||||
using nperftime_t = plib::chrono::timer<plib::chrono::exact_ticks, enabled_>;
|
||||
|
||||
template<bool enabled_>
|
||||
using nperfcount_t = plib::chrono::counter<enabled_>;
|
||||
|
||||
//============================================================
|
||||
// Types needed by various includes
|
||||
//============================================================
|
||||
|
@ -34,8 +34,10 @@ namespace plib {
|
||||
{
|
||||
//using arena_storage_type = P *;
|
||||
using arena_storage_type = typename std::conditional<P::is_stateless, P, P *>::type;
|
||||
|
||||
template <typename X, typename Y = void>
|
||||
typename std::enable_if<!X::is_stateless, X&>::type getref(X *x) { return *x;}
|
||||
|
||||
template <typename X, typename Y = void *>
|
||||
typename std::enable_if<std::remove_pointer<X>::type::is_stateless, X&>::type
|
||||
getref(X &x, Y y = nullptr)
|
||||
@ -44,13 +46,18 @@ namespace plib {
|
||||
return x;
|
||||
}
|
||||
|
||||
constexpr arena_deleter(arena_storage_type a = arena_storage_type()) noexcept
|
||||
constexpr arena_deleter(arena_storage_type a = arena_storage_type())
|
||||
: m_a(a) { }
|
||||
|
||||
#if 1
|
||||
template<typename U, typename = typename
|
||||
std::enable_if<std::is_convertible< U*, T*>::value>::type>
|
||||
arena_deleter(const arena_deleter<P, U> &rhs) : m_a(rhs.m_a) { }
|
||||
#else
|
||||
template<typename PU, typename U, typename = typename
|
||||
std::enable_if<std::is_convertible< U*, T*>::value>::type>
|
||||
arena_deleter(const arena_deleter<PU, U> &rhs) noexcept : m_a(rhs.m_a) { }
|
||||
|
||||
arena_deleter(const arena_deleter<PU, U> &rhs) : m_a(rhs.m_a) { }
|
||||
#endif
|
||||
void operator()(T *p) //const
|
||||
{
|
||||
/* call destructor */
|
||||
@ -80,11 +87,11 @@ namespace plib {
|
||||
template <typename, typename>
|
||||
friend class owned_ptr;
|
||||
|
||||
owned_ptr(pointer p, bool owned) noexcept
|
||||
owned_ptr(pointer p, bool owned)
|
||||
: m_ptr(p), m_deleter(), m_is_owned(owned)
|
||||
{ }
|
||||
|
||||
owned_ptr(pointer p, bool owned, D deleter) noexcept
|
||||
owned_ptr(pointer p, bool owned, D deleter)
|
||||
: m_ptr(p), m_deleter(deleter), m_is_owned(owned)
|
||||
{ }
|
||||
|
||||
@ -93,7 +100,7 @@ namespace plib {
|
||||
owned_ptr & operator =(owned_ptr &r) = delete;
|
||||
|
||||
template<typename DC, typename DC_D>
|
||||
owned_ptr & operator =(owned_ptr<DC, DC_D> &&r)
|
||||
owned_ptr & operator =(owned_ptr<DC, DC_D> &&r) noexcept
|
||||
{
|
||||
if (m_is_owned && (m_ptr != nullptr))
|
||||
//delete m_ptr;
|
||||
@ -122,7 +129,7 @@ namespace plib {
|
||||
m_deleter(m_ptr);
|
||||
m_is_owned = r.m_is_owned;
|
||||
m_ptr = r.m_ptr;
|
||||
m_deleter = std::move(r.m_deleter);
|
||||
m_deleter = r.m_deleter;
|
||||
r.m_is_owned = false;
|
||||
r.m_ptr = nullptr;
|
||||
return *this;
|
||||
@ -197,18 +204,12 @@ namespace plib {
|
||||
|
||||
~arena_allocator() noexcept = default;
|
||||
|
||||
arena_allocator(const arena_allocator &rhs) noexcept = default;
|
||||
arena_allocator& operator=(const arena_allocator&) noexcept = delete;
|
||||
|
||||
arena_allocator(arena_allocator&&) noexcept = default;
|
||||
arena_allocator& operator=(arena_allocator&&) = delete;
|
||||
|
||||
arena_allocator(arena_type & a) noexcept : m_a(a)
|
||||
{
|
||||
}
|
||||
|
||||
template <class U>
|
||||
arena_allocator(const arena_allocator<ARENA, U, ALIGN>& rhs) noexcept
|
||||
arena_allocator(const arena_allocator<ARENA, U, ALIGN>& rhs)
|
||||
: m_a(rhs.m_a)
|
||||
{
|
||||
}
|
||||
@ -223,7 +224,7 @@ namespace plib {
|
||||
return reinterpret_cast<T *>(m_a.allocate(ALIGN, sizeof(T) * n));
|
||||
}
|
||||
|
||||
void deallocate(T* p, std::size_t n) noexcept
|
||||
void deallocate(T* p, std::size_t n)
|
||||
{
|
||||
unused_var(n);
|
||||
m_a.deallocate(p);
|
||||
|
@ -32,6 +32,7 @@ namespace plib {
|
||||
struct sizeabs<FT, 0>
|
||||
{
|
||||
static constexpr std::size_t ABS() { return 0; }
|
||||
//using container = typename std::vector<FT, arena_allocator<mempool, FT, 64>>;
|
||||
using container = typename std::vector<FT, aligned_allocator<FT, PALIGN_VECTOROPT>>;
|
||||
};
|
||||
|
||||
@ -75,6 +76,15 @@ namespace plib {
|
||||
{
|
||||
}
|
||||
|
||||
// osx clang doesn't like COPYASSIGNMOVE(parray, default)
|
||||
// it will generate some weird error messages about move assignment
|
||||
// constructor having a different noexcept status.
|
||||
|
||||
parray(const parray &rhs) : m_a(rhs.m_a), m_size(rhs.m_size) {}
|
||||
parray(parray &&rhs) noexcept : m_a(std::move(rhs.m_a)), m_size(std::move(rhs.m_size)) {}
|
||||
parray &operator=(const parray &rhs) { m_a = rhs.m_a; m_size = rhs.m_size; return *this; }
|
||||
parray &operator=(parray &&rhs) noexcept { std::swap(m_a,rhs.m_a); std::swap(m_size, rhs.m_size); return *this; }
|
||||
|
||||
template <int X = SIZE >
|
||||
parray(size_type size, typename std::enable_if<(X != 0), int>::type = 0)
|
||||
: m_size(size)
|
||||
@ -125,6 +135,8 @@ namespace plib {
|
||||
(*this)[i] = parray<FT, SIZE2>(size2);
|
||||
}
|
||||
}
|
||||
|
||||
COPYASSIGNMOVE(parray2D, default)
|
||||
};
|
||||
|
||||
} // namespace plib
|
||||
|
@ -15,245 +15,253 @@
|
||||
//#include <cstdint>
|
||||
|
||||
namespace plib {
|
||||
namespace chrono {
|
||||
template <typename T>
|
||||
struct sys_ticks
|
||||
{
|
||||
using type = typename T::rep;
|
||||
static inline type start() { return T::now().time_since_epoch().count(); }
|
||||
static inline type stop() { return T::now().time_since_epoch().count(); }
|
||||
static inline constexpr type per_second() { return T::period::den / T::period::num; }
|
||||
};
|
||||
|
||||
using hires_ticks = sys_ticks<std::chrono::high_resolution_clock>;
|
||||
using steady_ticks = sys_ticks<std::chrono::steady_clock>;
|
||||
using system_ticks = sys_ticks<std::chrono::system_clock>;
|
||||
|
||||
#if defined(__x86_64__) && !defined(_clang__) && !defined(_MSC_VER) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 6))
|
||||
|
||||
template <typename T, typename R>
|
||||
struct base_ticks
|
||||
{
|
||||
using ret_type = R;
|
||||
static ret_type per_second()
|
||||
namespace chrono {
|
||||
template <typename T>
|
||||
struct sys_ticks
|
||||
{
|
||||
static ret_type persec = 0;
|
||||
if (persec == 0)
|
||||
using type = typename T::rep;
|
||||
static inline constexpr type start() noexcept { return T::now().time_since_epoch().count(); }
|
||||
static inline constexpr type stop() noexcept { return T::now().time_since_epoch().count(); }
|
||||
static inline constexpr type per_second() noexcept { return T::period::den / T::period::num; }
|
||||
};
|
||||
|
||||
using hires_ticks = sys_ticks<std::chrono::high_resolution_clock>;
|
||||
using steady_ticks = sys_ticks<std::chrono::steady_clock>;
|
||||
using system_ticks = sys_ticks<std::chrono::system_clock>;
|
||||
|
||||
#if defined(__x86_64__) && !defined(_clang__) && !defined(_MSC_VER) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 6))
|
||||
|
||||
template <typename T, typename R>
|
||||
struct base_ticks
|
||||
{
|
||||
using ret_type = R;
|
||||
static ret_type per_second()
|
||||
{
|
||||
ret_type x = 0;
|
||||
system_ticks::type t = system_ticks::start();
|
||||
system_ticks::type e;
|
||||
x = - T :: start();
|
||||
do {
|
||||
e = system_ticks::stop();
|
||||
} while (e - t < system_ticks::per_second() / 100 );
|
||||
x += T :: stop();
|
||||
persec = (ret_type)(double)((double) x * (double) system_ticks::per_second() / double (e - t));
|
||||
static ret_type persec = 0;
|
||||
if (persec == 0)
|
||||
{
|
||||
ret_type x = 0;
|
||||
system_ticks::type t = system_ticks::start();
|
||||
system_ticks::type e;
|
||||
x = - T :: start();
|
||||
do {
|
||||
e = system_ticks::stop();
|
||||
} while (e - t < system_ticks::per_second() / 100 );
|
||||
x += T :: stop();
|
||||
persec = (ret_type)(double)((double) x * (double) system_ticks::per_second() / double (e - t));
|
||||
}
|
||||
return persec;
|
||||
}
|
||||
return persec;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
#if PHAS_RDTSCP
|
||||
struct fast_ticks : public base_ticks<fast_ticks, int64_t>
|
||||
{
|
||||
typedef int64_t type;
|
||||
static inline type start()
|
||||
#if PHAS_RDTSCP
|
||||
struct fast_ticks : public base_ticks<fast_ticks, int64_t>
|
||||
{
|
||||
int64_t v;
|
||||
__asm__ __volatile__ (
|
||||
"rdtscp;"
|
||||
"shl $32, %%rdx;"
|
||||
"or %%rdx, %%rax;"
|
||||
: "=a"(v) /* outputs */
|
||||
: /* inputs */
|
||||
: "%rcx", "%rdx" /* clobbers */
|
||||
);
|
||||
return v;
|
||||
}
|
||||
static inline type stop()
|
||||
typedef int64_t type;
|
||||
static inline type start() noexcept
|
||||
{
|
||||
int64_t v;
|
||||
__asm__ __volatile__ (
|
||||
"rdtscp;"
|
||||
"shl $32, %%rdx;"
|
||||
"or %%rdx, %%rax;"
|
||||
: "=a"(v) /* outputs */
|
||||
: /* inputs */
|
||||
: "%rcx", "%rdx" /* clobbers */
|
||||
);
|
||||
return v;
|
||||
}
|
||||
static inline type stop() noexcept
|
||||
{
|
||||
return start();
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
struct fast_ticks : public base_ticks<fast_ticks, int64_t>
|
||||
{
|
||||
return start();
|
||||
}
|
||||
};
|
||||
typedef int64_t type;
|
||||
static inline type start() noexcept
|
||||
{
|
||||
int64_t v;
|
||||
__asm__ __volatile__ (
|
||||
"rdtsc;"
|
||||
"shl $32, %%rdx;"
|
||||
"or %%rdx, %%rax;"
|
||||
: "=a"(v) /* outputs */
|
||||
: /* inputs */
|
||||
: "%rdx" /* clobbers */
|
||||
);
|
||||
return v;
|
||||
}
|
||||
static inline type stop() noexcept
|
||||
{
|
||||
return start();
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
struct fast_ticks : public base_ticks<fast_ticks, int64_t>
|
||||
{
|
||||
typedef int64_t type;
|
||||
static inline type start()
|
||||
#endif
|
||||
|
||||
|
||||
/* Based on "How to Benchmark Code Execution Times on Intel?? IA-32 and IA-64
|
||||
* Instruction Set Architectures", Intel, 2010
|
||||
*
|
||||
*/
|
||||
#if PUSE_ACCURATE_STATS && PHAS_RDTSCP
|
||||
/*
|
||||
* kills performance completely, but is accurate
|
||||
* cpuid serializes, but clobbers ebx and ecx
|
||||
*
|
||||
*/
|
||||
|
||||
struct exact_ticks : public base_ticks<exact_ticks, int64_t>
|
||||
{
|
||||
int64_t v;
|
||||
__asm__ __volatile__ (
|
||||
"rdtsc;"
|
||||
"shl $32, %%rdx;"
|
||||
"or %%rdx, %%rax;"
|
||||
: "=a"(v) /* outputs */
|
||||
: /* inputs */
|
||||
: "%rdx" /* clobbers */
|
||||
);
|
||||
return v;
|
||||
}
|
||||
static inline type stop()
|
||||
typedef int64_t type;
|
||||
|
||||
static inline type start() noexcept
|
||||
{
|
||||
int64_t v;
|
||||
__asm__ __volatile__ (
|
||||
"cpuid;"
|
||||
//"xor %%eax, %%eax\n\t"
|
||||
"rdtsc;"
|
||||
"shl $32, %%rdx;"
|
||||
"or %%rdx, %%rax;"
|
||||
: "=a"(v) /* outputs */
|
||||
: "a"(0x0) /* inputs */
|
||||
: "%ebx", "%ecx", "%rdx" /* clobbers*/
|
||||
);
|
||||
return v;
|
||||
}
|
||||
static inline type stop() noexcept
|
||||
{
|
||||
int64_t v;
|
||||
__asm__ __volatile__ (
|
||||
"rdtscp;"
|
||||
"shl $32, %%rdx;"
|
||||
"or %%rax, %%rdx;"
|
||||
"mov %%rdx, %%r10;"
|
||||
"xor %%eax, %%eax\n\t"
|
||||
"cpuid;"
|
||||
"mov %%r10, %%rax;"
|
||||
: "=a" (v)
|
||||
:
|
||||
: "%ebx", "%ecx", "%rdx", "%r10"
|
||||
);
|
||||
return v;
|
||||
}
|
||||
};
|
||||
#else
|
||||
using exact_ticks = fast_ticks;
|
||||
#endif
|
||||
|
||||
|
||||
#else
|
||||
using fast_ticks = hires_ticks;
|
||||
using exact_ticks = fast_ticks;
|
||||
#endif
|
||||
|
||||
template<bool enabled_>
|
||||
struct counter
|
||||
{
|
||||
return start();
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* Based on "How to Benchmark Code Execution Times on Intel?? IA-32 and IA-64
|
||||
* Instruction Set Architectures", Intel, 2010
|
||||
*
|
||||
*/
|
||||
#if PUSE_ACCURATE_STATS && PHAS_RDTSCP
|
||||
/*
|
||||
* kills performance completely, but is accurate
|
||||
* cpuid serializes, but clobbers ebx and ecx
|
||||
*
|
||||
*/
|
||||
|
||||
struct exact_ticks : public base_ticks<exact_ticks, int64_t>
|
||||
{
|
||||
typedef int64_t type;
|
||||
|
||||
static inline type start()
|
||||
{
|
||||
int64_t v;
|
||||
__asm__ __volatile__ (
|
||||
"cpuid;"
|
||||
//"xor %%eax, %%eax\n\t"
|
||||
"rdtsc;"
|
||||
"shl $32, %%rdx;"
|
||||
"or %%rdx, %%rax;"
|
||||
: "=a"(v) /* outputs */
|
||||
: "a"(0x0) /* inputs */
|
||||
: "%ebx", "%ecx", "%rdx" /* clobbers*/
|
||||
);
|
||||
return v;
|
||||
}
|
||||
static inline type stop()
|
||||
{
|
||||
int64_t v;
|
||||
__asm__ __volatile__ (
|
||||
"rdtscp;"
|
||||
"shl $32, %%rdx;"
|
||||
"or %%rax, %%rdx;"
|
||||
"mov %%rdx, %%r10;"
|
||||
"xor %%eax, %%eax\n\t"
|
||||
"cpuid;"
|
||||
"mov %%r10, %%rax;"
|
||||
: "=a" (v)
|
||||
:
|
||||
: "%ebx", "%ecx", "%rdx", "%r10"
|
||||
);
|
||||
return v;
|
||||
}
|
||||
};
|
||||
#else
|
||||
using exact_ticks = fast_ticks;
|
||||
#endif
|
||||
|
||||
|
||||
#else
|
||||
using fast_ticks = hires_ticks;
|
||||
using exact_ticks = fast_ticks;
|
||||
#endif
|
||||
|
||||
template<bool enabled_>
|
||||
struct counter
|
||||
{
|
||||
counter() : m_count(0) { }
|
||||
using type = uint_least64_t;
|
||||
type operator()() const { return m_count; }
|
||||
void inc() { ++m_count; }
|
||||
void reset() { m_count = 0; }
|
||||
constexpr static bool enabled = enabled_;
|
||||
private:
|
||||
type m_count;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct counter<false>
|
||||
{
|
||||
using type = uint_least64_t;
|
||||
constexpr type operator()() const { return 0; }
|
||||
void inc() const { }
|
||||
void reset() const { }
|
||||
constexpr static bool enabled = false;
|
||||
};
|
||||
|
||||
|
||||
template< typename T, bool enabled_ = true>
|
||||
struct timer
|
||||
{
|
||||
using type = typename T::type;
|
||||
using ctype = uint_least64_t;
|
||||
constexpr static bool enabled = enabled_;
|
||||
|
||||
struct guard_t
|
||||
{
|
||||
guard_t() = delete;
|
||||
guard_t(timer &m) noexcept : m_m(m) { m_m.m_time -= T::start(); }
|
||||
~guard_t() { m_m.m_time += T::stop(); ++m_m.m_count; }
|
||||
|
||||
COPYASSIGNMOVE(guard_t, default)
|
||||
|
||||
counter() : m_count(0) { }
|
||||
using type = uint_least64_t;
|
||||
type operator()() const noexcept { return m_count; }
|
||||
void inc() noexcept { ++m_count; }
|
||||
void reset() noexcept { m_count = 0; }
|
||||
constexpr static bool enabled = enabled_;
|
||||
private:
|
||||
timer &m_m;
|
||||
type m_count;
|
||||
};
|
||||
|
||||
friend struct guard_t;
|
||||
|
||||
timer() : m_time(0), m_count(0) { }
|
||||
|
||||
type operator()() const { return m_time; }
|
||||
|
||||
void reset() { m_time = 0; m_count = 0; }
|
||||
type average() const { return (m_count == 0) ? 0 : m_time / m_count; }
|
||||
type total() const { return m_time; }
|
||||
ctype count() const { return m_count; }
|
||||
|
||||
double as_seconds() const { return static_cast<double>(total())
|
||||
/ static_cast<double>(T::per_second()); }
|
||||
|
||||
guard_t guard() { return guard_t(*this); }
|
||||
private:
|
||||
type m_time;
|
||||
ctype m_count;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct timer<T, false>
|
||||
{
|
||||
using type = typename T::type;
|
||||
using ctype = uint_least64_t;
|
||||
|
||||
struct guard_t
|
||||
template<>
|
||||
struct counter<false>
|
||||
{
|
||||
guard_t() = default;
|
||||
COPYASSIGNMOVE(guard_t, default)
|
||||
/* using default constructor will trigger warning on
|
||||
* unused local variable.
|
||||
*/
|
||||
// NOLINTNEXTLINE(modernize-use-equals-default)
|
||||
~guard_t() { }
|
||||
using type = uint_least64_t;
|
||||
constexpr type operator()() const { return 0; }
|
||||
void inc() const { }
|
||||
void reset() const { }
|
||||
constexpr static bool enabled = false;
|
||||
};
|
||||
|
||||
constexpr type operator()() const { return 0; }
|
||||
void reset() const { }
|
||||
constexpr type average() const { return 0; }
|
||||
constexpr type total() const { return 0; }
|
||||
constexpr ctype count() const { return 0; }
|
||||
constexpr double as_seconds() const { return 0.0; }
|
||||
constexpr static bool enabled = false;
|
||||
guard_t guard() { return guard_t(); }
|
||||
};
|
||||
|
||||
template< typename T, bool enabled_ = true>
|
||||
struct timer
|
||||
{
|
||||
using type = typename T::type;
|
||||
using ctype = uint_least64_t;
|
||||
constexpr static bool enabled = enabled_;
|
||||
|
||||
struct guard_t
|
||||
{
|
||||
guard_t() = delete;
|
||||
guard_t(timer &m) noexcept : m_m(m) { m_m.m_time -= T::start(); }
|
||||
~guard_t() { m_m.m_time += T::stop(); ++m_m.m_count; }
|
||||
|
||||
COPYASSIGNMOVE(guard_t, default)
|
||||
|
||||
private:
|
||||
timer &m_m;
|
||||
};
|
||||
|
||||
friend struct guard_t;
|
||||
|
||||
timer() : m_time(0), m_count(0) { }
|
||||
|
||||
type operator()() const { return m_time; }
|
||||
|
||||
void reset() { m_time = 0; m_count = 0; }
|
||||
type average() const { return (m_count == 0) ? 0 : m_time / m_count; }
|
||||
type total() const { return m_time; }
|
||||
ctype count() const { return m_count; }
|
||||
|
||||
double as_seconds() const { return static_cast<double>(total())
|
||||
/ static_cast<double>(T::per_second()); }
|
||||
|
||||
guard_t guard() { return guard_t(*this); }
|
||||
private:
|
||||
type m_time;
|
||||
ctype m_count;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct timer<T, false>
|
||||
{
|
||||
using type = typename T::type;
|
||||
using ctype = uint_least64_t;
|
||||
|
||||
struct guard_t
|
||||
{
|
||||
guard_t() = default;
|
||||
COPYASSIGNMOVE(guard_t, default)
|
||||
/* using default constructor will trigger warning on
|
||||
* unused local variable.
|
||||
*/
|
||||
// NOLINTNEXTLINE(modernize-use-equals-default)
|
||||
~guard_t() { }
|
||||
};
|
||||
|
||||
constexpr type operator()() const { return 0; }
|
||||
void reset() const { }
|
||||
constexpr type average() const { return 0; }
|
||||
constexpr type total() const { return 0; }
|
||||
constexpr ctype count() const { return 0; }
|
||||
constexpr double as_seconds() const { return 0.0; }
|
||||
constexpr static bool enabled = false;
|
||||
guard_t guard() { return guard_t(); }
|
||||
};
|
||||
|
||||
} // namespace chrono
|
||||
//============================================================
|
||||
// Performance tracking
|
||||
//============================================================
|
||||
|
||||
template<bool enabled_>
|
||||
using pperftime_t = plib::chrono::timer<plib::chrono::exact_ticks, enabled_>;
|
||||
|
||||
template<bool enabled_>
|
||||
using pperfcount_t = plib::chrono::counter<enabled_>;
|
||||
} // namespace plib
|
||||
|
||||
#endif /* PCHRONO_H_ */
|
||||
|
@ -1,7 +1,7 @@
|
||||
// license:GPL-2.0+
|
||||
// copyright-holders:Couriersud
|
||||
/*
|
||||
* nl_string.c
|
||||
* pfm_log.cpp
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -10,283 +10,506 @@
|
||||
#ifndef PLISTS_H_
|
||||
#define PLISTS_H_
|
||||
|
||||
#include "palloc.h"
|
||||
#include "pchrono.h"
|
||||
#include "pstring.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace plib {
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* uninitialised_array_t:
|
||||
* fixed size array allowing to override constructor and initialize
|
||||
* members by placement new.
|
||||
*
|
||||
* Use with care. This template is provided to improve locality of storage
|
||||
* in high frequency applications. It should not be used for anything else.
|
||||
* ---------------------------------------------------------------------------------------- */
|
||||
|
||||
template <class C, std::size_t N>
|
||||
class uninitialised_array_t
|
||||
{
|
||||
public:
|
||||
|
||||
using iterator = C *;
|
||||
using const_iterator = const C *;
|
||||
|
||||
//uninitialised_array_t() noexcept = default;
|
||||
uninitialised_array_t() noexcept
|
||||
: m_initialized(0)
|
||||
{
|
||||
}
|
||||
|
||||
COPYASSIGNMOVE(uninitialised_array_t, delete)
|
||||
~uninitialised_array_t() noexcept
|
||||
{
|
||||
if (m_initialized>=N)
|
||||
for (std::size_t i=0; i<N; i++)
|
||||
(*this)[i].~C();
|
||||
}
|
||||
|
||||
size_t size() const { return N; }
|
||||
|
||||
C& operator[](const std::size_t &index) noexcept
|
||||
{
|
||||
return *reinterpret_cast<C *>(&m_buf[index]);
|
||||
}
|
||||
|
||||
const C& operator[](const std::size_t &index) const noexcept
|
||||
{
|
||||
return *reinterpret_cast<const C *>(&m_buf[index]);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void emplace(const std::size_t index, Args&&... args)
|
||||
{
|
||||
m_initialized++;
|
||||
// allocate on buffer
|
||||
new (&m_buf[index]) C(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
iterator begin() const noexcept { return reinterpret_cast<iterator>(&m_buf[0]); }
|
||||
iterator end() const noexcept { return reinterpret_cast<iterator>(&m_buf[N]); }
|
||||
|
||||
iterator begin() noexcept { return reinterpret_cast<iterator>(&m_buf[0]); }
|
||||
iterator end() noexcept { return reinterpret_cast<iterator>(&m_buf[N]); }
|
||||
|
||||
const_iterator cbegin() const noexcept { return reinterpret_cast<const_iterator>(&m_buf[0]); }
|
||||
const_iterator cend() const noexcept { return reinterpret_cast<const_iterator>(&m_buf[N]); }
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
|
||||
/* ensure proper alignment */
|
||||
PALIGNAS_VECTOROPT()
|
||||
std::array<typename std::aligned_storage<sizeof(C), alignof(C)>::type, N> m_buf;
|
||||
unsigned m_initialized;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// plinkedlist_t: a simple linked list
|
||||
// the list allows insertions / deletions if used properly
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
#if 0
|
||||
template <class LC>
|
||||
class linkedlist_t
|
||||
{
|
||||
public:
|
||||
|
||||
struct element_t
|
||||
/**! fixed size array allowing to override constructor and initialize members by placement new.
|
||||
*
|
||||
* Use with care. This template is provided to improve locality of storage
|
||||
* in high frequency applications. It should not be used for anything else.
|
||||
*
|
||||
*/
|
||||
template <class C, std::size_t N>
|
||||
class uninitialised_array_t
|
||||
{
|
||||
public:
|
||||
|
||||
friend class linkedlist_t<LC>;
|
||||
using iterator = C *;
|
||||
using const_iterator = const C *;
|
||||
|
||||
constexpr element_t() : m_next(nullptr) {}
|
||||
constexpr element_t(const element_t &rhs) = delete;
|
||||
constexpr element_t(element_t &&rhs) = delete;
|
||||
//uninitialised_array_t() noexcept = default;
|
||||
uninitialised_array_t() noexcept
|
||||
: m_initialized(0)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr LC *next() const noexcept { return m_next; }
|
||||
COPYASSIGNMOVE(uninitialised_array_t, delete)
|
||||
~uninitialised_array_t() noexcept
|
||||
{
|
||||
if (m_initialized>=N)
|
||||
for (std::size_t i=0; i<N; i++)
|
||||
(*this)[i].~C();
|
||||
}
|
||||
|
||||
size_t size() const { return N; }
|
||||
|
||||
C& operator[](const std::size_t &index) noexcept
|
||||
{
|
||||
return *reinterpret_cast<C *>(&m_buf[index]);
|
||||
}
|
||||
|
||||
const C& operator[](const std::size_t &index) const noexcept
|
||||
{
|
||||
return *reinterpret_cast<const C *>(&m_buf[index]);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void emplace(const std::size_t index, Args&&... args)
|
||||
{
|
||||
m_initialized++;
|
||||
// allocate on buffer
|
||||
new (&m_buf[index]) C(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
iterator begin() const noexcept { return reinterpret_cast<iterator>(&m_buf[0]); }
|
||||
iterator end() const noexcept { return reinterpret_cast<iterator>(&m_buf[N]); }
|
||||
|
||||
iterator begin() noexcept { return reinterpret_cast<iterator>(&m_buf[0]); }
|
||||
iterator end() noexcept { return reinterpret_cast<iterator>(&m_buf[N]); }
|
||||
|
||||
const_iterator cbegin() const noexcept { return reinterpret_cast<const_iterator>(&m_buf[0]); }
|
||||
const_iterator cend() const noexcept { return reinterpret_cast<const_iterator>(&m_buf[N]); }
|
||||
|
||||
protected:
|
||||
~element_t() = default;
|
||||
|
||||
private:
|
||||
LC * m_next;
|
||||
|
||||
/* ensure proper alignment */
|
||||
PALIGNAS_VECTOROPT()
|
||||
std::array<typename std::aligned_storage<sizeof(C), alignof(C)>::type, N> m_buf;
|
||||
unsigned m_initialized;
|
||||
};
|
||||
|
||||
struct iter_t final : public std::iterator<std::forward_iterator_tag, LC>
|
||||
{
|
||||
private:
|
||||
LC* p;
|
||||
public:
|
||||
explicit constexpr iter_t(LC* x) noexcept : p(x) { }
|
||||
explicit constexpr iter_t(const iter_t &rhs) noexcept : p(rhs.p) { }
|
||||
iter_t(iter_t &&rhs) noexcept { std::swap(*this, rhs); }
|
||||
iter_t& operator=(const iter_t &rhs) { iter_t t(rhs); std::swap(*this, t); return *this; }
|
||||
iter_t& operator=(iter_t &&rhs) { std::swap(*this, rhs); return *this; }
|
||||
iter_t& operator++() noexcept {p = p->next();return *this;}
|
||||
iter_t operator++(int) noexcept {iter_t tmp(*this); operator++(); return tmp;}
|
||||
constexpr bool operator==(const iter_t& rhs) const noexcept {return p == rhs.p;}
|
||||
constexpr bool operator!=(const iter_t& rhs) const noexcept {return p != rhs.p;}
|
||||
/* constexpr */ LC& operator*() noexcept {return *p;}
|
||||
/* constexpr */ LC* operator->() noexcept {return p;}
|
||||
|
||||
constexpr LC& operator*() const noexcept {return *p;}
|
||||
constexpr LC* operator->() const noexcept {return p;}
|
||||
};
|
||||
|
||||
constexpr linkedlist_t() : m_head(nullptr) {}
|
||||
|
||||
constexpr iter_t begin() const noexcept { return iter_t(m_head); }
|
||||
constexpr iter_t end() const noexcept { return iter_t(nullptr); }
|
||||
|
||||
void push_front(LC *elem) noexcept
|
||||
{
|
||||
elem->m_next = m_head;
|
||||
m_head = elem;
|
||||
}
|
||||
|
||||
void push_back(LC *elem) noexcept
|
||||
{
|
||||
LC **p = &m_head;
|
||||
while (*p != nullptr)
|
||||
{
|
||||
p = &((*p)->m_next);
|
||||
}
|
||||
*p = elem;
|
||||
elem->m_next = nullptr;
|
||||
}
|
||||
|
||||
void remove(const LC *elem) noexcept
|
||||
{
|
||||
auto p = &m_head;
|
||||
while(*p != elem)
|
||||
{
|
||||
//nl_assert(*p != nullptr);
|
||||
p = &((*p)->m_next);
|
||||
}
|
||||
(*p) = elem->m_next;
|
||||
}
|
||||
|
||||
LC *front() const noexcept { return m_head; }
|
||||
void clear() noexcept { m_head = nullptr; }
|
||||
constexpr bool empty() const noexcept { return (m_head == nullptr); }
|
||||
|
||||
private:
|
||||
LC *m_head;
|
||||
};
|
||||
#else
|
||||
template <class LC>
|
||||
class linkedlist_t
|
||||
{
|
||||
public:
|
||||
|
||||
struct element_t
|
||||
/**! a simple linked list.
|
||||
*
|
||||
* the list allows insertions deletions whilst being processed.
|
||||
*/
|
||||
template <class LC>
|
||||
class linkedlist_t
|
||||
{
|
||||
public:
|
||||
|
||||
friend class linkedlist_t<LC>;
|
||||
struct element_t
|
||||
{
|
||||
public:
|
||||
friend class linkedlist_t<LC>;
|
||||
|
||||
constexpr element_t() : m_next(nullptr), m_prev(nullptr) {}
|
||||
~element_t() noexcept = default;
|
||||
constexpr element_t() : m_next(nullptr), m_prev(nullptr) {}
|
||||
~element_t() noexcept = default;
|
||||
|
||||
COPYASSIGNMOVE(element_t, delete)
|
||||
COPYASSIGNMOVE(element_t, delete)
|
||||
|
||||
constexpr LC *next() const noexcept { return m_next; }
|
||||
constexpr LC *prev() const noexcept { return m_prev; }
|
||||
private:
|
||||
LC * m_next;
|
||||
LC * m_prev;
|
||||
};
|
||||
|
||||
struct iter_t final : public std::iterator<std::forward_iterator_tag, LC>
|
||||
{
|
||||
private:
|
||||
LC* p;
|
||||
public:
|
||||
explicit constexpr iter_t(LC* x) noexcept : p(x) { }
|
||||
constexpr iter_t(iter_t &rhs) noexcept : p(rhs.p) { }
|
||||
iter_t(iter_t &&rhs) noexcept { std::swap(*this, rhs); }
|
||||
iter_t& operator=(const iter_t &rhs) noexcept { if (this != &rhs) p = rhs.p; return *this; }
|
||||
iter_t& operator=(iter_t &&rhs) noexcept { std::swap(*this, rhs); return *this; }
|
||||
~iter_t() = default;
|
||||
|
||||
iter_t& operator++() noexcept { p = p->next();return *this; }
|
||||
// NOLINTNEXTLINE(cert-dcl21-cpp)
|
||||
iter_t operator++(int) & noexcept { const iter_t tmp(*this); operator++(); return tmp; }
|
||||
|
||||
constexpr bool operator==(const iter_t& rhs) const noexcept { return p == rhs.p; }
|
||||
constexpr bool operator!=(const iter_t& rhs) const noexcept { return p != rhs.p; }
|
||||
C14CONSTEXPR LC& operator*() noexcept { return *p; }
|
||||
C14CONSTEXPR LC* operator->() noexcept { return p; }
|
||||
|
||||
C14CONSTEXPR LC& operator*() const noexcept { return *p; }
|
||||
C14CONSTEXPR LC* operator->() const noexcept { return p; }
|
||||
};
|
||||
|
||||
constexpr linkedlist_t() : m_head(nullptr) {}
|
||||
|
||||
constexpr iter_t begin() const noexcept { return iter_t(m_head); }
|
||||
constexpr iter_t end() const noexcept { return iter_t(nullptr); }
|
||||
|
||||
void push_front(LC *elem) noexcept
|
||||
{
|
||||
elem->m_next = m_head;
|
||||
elem->m_prev = nullptr;
|
||||
if (m_head)
|
||||
m_head->m_prev = elem;
|
||||
m_head = elem;
|
||||
}
|
||||
|
||||
void push_back(LC *elem) noexcept
|
||||
{
|
||||
LC ** p(&m_head);
|
||||
LC * prev(nullptr);
|
||||
while (*p != nullptr)
|
||||
{
|
||||
prev = *p;
|
||||
p = &((*p)->m_next);
|
||||
}
|
||||
*p = elem;
|
||||
elem->m_prev = prev;
|
||||
elem->m_next = nullptr;
|
||||
}
|
||||
|
||||
void remove(const LC *elem) noexcept
|
||||
{
|
||||
if (elem->m_prev)
|
||||
elem->m_prev->m_next = elem->m_next;
|
||||
else
|
||||
m_head = elem->m_next;
|
||||
if (elem->m_next)
|
||||
elem->m_next->m_prev = elem->m_prev;
|
||||
else
|
||||
{
|
||||
/* update tail */
|
||||
}
|
||||
}
|
||||
|
||||
LC *front() const noexcept { return m_head; }
|
||||
constexpr bool empty() const noexcept { return (m_head == nullptr); }
|
||||
void clear() noexcept
|
||||
{
|
||||
LC *p(m_head);
|
||||
while (p != nullptr)
|
||||
{
|
||||
LC *n(p->m_next);
|
||||
p->m_next = nullptr;
|
||||
p->m_prev = nullptr;
|
||||
p = n;
|
||||
}
|
||||
m_head = nullptr;
|
||||
}
|
||||
|
||||
constexpr LC *next() const noexcept { return m_next; }
|
||||
constexpr LC *prev() const noexcept { return m_prev; }
|
||||
private:
|
||||
LC * m_next;
|
||||
LC * m_prev;
|
||||
LC *m_head;
|
||||
};
|
||||
|
||||
struct iter_t final : public std::iterator<std::forward_iterator_tag, LC>
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// FIXME: Move elsewhere
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
template<bool enabled_ = true>
|
||||
class pspin_mutex
|
||||
{
|
||||
private:
|
||||
LC* p;
|
||||
public:
|
||||
explicit constexpr iter_t(LC* x) noexcept : p(x) { }
|
||||
constexpr iter_t(iter_t &rhs) noexcept : p(rhs.p) { }
|
||||
iter_t(iter_t &&rhs) noexcept { std::swap(*this, rhs); }
|
||||
iter_t& operator=(const iter_t &rhs) noexcept { p = rhs.p; return *this; }
|
||||
iter_t& operator=(iter_t &&rhs) noexcept { std::swap(*this, rhs); return *this; }
|
||||
iter_t& operator++() noexcept {p = p->next();return *this;}
|
||||
// NOLINTNEXTLINE(cert-dcl21-cpp)
|
||||
iter_t operator++(int) & noexcept {const iter_t tmp(*this); operator++(); return tmp;}
|
||||
|
||||
~iter_t() = default;
|
||||
|
||||
constexpr bool operator==(const iter_t& rhs) const noexcept {return p == rhs.p;}
|
||||
constexpr bool operator!=(const iter_t& rhs) const noexcept {return p != rhs.p;}
|
||||
constexpr LC& operator*() noexcept {return *p;}
|
||||
constexpr LC* operator->() noexcept {return p;}
|
||||
|
||||
constexpr LC& operator*() const noexcept {return *p;}
|
||||
constexpr LC* operator->() const noexcept {return p;}
|
||||
pspin_mutex() noexcept = default;
|
||||
void lock() noexcept{ while (m_lock.test_and_set(std::memory_order_acquire)) { } }
|
||||
void unlock() noexcept { m_lock.clear(std::memory_order_release); }
|
||||
private:
|
||||
PALIGNAS_CACHELINE()
|
||||
std::atomic_flag m_lock = ATOMIC_FLAG_INIT;
|
||||
};
|
||||
|
||||
constexpr linkedlist_t() : m_head(nullptr) {}
|
||||
|
||||
constexpr iter_t begin() const noexcept { return iter_t(m_head); }
|
||||
constexpr iter_t end() const noexcept { return iter_t(nullptr); }
|
||||
|
||||
void push_front(LC *elem) noexcept
|
||||
template<>
|
||||
class pspin_mutex<false>
|
||||
{
|
||||
if (m_head)
|
||||
m_head->m_prev = elem;
|
||||
elem->m_next = m_head;
|
||||
elem->m_prev = nullptr;
|
||||
m_head = elem;
|
||||
}
|
||||
public:
|
||||
void lock() const noexcept { }
|
||||
void unlock() const noexcept { }
|
||||
};
|
||||
|
||||
void push_back(LC *elem) noexcept
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// timed queue
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
template <class Element, class Time>
|
||||
struct pqentry_t final
|
||||
{
|
||||
LC ** p(&m_head);
|
||||
LC * prev(nullptr);
|
||||
while (*p != nullptr)
|
||||
constexpr pqentry_t() noexcept : m_exec_time(), m_object(nullptr) { }
|
||||
constexpr pqentry_t(const Time t, const Element o) noexcept : m_exec_time(t), m_object(o) { }
|
||||
#if 0
|
||||
~pqentry_t() = default;
|
||||
constexpr pqentry_t(const pqentry_t &e) noexcept = default;
|
||||
constexpr pqentry_t(pqentry_t &&e) noexcept = default;
|
||||
pqentry_t& operator=(pqentry_t && other) noexcept = default;
|
||||
pqentry_t& operator=(const pqentry_t &other) noexcept = default;
|
||||
|
||||
void swap(pqentry_t &other) noexcept
|
||||
{
|
||||
prev = *p;
|
||||
p = &((*p)->m_next);
|
||||
std::swap(m_exec_time, other.m_exec_time);
|
||||
std::swap(m_object, other.m_object);
|
||||
}
|
||||
*p = elem;
|
||||
elem->m_prev = prev;
|
||||
elem->m_next = nullptr;
|
||||
}
|
||||
|
||||
void remove(const LC *elem) noexcept
|
||||
{
|
||||
if (elem->m_prev)
|
||||
elem->m_prev->m_next = elem->m_next;
|
||||
else
|
||||
m_head = elem->m_next;
|
||||
if (elem->m_next)
|
||||
elem->m_next->m_prev = elem->m_prev;
|
||||
else
|
||||
{
|
||||
/* update tail */
|
||||
}
|
||||
}
|
||||
|
||||
LC *front() const noexcept { return m_head; }
|
||||
constexpr bool empty() const noexcept { return (m_head == nullptr); }
|
||||
void clear() noexcept
|
||||
{
|
||||
LC *p(m_head);
|
||||
while (p != nullptr)
|
||||
{
|
||||
LC *n(p->m_next);
|
||||
p->m_next = nullptr;
|
||||
p->m_prev = nullptr;
|
||||
p = n;
|
||||
}
|
||||
m_head = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
LC *m_head;
|
||||
};
|
||||
#endif
|
||||
inline bool operator ==(const pqentry_t &rhs) const noexcept
|
||||
{
|
||||
return m_object == rhs.m_object;
|
||||
}
|
||||
|
||||
inline bool operator ==(const Element &rhs) const noexcept
|
||||
{
|
||||
return m_object == rhs;
|
||||
}
|
||||
|
||||
inline bool operator <=(const pqentry_t &rhs) const noexcept
|
||||
{
|
||||
return (m_exec_time <= rhs.m_exec_time);
|
||||
}
|
||||
|
||||
inline bool operator <(const pqentry_t &rhs) const noexcept
|
||||
{
|
||||
return (m_exec_time < rhs.m_exec_time);
|
||||
}
|
||||
|
||||
inline static constexpr pqentry_t never() noexcept { return pqentry_t(Time::never(), nullptr); }
|
||||
|
||||
Time m_exec_time;
|
||||
Element m_object;
|
||||
};
|
||||
|
||||
/* Use TS = true for a threadsafe queue */
|
||||
template <class T, bool TS>
|
||||
class timed_queue_linear : nocopyassignmove
|
||||
{
|
||||
public:
|
||||
|
||||
explicit timed_queue_linear(const std::size_t list_size)
|
||||
: m_list(list_size)
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
std::size_t capacity() const noexcept { return m_list.capacity() - 1; }
|
||||
bool empty() const noexcept { return (m_end == &m_list[1]); }
|
||||
|
||||
template<bool KEEPSTAT>
|
||||
void push(T && e) noexcept
|
||||
{
|
||||
#if 0
|
||||
/* Lock */
|
||||
lock_guard_type lck(m_lock);
|
||||
T * i(m_end-1);
|
||||
for (; *i < e; --i)
|
||||
{
|
||||
*(i+1) = *(i);
|
||||
if (KEEPSTAT)
|
||||
m_prof_sortmove.inc();
|
||||
}
|
||||
*(i+1) = std::move(e);
|
||||
++m_end;
|
||||
#else
|
||||
/* Lock */
|
||||
lock_guard_type lck(m_lock);
|
||||
T * i(m_end++);
|
||||
*i = std::move(e);
|
||||
for (; *(i-1) < *i; --i)
|
||||
{
|
||||
std::swap(*(i-1), *(i));
|
||||
if (KEEPSTAT)
|
||||
m_prof_sortmove.inc();
|
||||
}
|
||||
#endif
|
||||
if (KEEPSTAT)
|
||||
m_prof_call.inc();
|
||||
}
|
||||
|
||||
T pop() noexcept { return *(--m_end); }
|
||||
const T &top() const noexcept { return *(m_end-1); }
|
||||
|
||||
template <bool KEEPSTAT, class R>
|
||||
void remove(const R &elem) noexcept
|
||||
{
|
||||
/* Lock */
|
||||
lock_guard_type lck(m_lock);
|
||||
if (KEEPSTAT)
|
||||
m_prof_remove.inc();
|
||||
for (T * i = m_end - 1; i > &m_list[0]; --i)
|
||||
{
|
||||
// == operator ignores time!
|
||||
if (*i == elem)
|
||||
{
|
||||
std::copy(i+1, m_end--, i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <bool KEEPSTAT, class R>
|
||||
void retime(R && elem) noexcept
|
||||
{
|
||||
/* Lock */
|
||||
lock_guard_type lck(m_lock);
|
||||
if (KEEPSTAT)
|
||||
m_prof_retime.inc();
|
||||
|
||||
for (R * i = m_end - 1; i > &m_list[0]; --i)
|
||||
{
|
||||
if (*i == elem) // partial equal!
|
||||
{
|
||||
*i = std::forward<R>(elem);
|
||||
while (*(i-1) < *i)
|
||||
{
|
||||
std::swap(*(i-1), *i);
|
||||
--i;
|
||||
}
|
||||
while (i < m_end && *i < *(i+1))
|
||||
{
|
||||
std::swap(*(i+1), *i);
|
||||
++i;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void clear() noexcept
|
||||
{
|
||||
lock_guard_type lck(m_lock);
|
||||
m_end = &m_list[0];
|
||||
/* put an empty element with maximum time into the queue.
|
||||
* the insert algo above will run into this element and doesn't
|
||||
* need a comparison with queue start.
|
||||
*/
|
||||
m_list[0] = T::never();
|
||||
m_end++;
|
||||
}
|
||||
|
||||
// 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]); }
|
||||
const T & operator[](const std::size_t index) const noexcept { return m_list[ 1 + index]; }
|
||||
private:
|
||||
using mutex_type = pspin_mutex<TS>;
|
||||
using lock_guard_type = std::lock_guard<mutex_type>;
|
||||
|
||||
mutex_type m_lock;
|
||||
PALIGNAS_CACHELINE()
|
||||
T * m_end;
|
||||
aligned_vector<T> m_list;
|
||||
|
||||
public:
|
||||
// profiling
|
||||
pperfcount_t<true> m_prof_sortmove;
|
||||
pperfcount_t<true> m_prof_call;
|
||||
pperfcount_t<true> m_prof_remove;
|
||||
pperfcount_t<true> m_prof_retime;
|
||||
};
|
||||
|
||||
template <class T, bool TS>
|
||||
class timed_queue_heap : nocopyassignmove
|
||||
{
|
||||
public:
|
||||
|
||||
struct compare
|
||||
{
|
||||
constexpr bool operator()(const T &a, const T &b) const { return b <= a; }
|
||||
};
|
||||
|
||||
explicit timed_queue_heap(const std::size_t list_size)
|
||||
: m_list(list_size)
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
std::size_t capacity() const noexcept { return m_list.capacity(); }
|
||||
bool empty() const noexcept { return &m_list[0] == m_end; }
|
||||
|
||||
template <bool KEEPSTAT>
|
||||
void push(T &&e) noexcept
|
||||
{
|
||||
/* Lock */
|
||||
lock_guard_type lck(m_lock);
|
||||
*m_end++ = e;
|
||||
std::push_heap(&m_list[0], m_end, compare());
|
||||
if (KEEPSTAT)
|
||||
m_prof_call.inc();
|
||||
}
|
||||
|
||||
T pop() noexcept
|
||||
{
|
||||
T ret(m_list[0]);
|
||||
std::pop_heap(&m_list[0], m_end, compare());
|
||||
m_end--;
|
||||
return ret;
|
||||
}
|
||||
|
||||
const T &top() const noexcept { return m_list[0]; }
|
||||
|
||||
template <bool KEEPSTAT, class R>
|
||||
void remove(const R &elem) noexcept
|
||||
{
|
||||
/* Lock */
|
||||
lock_guard_type lck(m_lock);
|
||||
if (KEEPSTAT)
|
||||
m_prof_remove.inc();
|
||||
for (T * i = m_end - 1; i >= &m_list[0]; i--)
|
||||
{
|
||||
if (*i == elem)
|
||||
{
|
||||
m_end--;
|
||||
for (;i < m_end; i++)
|
||||
*i = std::move(*(i+1));
|
||||
std::make_heap(&m_list[0], m_end, compare());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <bool KEEPSTAT>
|
||||
void retime(const T &elem) noexcept
|
||||
{
|
||||
/* Lock */
|
||||
lock_guard_type lck(m_lock);
|
||||
if (KEEPSTAT)
|
||||
m_prof_retime.inc();
|
||||
for (T * i = m_end - 1; i >= &m_list[0]; i--)
|
||||
{
|
||||
if (*i == elem) // partial equal!
|
||||
{
|
||||
*i = elem;
|
||||
std::make_heap(&m_list[0], m_end, compare());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
lock_guard_type lck(m_lock);
|
||||
m_list.clear();
|
||||
m_end = &m_list[0];
|
||||
}
|
||||
|
||||
// save state support & mame disasm
|
||||
|
||||
constexpr const T *listptr() const { return &m_list[0]; }
|
||||
constexpr std::size_t size() const noexcept { return m_list.size(); }
|
||||
constexpr const T & operator[](const std::size_t index) const { return m_list[ 0 + index]; }
|
||||
private:
|
||||
using mutex_type = pspin_mutex<TS>;
|
||||
using lock_guard_type = std::lock_guard<mutex_type>;
|
||||
|
||||
mutex_type m_lock;
|
||||
std::vector<T> m_list;
|
||||
T *m_end;
|
||||
|
||||
public:
|
||||
// profiling
|
||||
pperfcount_t<true> m_prof_sortmove;
|
||||
pperfcount_t<true> m_prof_call;
|
||||
pperfcount_t<true> m_prof_remove;
|
||||
pperfcount_t<true> m_prof_retime;
|
||||
};
|
||||
|
||||
} // namespace plib
|
||||
|
||||
#endif /* PLISTS_H_ */
|
||||
|
@ -123,6 +123,12 @@ namespace plib {
|
||||
}
|
||||
}
|
||||
|
||||
static inline mempool &instance()
|
||||
{
|
||||
static mempool s_mempool;
|
||||
return s_mempool;
|
||||
}
|
||||
|
||||
void *allocate(size_t align, size_t size)
|
||||
{
|
||||
block *b = nullptr;
|
||||
@ -220,6 +226,8 @@ namespace plib {
|
||||
}
|
||||
}
|
||||
|
||||
bool operator ==(const mempool &rhs) { return this == &rhs; }
|
||||
|
||||
};
|
||||
|
||||
} // namespace plib
|
||||
|
@ -261,8 +261,8 @@ ptokenizer::token_t ptokenizer::get_token_internal()
|
||||
|
||||
ppreprocessor::ppreprocessor(defines_map_type *defines)
|
||||
: std::istream(new readbuffer(this))
|
||||
, m_ifflag(0)
|
||||
, m_level(0)
|
||||
, m_if_flag(0)
|
||||
, m_if_level(0)
|
||||
, m_lineno(0)
|
||||
, m_pos(0)
|
||||
, m_state(PROCESS)
|
||||
@ -473,34 +473,34 @@ pstring ppreprocessor::process_line(pstring line)
|
||||
std::vector<pstring> lti(psplit(lt, " ", true));
|
||||
if (lti[0] == "#if")
|
||||
{
|
||||
m_level++;
|
||||
m_if_level++;
|
||||
std::size_t start = 0;
|
||||
lt = replace_macros(lt);
|
||||
std::vector<pstring> t(psplit(replace_all(lt.substr(3), " ", ""), m_expr_sep));
|
||||
auto val = static_cast<int>(expr(t, start, 255));
|
||||
if (val == 0)
|
||||
m_ifflag |= (1 << m_level);
|
||||
m_if_flag |= (1 << m_if_level);
|
||||
}
|
||||
else if (lti[0] == "#ifdef")
|
||||
{
|
||||
m_level++;
|
||||
m_if_level++;
|
||||
if (get_define(lti[1]) == nullptr)
|
||||
m_ifflag |= (1 << m_level);
|
||||
m_if_flag |= (1 << m_if_level);
|
||||
}
|
||||
else if (lti[0] == "#ifndef")
|
||||
{
|
||||
m_level++;
|
||||
m_if_level++;
|
||||
if (get_define(lti[1]) != nullptr)
|
||||
m_ifflag |= (1 << m_level);
|
||||
m_if_flag |= (1 << m_if_level);
|
||||
}
|
||||
else if (lti[0] == "#else")
|
||||
{
|
||||
m_ifflag ^= (1 << m_level);
|
||||
m_if_flag ^= (1 << m_if_level);
|
||||
}
|
||||
else if (lti[0] == "#endif")
|
||||
{
|
||||
m_ifflag &= ~(1 << m_level);
|
||||
m_level--;
|
||||
m_if_flag &= ~(1 << m_if_level);
|
||||
m_if_level--;
|
||||
}
|
||||
else if (lti[0] == "#include")
|
||||
{
|
||||
@ -508,7 +508,7 @@ pstring ppreprocessor::process_line(pstring line)
|
||||
}
|
||||
else if (lti[0] == "#pragma")
|
||||
{
|
||||
if (m_ifflag == 0 && lti.size() > 3 && lti[1] == "NETLIST")
|
||||
if (m_if_flag == 0 && lti.size() > 3 && lti[1] == "NETLIST")
|
||||
{
|
||||
if (lti[2] == "warning")
|
||||
error("NETLIST: " + catremainder(lti, 3, " "));
|
||||
@ -516,7 +516,7 @@ pstring ppreprocessor::process_line(pstring line)
|
||||
}
|
||||
else if (lti[0] == "#define")
|
||||
{
|
||||
if (m_ifflag == 0)
|
||||
if (m_if_flag == 0)
|
||||
{
|
||||
if (lti.size() < 2)
|
||||
error("PREPRO: define needs at least one argument: " + line);
|
||||
@ -534,14 +534,14 @@ pstring ppreprocessor::process_line(pstring line)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_ifflag == 0)
|
||||
if (m_if_flag == 0)
|
||||
error(pfmt("unknown directive on line {1}: {2}")(m_lineno)(replace_macros(line)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lt = replace_macros(lt);
|
||||
if (m_ifflag == 0)
|
||||
if (m_if_flag == 0)
|
||||
ret += lt;
|
||||
}
|
||||
return ret;
|
||||
|
@ -190,7 +190,7 @@ public:
|
||||
{
|
||||
m_lineno++;
|
||||
line = process_line(line);
|
||||
m_buf += decltype(m_buf)(line.c_str()) + static_cast<char>(10);
|
||||
m_outbuf += decltype(m_outbuf)(line.c_str()) + static_cast<char>(10);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@ -202,10 +202,10 @@ public:
|
||||
: std::istream(new readbuffer(this))
|
||||
, m_defines(std::move(s.m_defines))
|
||||
, m_expr_sep(std::move(s.m_expr_sep))
|
||||
, m_ifflag(s.m_ifflag)
|
||||
, m_level(s.m_level)
|
||||
, m_if_flag(s.m_if_flag)
|
||||
, m_if_level(s.m_if_level)
|
||||
, m_lineno(s.m_lineno)
|
||||
, m_buf(std::move(s.m_buf))
|
||||
, m_outbuf(std::move(s.m_outbuf))
|
||||
, m_pos(s.m_pos)
|
||||
, m_state(s.m_state)
|
||||
, m_comment(s.m_comment)
|
||||
@ -225,15 +225,14 @@ protected:
|
||||
|
||||
int_type underflow() override
|
||||
{
|
||||
//printf("here\n");
|
||||
if (this->gptr() == this->egptr())
|
||||
{
|
||||
/* clang reports sign error - weird */
|
||||
std::size_t bytes = pstring_mem_t_size(m_strm->m_buf) - static_cast<std::size_t>(m_strm->m_pos);
|
||||
std::size_t bytes = pstring_mem_t_size(m_strm->m_outbuf) - static_cast<std::size_t>(m_strm->m_pos);
|
||||
|
||||
if (bytes > m_buf.size())
|
||||
bytes = m_buf.size();
|
||||
std::copy(m_strm->m_buf.c_str() + m_strm->m_pos, m_strm->m_buf.c_str() + m_strm->m_pos + bytes, m_buf.data());
|
||||
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());
|
||||
//printf("%ld\n", (long int)bytes);
|
||||
this->setg(m_buf.data(), m_buf.data(), m_buf.data() + bytes);
|
||||
|
||||
@ -268,10 +267,10 @@ private:
|
||||
defines_map_type m_defines;
|
||||
std::vector<pstring> m_expr_sep;
|
||||
|
||||
std::uint_least64_t m_ifflag; // 31 if levels
|
||||
int m_level;
|
||||
std::uint_least64_t m_if_flag; // 31 if levels
|
||||
int m_if_level;
|
||||
int m_lineno;
|
||||
pstring_t<pu8_traits> m_buf;
|
||||
pstring_t<pu8_traits> m_outbuf;
|
||||
std::istream::pos_type m_pos;
|
||||
state_e m_state;
|
||||
pstring m_line;
|
||||
|
@ -15,24 +15,24 @@
|
||||
|
||||
/*
|
||||
*
|
||||
* NL_PMF_TYPE_GNUC_PMF
|
||||
* PMF_TYPE_GNUC_PMF
|
||||
* Use standard pointer to member function syntax C++11
|
||||
*
|
||||
* NL_PMF_TYPE_GNUC_PMF_CONV
|
||||
* PMF_TYPE_GNUC_PMF_CONV
|
||||
* Use gnu extension and convert the pmf to a function pointer.
|
||||
* This is not standard compliant and needs
|
||||
* -Wno-pmf-conversions to compile.
|
||||
*
|
||||
* NL_PMF_TYPE_INTERNAL
|
||||
* PMF_TYPE_INTERNAL
|
||||
* Use the same approach as MAME for deriving the function pointer.
|
||||
* This is compiler-dependent as well
|
||||
*
|
||||
* Benchmarks for ./nltool -c run -f src/mame/machine/nl_pong.cpp -t 10 -n pong_fast
|
||||
*
|
||||
* NL_PMF_TYPE_INTERNAL: 215% 215%
|
||||
* NL_PMF_TYPE_GNUC_PMF: 163% 196%
|
||||
* NL_PMF_TYPE_GNUC_PMF_CONV: 215% 215%
|
||||
* NL_PMF_TYPE_VIRTUAL: 213% 209%
|
||||
* PMF_TYPE_INTERNAL: 215% 215%
|
||||
* PMF_TYPE_GNUC_PMF: 163% 196%
|
||||
* PMF_TYPE_GNUC_PMF_CONV: 215% 215%
|
||||
* PMF_TYPE_VIRTUAL: 213% 209%
|
||||
*
|
||||
* The whole exercise was done to avoid virtual calls. In prior versions of
|
||||
* netlist, the INTERNAL and GNUC_PMF_CONV approach provided significant improvement.
|
||||
|
@ -1,7 +1,7 @@
|
||||
// license:GPL-2.0+
|
||||
// copyright-holders:Couriersud
|
||||
/*
|
||||
* nl_string.c
|
||||
* pstring.cpp
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -17,9 +17,9 @@
|
||||
// noexcept on move operator -> issue with macosx clang
|
||||
#define COPYASSIGNMOVE(name, def) \
|
||||
name(const name &) = def; \
|
||||
name(name &&) /*noexcept*/ = def; \
|
||||
name(name &&) noexcept = def; \
|
||||
name &operator=(const name &) = def; \
|
||||
name &operator=(name &&) /*noexcept*/ = def;
|
||||
name &operator=(name &&) noexcept = def;
|
||||
|
||||
#define COPYASSIGN(name, def) \
|
||||
name(const name &) = def; \
|
||||
@ -36,14 +36,14 @@ namespace plib
|
||||
template<> struct is_integral<INT128> { static constexpr bool value = true; };
|
||||
template<> struct numeric_limits<UINT128>
|
||||
{
|
||||
static constexpr UINT128 max()
|
||||
static constexpr UINT128 max() noexcept
|
||||
{
|
||||
return ~((UINT128)0);
|
||||
}
|
||||
};
|
||||
template<> struct numeric_limits<INT128>
|
||||
{
|
||||
static constexpr INT128 max()
|
||||
static constexpr INT128 max() noexcept
|
||||
{
|
||||
return (~((UINT128)0)) >> 1;
|
||||
}
|
||||
@ -80,7 +80,7 @@ namespace plib
|
||||
// Avoid unused variable warnings
|
||||
//============================================================
|
||||
template<typename... Ts>
|
||||
inline void unused_var(Ts&&...) {}
|
||||
inline void unused_var(Ts&&...) noexcept {}
|
||||
|
||||
//============================================================
|
||||
// is_pow2
|
||||
@ -100,7 +100,7 @@ namespace plib
|
||||
template<typename T>
|
||||
constexpr
|
||||
typename std::enable_if<std::is_integral<T>::value && std::is_signed<T>::value, T>::type
|
||||
abs(T v)
|
||||
abs(T v) noexcept
|
||||
{
|
||||
return v < 0 ? -v : v;
|
||||
}
|
||||
@ -108,14 +108,14 @@ namespace plib
|
||||
template<typename T>
|
||||
constexpr
|
||||
typename std::enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value, T>::type
|
||||
abs(T v)
|
||||
abs(T v) noexcept
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
template<typename M, typename N>
|
||||
constexpr typename std::common_type<M, N>::type
|
||||
gcd(M m, N n)
|
||||
gcd(M m, N n) noexcept
|
||||
{
|
||||
static_assert(std::is_integral<M>::value, "gcd: M must be an integer");
|
||||
static_assert(std::is_integral<N>::value, "gcd: N must be an integer");
|
||||
@ -127,7 +127,7 @@ namespace plib
|
||||
|
||||
template<typename M, typename N>
|
||||
constexpr typename std::common_type<M, N>::type
|
||||
lcm(M m, N n)
|
||||
lcm(M m, N n) noexcept
|
||||
{
|
||||
static_assert(std::is_integral<M>::value, "lcm: M must be an integer");
|
||||
static_assert(std::is_integral<N>::value, "lcm: N must be an integer");
|
||||
|
@ -31,7 +31,6 @@
|
||||
#pragma GCC optimize "ivopts"
|
||||
#endif
|
||||
|
||||
#include "netlist/nl_lists.h"
|
||||
#include "netlist/nl_factory.h"
|
||||
#include "nld_matrix_solver.h"
|
||||
#include "nld_ms_direct.h"
|
||||
|
Loading…
Reference in New Issue
Block a user