diff options
Diffstat (limited to 'src/lib/netlist/plib')
38 files changed, 4004 insertions, 1497 deletions
diff --git a/src/lib/netlist/plib/gmres.h b/src/lib/netlist/plib/gmres.h new file mode 100644 index 00000000000..2c357e97624 --- /dev/null +++ b/src/lib/netlist/plib/gmres.h @@ -0,0 +1,450 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud +/* + * gmres.h + * + */ + +#ifndef PLIB_GMRES_H_ +#define PLIB_GMRES_H_ + +#include "mat_cr.h" +#include "parray.h" +#include "pconfig.h" +#include "vector_ops.h" + +#include <algorithm> +#include <cmath> + + +namespace plib +{ + + template <typename FT, int SIZE> + struct mat_precondition_ILU + { + using mat_type = plib::matrix_compressed_rows_t<FT, SIZE>; + + mat_precondition_ILU(std::size_t size, int ilu_scale = 4 + , std::size_t bw = plib::matrix_compressed_rows_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_use_iLU_preconditioning(ilu_scale >= 0) + , m_ILU_scale(static_cast<std::size_t>(ilu_scale)) + , m_band_width(bw) + { + } + + template <typename M> + void build(M &fill) + { + m_mat.build_from_fill_mat(fill, 0); + if (m_use_iLU_preconditioning) + { + m_LU.gaussian_extend_fill_mat(fill); + m_LU.build_from_fill_mat(fill, m_ILU_scale, m_band_width); // ILU(2) + //m_LU.build_from_fill_mat(fill, 9999, 20); // Band matrix width 20 + } + } + + + template<typename R, typename V> + void calc_rhs(R &rhs, const V &v) + { + m_mat.mult_vec(rhs, v); + } + + void precondition() + { + if (m_use_iLU_preconditioning) + { + if (m_ILU_scale < 1) + m_LU.raw_copy_from(m_mat); + else + m_LU.reduction_copy_from(m_mat); + m_LU.incomplete_LU_factorization(); + } + } + + template<typename V> + void solve_LU_inplace(V &v) + { + if (m_use_iLU_preconditioning) + { + m_LU.solveLUx(v); + } + } + + PALIGNAS_VECTOROPT() + mat_type m_mat; + PALIGNAS_VECTOROPT() + mat_type m_LU; + bool m_use_iLU_preconditioning; + std::size_t m_ILU_scale; + std::size_t m_band_width; + }; + + template <typename FT, int SIZE> + struct mat_precondition_diag + { + mat_precondition_diag(std::size_t size) + : m_mat(size) + , m_diag(size) + , m_use_iLU_preconditioning(true) + { + } + + template <typename M> + void build(M &fill) + { + m_mat.build_from_fill_mat(fill, 0); + } + + template<typename R, typename V> + void calc_rhs(R &rhs, const V &v) + { + m_mat.mult_vec(rhs, v); + } + + void precondition() + { + if (m_use_iLU_preconditioning) + { + for (std::size_t i = 0; i< m_diag.size(); i++) + { + m_diag[i] = 1.0 / m_mat.A[m_mat.diag[i]]; + } + } + } + + template<typename V> + void solve_LU_inplace(V &v) + { + if (m_use_iLU_preconditioning) + { + for (std::size_t i = 0; i< m_diag.size(); i++) + v[i] = v[i] * m_diag[i]; + } + } + + plib::matrix_compressed_rows_t<FT, SIZE> m_mat; + plib::parray<FT, SIZE> m_diag; + bool m_use_iLU_preconditioning; + }; + + /* FIXME: hardcoding RESTART to 20 becomes an issue on very large + * systems. + */ + template <typename FT, int SIZE, int RESTART = 20> + 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(); + + gmres_t(std::size_t size) + : residual(size) + , Ax(size) + , m_size(size) + , m_use_more_precise_stop_condition(false) + { + } + + void givens_mult( const FT c, const FT s, FT & g0, FT & g1 ) + { + const FT g0_last(g0); + + g0 = c * g0 - s * g1; + g1 = s * g0_last + c * g1; + } + + std::size_t size() const { return (SIZE<=0) ? m_size : static_cast<std::size_t>(SIZE); } + + template <typename OPS, typename VT, typename VRHS> + std::size_t solve(OPS &ops, VT &x, const VRHS & rhs, const std::size_t itr_max, float_type accuracy) + { + /*------------------------------------------------------------------------- + * The code below was inspired by code published by John Burkardt under + * the LPGL here: + * + * http://people.sc.fsu.edu/~jburkardt/cpp_src/mgmres/mgmres.html + * + * The code below was completely written from scratch based on the pseudo code + * found here: + * + * http://de.wikipedia.org/wiki/GMRES-Verfahren + * + * The Algorithm itself is described in + * + * Yousef Saad, + * Iterative Methods for Sparse Linear Systems, + * Second Edition, + * SIAM, 20003, + * ISBN: 0898715342, + * LC: QA188.S17. + * + *------------------------------------------------------------------------*/ + + std::size_t itr_used = 0; + double rho_delta = 0.0; + + const std::size_t n = size(); + + ops.precondition(); + + if (m_use_more_precise_stop_condition) + { + /* derive residual for a given delta x + * + * LU y = A dx + * + * ==> rho / accuracy = sqrt(y * y) + * + * This approach will approximate the iterative stop condition + * based |xnew - xold| pretty precisely. But it is slow, or expressed + * differently: The invest doesn't pay off. + */ + + vec_set_scalar(n, residual, accuracy); + ops.calc_rhs(Ax, residual); + + ops.solve_LU_inplace(Ax); + + const float_type rho_to_accuracy = std::sqrt(vec_mult2<FT>(n, Ax)) / accuracy; + + rho_delta = accuracy * rho_to_accuracy; + } + else + rho_delta = accuracy * std::sqrt(static_cast<FT>(n)); + + /* + * Using + * + * vec_set(n, x, rhs); + * ops.solve_LU_inplace(x); + * + * to get a starting point for x degrades convergence speed compared + * to using the last solution for x. + * + * LU x = b; solve for x; + * + */ + + while (itr_used < itr_max) + { + std::size_t last_k = RESTART; + float_type rho; + + ops.calc_rhs(Ax, x); + + vec_sub(n, residual, rhs, Ax); + + ops.solve_LU_inplace(residual); + + rho = std::sqrt(vec_mult2<FT>(n, residual)); + + if (rho < rho_delta) + return itr_used + 1; + + /* FIXME: The "+" is necessary to avoid link issues + * on some systems / compiler versions. Issue reported by + * AJR, no details known yet. + */ + vec_set_scalar(RESTART+1, m_g, +constants<FT>::zero()); + m_g[0] = rho; + + //for (std::size_t i = 0; i < mr + 1; i++) + // vec_set_scalar(mr, m_ht[i], NL_FCONST(0.0)); + + vec_mult_scalar(n, m_v[0], residual, constants<FT>::one() / rho); + + for (std::size_t k = 0; k < RESTART; k++) + { + const std::size_t kp1 = k + 1; + + ops.calc_rhs(m_v[kp1], m_v[k]); + ops.solve_LU_inplace(m_v[kp1]); + + for (std::size_t j = 0; j <= k; j++) + { + m_ht[j][k] = vec_mult<FT>(n, m_v[kp1], m_v[j]); + vec_add_mult_scalar(n, m_v[kp1], m_v[j], -m_ht[j][k]); + } + m_ht[kp1][k] = std::sqrt(vec_mult2<FT>(n, m_v[kp1])); + + if (m_ht[kp1][k] != 0.0) + vec_scale(n, m_v[kp1], constants<FT>::one() / m_ht[kp1][k]); + + for (std::size_t j = 0; j < k; j++) + givens_mult(m_c[j], m_s[j], m_ht[j][k], m_ht[j+1][k]); + + const float_type mu = 1.0 / std::hypot(m_ht[k][k], m_ht[kp1][k]); + + m_c[k] = m_ht[k][k] * mu; + m_s[k] = -m_ht[kp1][k] * mu; + m_ht[k][k] = m_c[k] * m_ht[k][k] - m_s[k] * m_ht[kp1][k]; + m_ht[kp1][k] = 0.0; + + givens_mult(m_c[k], m_s[k], m_g[k], m_g[kp1]); + + rho = std::abs(m_g[kp1]); + + itr_used = itr_used + 1; + + if (rho <= rho_delta) + { + last_k = k; + break; + } + } + + if (last_k >= RESTART) + /* didn't converge within accuracy */ + last_k = RESTART - 1; + + /* Solve the system H * y = g */ + /* x += m_v[j] * m_y[j] */ + for (std::size_t i = last_k + 1; i-- > 0;) + { + double tmp = m_g[i]; + for (std::size_t j = i + 1; j <= last_k; j++) + tmp -= m_ht[i][j] * m_y[j]; + m_y[i] = tmp / m_ht[i][i]; + } + + for (std::size_t i = 0; i <= last_k; i++) + vec_add_mult_scalar(n, x, m_v[i], m_y[i]); + + if (rho <= rho_delta) + break; + + } + return itr_used; + } + + private: + + //typedef typename plib::mat_cr_t<FT, SIZE>::index_type mattype; + + plib::parray<float_type, SIZE> residual; + plib::parray<float_type, SIZE> Ax; + + plib::parray<float_type, RESTART + 1> m_c; /* mr + 1 */ + plib::parray<float_type, RESTART + 1> m_g; /* mr + 1 */ + plib::parray<plib::parray<float_type, RESTART>, RESTART + 1> m_ht; /* (mr + 1), mr */ + plib::parray<float_type, RESTART + 1> m_s; /* mr + 1 */ + plib::parray<float_type, RESTART + 1> m_y; /* mr + 1 */ + + //plib::parray<float_type, SIZE> m_v[RESTART + 1]; /* mr + 1, n */ + plib::parray<plib::parray<float_type, storage_N>, RESTART + 1> m_v; /* mr + 1, n */ + + std::size_t m_size; + + bool m_use_more_precise_stop_condition; + + + }; + + +#if 0 + /* Example of a Chebyshev iteration solver. This one doesn't work yet, + * it needs to be extended for non-symmetric matrix operation and + * depends on spectral radius estimates - which we don't have. + * + * Left here as another example. + */ + + template <typename FT, int SIZE> + struct ch_t + { + public: + + typedef FT float_type; + // FIXME: dirty hack to make this compile + static constexpr const std::size_t storage_N = plib::sizeabs<FT, SIZE>::ABS(); + + // Maximum iterations before a restart ... + static constexpr const std::size_t restart_N = (storage_N > 0 ? 20 : 0); + + ch_t(std::size_t size) + : residual(size) + , Ax(size) + , m_size(size) + { + } + + std::size_t size() const { return (SIZE<=0) ? m_size : static_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) + { + /*------------------------------------------------------------------------- + * + * + *------------------------------------------------------------------------*/ + + ops.precondition(); + + const FT lmax = 20.0; + const FT lmin = 0.0001; + + const FT d = (lmax+lmin)/2.0; + const FT c = (lmax-lmin)/2.0; + FT alpha = 0; + FT beta = 0; + std::size_t itr_used = 0; + + plib::parray<FT, SIZE> x(size()); + plib::parray<FT, SIZE> p(size()); + + plib::vec_set(size(), x, x0); + + ops.calc_rhs(Ax, x); + vec_sub(size(), rhs, Ax, residual); + + FT rho_delta = accuracy * std::sqrt(static_cast<FT>(size())); + + rho_delta = 1e-9; + + for (int i = 0; i < iter_max; i++) + { + ops.solve_LU_inplace(residual); + if (i==0) + { + vec_set(size(), p, residual); + alpha = 2.0 / d; + } + else + { + beta = alpha * ( c / 2.0)*( c / 2.0); + alpha = 1.0 / (d - beta); + for (std::size_t k = 0; k < size(); k++) + p[k] = residual[k] + beta * p[k]; + } + plib::vec_add_mult_scalar(size(), p, alpha, x); + ops.calc_rhs(Ax, x); + plib::vec_sub(size(), rhs, Ax, residual); + FT rho = std::sqrt(plib::vec_mult2<FT>(size(), residual)); + if (rho < rho_delta) + break; + itr_used++; + } + return itr_used; + } + private: + + //typedef typename plib::mat_cr_t<FT, SIZE>::index_type mattype; + + plib::parray<float_type, SIZE> residual; + plib::parray<float_type, SIZE> Ax; + + std::size_t m_size; + + }; +#endif + +} // namespace plib + +#endif /* PLIB_GMRES_H_ */ diff --git a/src/lib/netlist/plib/mat_cr.h b/src/lib/netlist/plib/mat_cr.h new file mode 100644 index 00000000000..4cc027f0d8f --- /dev/null +++ b/src/lib/netlist/plib/mat_cr.h @@ -0,0 +1,530 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud +/* + * mat_cr.h + * + * Compressed row format matrices + * + */ + +#ifndef MAT_CR_H_ +#define MAT_CR_H_ + +#include "palloc.h" +#include "parray.h" +#include "pconfig.h" +#include "pomp.h" +#include "pstate.h" +#include "ptypes.h" +#include "putil.h" + +#include <algorithm> +#include <array> +#include <cmath> +#include <cstdlib> +#include <type_traits> +#include <vector> + +namespace plib +{ + + // FIXME: causes a crash with GMRES handler + // template<typename T, int N, typename C = std::size_t> + + template<typename T, int N, typename C = uint16_t> + struct matrix_compressed_rows_t + { + using index_type = C; + using value_type = T; + + COPYASSIGNMOVE(matrix_compressed_rows_t, default) + + enum constants_e + { + FILL_INFINITY = 9999999 + }; + + parray<index_type, N> diag; // diagonal index pointer n + parray<index_type, (N == 0) ? 0 : (N < 0 ? N - 1 : N + 1)> row_idx; // row index pointer n + 1 + parray<index_type, N < 0 ? -N * N : N *N> col_idx; // column index array nz_num, initially (n * n) + parray<value_type, N < 0 ? -N * N : N *N> A; // Matrix elements nz_num, initially (n * n) + //parray<C, N < 0 ? -N * (N-1) / 2 : N * (N+1) / 2 > nzbd; // Support for gaussian elimination + parray<std::vector<index_type>, N > nzbd; // Support for gaussian elimination + // contains elimination rows below the diagonal + // FIXME: convert to pvector + std::vector<std::vector<index_type>> m_ge_par; + + index_type nz_num; + + explicit matrix_compressed_rows_t(const index_type n) + : diag(n) + , row_idx(n+1) + , col_idx(n*n) + , A(n*n) + //, nzbd(n * (n+1) / 2) + , nzbd(n) + , nz_num(0) + , m_size(n) + { + for (index_type i=0; i<n+1; i++) + row_idx[i] = 0; + } + + ~matrix_compressed_rows_t() = default; + + constexpr index_type size() const { return static_cast<index_type>((N>0) ? N : m_size); } + + void clear() + { + nz_num = 0; + for (index_type i=0; i < size() + 1; i++) + row_idx[i] = 0; + } + + void set_scalar(const T scalar) + { + for (index_type i=0, e=nz_num; i<e; i++) + A[i] = scalar; + } + + void set(C r, C c, T val) + { + C ri = row_idx[r]; + while (ri < row_idx[r+1] && col_idx[ri] < c) + ri++; + // we have the position now; + if (ri < row_idx[r+1] && col_idx[ri] == c) + A[ri] = val; + else + { + for (C i = nz_num; i>ri; i--) + { + A[i] = A[i-1]; + col_idx[i] = col_idx[i-1]; + } + A[ri] = val; + col_idx[ri] = c; + for (C i = r + 1; i < size() + 1; i++) + row_idx[i]++; + nz_num++; + if (c==r) + diag[r] = ri; + } + } + + template <typename M> + std::pair<std::size_t, std::size_t> gaussian_extend_fill_mat(M &fill) + { + std::size_t ops = 0; + std::size_t fill_max = 0; + + for (std::size_t k = 0; k < fill.size(); k++) + { + ops++; // 1/A(k,k) + for (std::size_t row = k + 1; row < fill.size(); row++) + { + if (fill[row][k] < FILL_INFINITY) + { + ops++; + for (std::size_t col = k + 1; col < fill[row].size(); col++) + //if (fill[k][col] < FILL_INFINITY) + { + auto f = std::min(fill[row][col], 1 + fill[row][k] + fill[k][col]); + if (f < FILL_INFINITY) + { + if (f > fill_max) + fill_max = f; + ops += 2; + } + fill[row][col] = f; + } + } + } + } + build_parallel_gaussian_execution_scheme(fill); + return { fill_max, ops }; + } + + template <typename M> + void build_from_fill_mat(const M &f, std::size_t max_fill = FILL_INFINITY - 1, + std::size_t band_width = FILL_INFINITY) + { + C nz = 0; + if (nz_num != 0) + throw pexception("build_from_mat only allowed on empty CR matrix"); + for (std::size_t k=0; k < size(); k++) + { + row_idx[k] = nz; + + for (std::size_t j=0; j < size(); j++) + if (f[k][j] <= max_fill && std::abs(static_cast<int>(k)-static_cast<int>(j)) <= static_cast<int>(band_width)) + { + col_idx[nz] = static_cast<C>(j); + if (j == k) + diag[k] = nz; + nz++; + } + } + + row_idx[size()] = nz; + nz_num = nz; + /* build nzbd */ + + for (std::size_t k=0; k < size(); k++) + { + 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(0); // end of sequence + } + } + + template <typename V> + void gaussian_elimination(V & RHS) + { + const std::size_t iN = size(); + + for (std::size_t i = 0; i < iN - 1; i++) + { + std::size_t nzbdp = 0; + std::size_t pi = diag[i]; + const value_type f = 1.0 / A[pi++]; + const std::size_t piie = row_idx[i+1]; + const auto &nz = nzbd[i]; + + while (auto j = nz[nzbdp++]) + { + // proceed to column i + + std::size_t pj = row_idx[j]; + + while (col_idx[pj] < i) + pj++; + + const value_type f1 = - A[pj++] * f; + + // subtract row i from j + // fill-in available assumed, i.e. matrix was prepared + + for (std::size_t pii = pi; pii<piie; pii++) + { + while (col_idx[pj] < col_idx[pii]) + pj++; + if (col_idx[pj] == col_idx[pii]) + A[pj++] += A[pii] * f1; + } + + RHS[j] += f1 * RHS[i]; + } + } + } + + template <typename V> + void gaussian_elimination_parallel(V & RHS) + { + // FIXME: move into solver creation ... + plib::omp::set_num_threads(4); + for (auto l = 0ul; l < m_ge_par.size(); l++) + plib::omp::for_static(0ul, m_ge_par[l].size(), [this, &RHS, &l] (unsigned ll) + { + auto &i = m_ge_par[l][ll]; + { + std::size_t nzbdp = 0; + std::size_t pi = diag[i]; + const value_type f = 1.0 / A[pi++]; + const std::size_t piie = row_idx[i+1]; + + while (auto j = nzbd[i][nzbdp++]) + { + // proceed to column i + + std::size_t pj = row_idx[j]; + + while (col_idx[pj] < i) + pj++; + + const value_type f1 = - A[pj++] * f; + + // subtract row i from j + // fill-in available assumed, i.e. matrix was prepared + for (std::size_t pii = pi; pii<piie; pii++) + { + while (col_idx[pj] < col_idx[pii]) + pj++; + if (col_idx[pj] == col_idx[pii]) + A[pj++] += A[pii] * f1; + } + RHS[j] += f1 * RHS[i]; + } + } + }); + } + + template <typename V1, typename V2> + void gaussian_back_substitution(V1 &V, const V2 &RHS) + { + const std::size_t iN = size(); + /* row n-1 */ + V[iN - 1] = RHS[iN - 1] / A[diag[iN - 1]]; + + for (std::size_t j = iN - 1; j-- > 0;) + { + value_type tmp = 0; + const auto jdiag = diag[j]; + const std::size_t e = row_idx[j+1]; + for (std::size_t pk = jdiag + 1; pk < e; pk++) + tmp += A[pk] * V[col_idx[pk]]; + V[j] = (RHS[j] - tmp) / A[jdiag]; + } + } + + template <typename V1> + void gaussian_back_substitution(V1 &V) + { + const std::size_t iN = size(); + /* row n-1 */ + V[iN - 1] = V[iN - 1] / A[diag[iN - 1]]; + + for (std::size_t j = iN - 1; j-- > 0;) + { + value_type tmp = 0; + const auto jdiag = diag[j]; + const std::size_t e = row_idx[j+1]; + for (std::size_t pk = jdiag + 1; pk < e; pk++) + tmp += A[pk] * V[col_idx[pk]]; + V[j] = (V[j] - tmp) / A[jdiag]; + } + } + + + template <typename VTV, typename VTR> + void mult_vec(VTR & res, const VTV & x) + { + /* + * res = A * x + */ + + std::size_t row = 0; + std::size_t k = 0; + const std::size_t oe = nz_num; + + while (k < oe) + { + T tmp = 0.0; + const std::size_t e = row_idx[row+1]; + for (; k < e; k++) + tmp += A[k] * x[col_idx[k]]; + res[row++] = tmp; + } + } + + /* throws error if P(source)>P(destination) */ + template <typename LUMAT> + void slim_copy_from(LUMAT & src) + { + for (std::size_t r=0; r<src.size(); r++) + { + C dp = row_idx[r]; + for (C sp = src.row_idx[r]; sp < src.row_idx[r+1]; sp++) + { + /* advance dp to source column and fill 0s if necessary */ + while (col_idx[dp] < src.col_idx[sp]) + A[dp++] = 0; + if (row_idx[r+1] <= dp || col_idx[dp] != src.col_idx[sp]) + throw plib::pexception("slim_copy_from error"); + A[dp++] = src.A[sp]; + } + /* fill remaining elements in row */ + while (dp < row_idx[r+1]) + A[dp++] = 0; + } + } + + /* only copies common elements */ + template <typename LUMAT> + void reduction_copy_from(LUMAT & src) + { + C sp = 0; + for (std::size_t r=0; r<src.size(); r++) + { + C dp = row_idx[r]; + while(sp < src.row_idx[r+1]) + { + /* advance dp to source column and fill 0s if necessary */ + if (col_idx[dp] < src.col_idx[sp]) + A[dp++] = 0; + else if (col_idx[dp] == src.col_idx[sp]) + A[dp++] = src.A[sp++]; + else + sp++; + } + /* fill remaining elements in row */ + while (dp < row_idx[r+1]) + A[dp++] = 0; + } + } + + /* checks at all - may crash */ + template <typename LUMAT> + void raw_copy_from(LUMAT & src) + { + for (std::size_t k = 0; k < nz_num; k++) + A[k] = src.A[k]; + } + + void incomplete_LU_factorization() + { + /* + * incomplete LU Factorization according to http://de.wikipedia.org/wiki/ILU-Zerlegung + * + * Result is stored in matrix LU + * + * For i = 1,...,N-1 + * For k = 0, ... , i - 1 + * If a[i,k] != 0 + * a[i,k] = a[i,k] / a[k,k] + * For j = k + 1, ... , N - 1 + * If a[i,j] != 0 + * a[i,j] = a[i,j] - a[i,k] * a[k,j] + * j=j+1 + * k=k+1 + * i=i+1 + * + */ + + for (std::size_t i = 1; i < size(); i++) // row i + { + const std::size_t p_i_end = row_idx[i + 1]; + // loop over all columns k left of diag in row i + for (std::size_t i_k = row_idx[i]; i_k < diag[i]; i_k++) + { + const std::size_t k = col_idx[i_k]; + const std::size_t p_k_end = row_idx[k + 1]; + const T LUp_i_k = A[i_k] = A[i_k] / A[diag[k]]; + + std::size_t k_j = diag[k] + 1; + std::size_t i_j = i_k + 1; + + while (i_j < p_i_end && k_j < p_k_end ) // pj = (i, j) + { + // we can assume that within a row ja increases continuously */ + const std::size_t c_i_j = col_idx[i_j]; // row i, column j + const std::size_t c_k_j = col_idx[k_j]; // row i, column j + if (c_k_j < c_i_j) + k_j++; + else if (c_k_j == c_i_j) + A[i_j++] -= LUp_i_k * A[k_j++]; + else + i_j++; + } + } + } + } + + template <typename R> + void solveLUx (R &r) + { + /* + * Solve a linear equation Ax = r + * where + * A = L*U + * + * L unit lower triangular + * U upper triangular + * + * ==> LUx = r + * + * ==> Ux = L⁻¹ r = w + * + * ==> r = Lw + * + * This can be solved for w using backwards elimination in L. + * + * Now Ux = w + * + * This can be solved for x using backwards elimination in U. + * + */ + for (std::size_t i = 1; i < size(); ++i ) + { + T tmp = 0.0; + const std::size_t j1 = row_idx[i]; + const std::size_t j2 = diag[i]; + + for (std::size_t j = j1; j < j2; ++j ) + tmp += A[j] * r[col_idx[j]]; + r[i] -= tmp; + } + // i now is equal to n; + for (std::size_t i = size(); i-- > 0; ) + { + T tmp = 0.0; + const std::size_t di = diag[i]; + const std::size_t j2 = row_idx[i+1]; + for (std::size_t j = di + 1; j < j2; j++ ) + tmp += A[j] * r[col_idx[j]]; + r[i] = (r[i] - tmp) / A[di]; + } + } + private: + template <typename M> + void build_parallel_gaussian_execution_scheme(const M &fill) + { + // calculate parallel scheme for gaussian elimination + std::vector<std::vector<index_type>> rt(size()); + for (index_type k = 0; k < size(); k++) + { + for (index_type j = k+1; j < size(); j++) + { + if (fill[j][k] < FILL_INFINITY) + { + rt[k].push_back(j); + } + } + } + + std::vector<index_type> levGE(size(), 0); + index_type cl = 0; + + for (index_type k = 0; k < size(); k++ ) + { + if (levGE[k] >= cl) + { + std::vector<index_type> t = rt[k]; + for (index_type j = k+1; j < size(); j++ ) + { + bool overlap = false; + // is there overlap + if (plib::container::contains(t, j)) + overlap = true; + for (auto &x : rt[j]) + if (plib::container::contains(t, x)) + { + overlap = true; + break; + } + if (overlap) + levGE[j] = cl + 1; + else + { + t.push_back(j); + for (auto &x : rt[j]) + t.push_back(x); + } + } + cl++; + } + } + + m_ge_par.clear(); + m_ge_par.resize(cl+1); + for (index_type k = 0; k < size(); k++) + m_ge_par[levGE[k]].push_back(k); + } + + index_type m_size; + }; + +} // namespace plib + +#endif /* MAT_CR_H_ */ diff --git a/src/lib/netlist/plib/palloc.cpp b/src/lib/netlist/plib/palloc.cpp deleted file mode 100644 index e4d31985b23..00000000000 --- a/src/lib/netlist/plib/palloc.cpp +++ /dev/null @@ -1,105 +0,0 @@ -// license:GPL-2.0+ -// copyright-holders:Couriersud -/* - * palloc.c - * - */ - -#include "pconfig.h" -#include "palloc.h" -#include "pfmtlog.h" - -#include <algorithm> - -namespace plib { - -//============================================================ -// Memory pool -//============================================================ - -mempool::mempool(size_t min_alloc, size_t min_align) -: m_min_alloc(min_alloc), m_min_align(min_align) -{ -} -mempool::~mempool() -{ - for (auto & b : m_blocks) - { - if (b.m_num_alloc != 0) - { - fprintf(stderr, "Found block with %d dangling allocations\n", static_cast<int>(b.m_num_alloc)); - } - ::operator delete(b.data); - } - m_blocks.clear(); -} - -size_t mempool::new_block() -{ - block b; - b.data = static_cast<char *>(::operator new(m_min_alloc)); - b.cur_ptr = b.data; - b.m_free = m_min_alloc; - b.m_num_alloc = 0; - m_blocks.push_back(b); - return m_blocks.size() - 1; -} - -size_t mempool::mininfosize() -{ - size_t sinfo = sizeof(mempool::info); -#ifdef __APPLE__ - size_t ma = 16; -#else - size_t ma = 8; -#endif - return ((std::max(m_min_align, sinfo) + ma - 1) / ma) * ma; -} - -void *mempool::alloc(size_t size) -{ - size_t rs = (size + mininfosize() + m_min_align - 1) & ~(m_min_align - 1); - for (size_t bn=0; bn < m_blocks.size(); bn++) - { - auto &b = m_blocks[bn]; - if (b.m_free > rs) - { - b.m_free -= rs; - b.m_num_alloc++; - auto i = reinterpret_cast<info *>(b.cur_ptr); - i->m_block = bn; - auto ret = reinterpret_cast<void *>(b.cur_ptr + mininfosize()); - b.cur_ptr += rs; - return ret; - } - } - { - size_t bn = new_block(); - auto &b = m_blocks[bn]; - b.m_num_alloc = 1; - b.m_free = m_min_alloc - rs; - auto i = reinterpret_cast<info *>(b.cur_ptr); - i->m_block = bn; - auto ret = reinterpret_cast<void *>(b.cur_ptr + mininfosize()); - b.cur_ptr += rs; - return ret; - } -} - -void mempool::free(void *ptr) -{ - auto p = reinterpret_cast<char *>(ptr); - - auto i = reinterpret_cast<info *>(p - mininfosize()); - block *b = &m_blocks[i->m_block]; - if (b->m_num_alloc == 0) - fprintf(stderr, "Argh .. double free\n"); - else - { - //b->m_free = m_min_alloc; - //b->cur_ptr = b->data; - } - b->m_num_alloc--; -} - -} diff --git a/src/lib/netlist/plib/palloc.h b/src/lib/netlist/plib/palloc.h index a35bc50ff17..15fede3a99b 100644 --- a/src/lib/netlist/plib/palloc.h +++ b/src/lib/netlist/plib/palloc.h @@ -8,172 +8,427 @@ #ifndef PALLOC_H_ #define PALLOC_H_ +#include "pconfig.h" #include "pstring.h" +#include "ptypes.h" -#include <vector> +#include <cstddef> +#include <cstdlib> #include <memory> +#include <type_traits> +#include <utility> +#include <vector> + +#if defined(_WIN32) || defined(_WIN64) || defined(_MSC_VER) +#include <malloc.h> +#endif namespace plib { -//============================================================ -// Memory allocation -//============================================================ - -template<typename T, typename... Args> -T *palloc(Args&&... args) -{ - return new T(std::forward<Args>(args)...); -} - -template<typename T> -void pfree(T *ptr) -{ - delete ptr; -} - -template<typename T> -T* palloc_array(const std::size_t num) -{ - return new T[num](); -} - -template<typename T> -void pfree_array(T *ptr) -{ - delete [] ptr; -} - -template<typename T, typename... Args> -std::unique_ptr<T> make_unique(Args&&... args) -{ - return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); -} - -template<typename BC, typename DC, typename... Args> -static std::unique_ptr<BC> make_unique_base(Args&&... args) -{ - std::unique_ptr<BC> ret(new DC(std::forward<Args>(args)...)); - return ret; -} - -template <typename SC> -class owned_ptr -{ -private: - owned_ptr() - : m_ptr(nullptr), m_is_owned(true) { } -public: - owned_ptr(SC *p, bool owned) noexcept - : m_ptr(p), m_is_owned(owned) - { } - - owned_ptr(const owned_ptr &r) = delete; - owned_ptr & operator =(owned_ptr &r) = delete; - - template<typename DC> - owned_ptr & operator =(owned_ptr<DC> &&r) + //============================================================ + // Standard arena_deleter + //============================================================ + + template <typename P, typename T> + struct arena_deleter + { + //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) + { + unused_var(y); + return x; + } + + constexpr arena_deleter(arena_storage_type a = arena_storage_type()) noexcept + : m_a(a) { } + + 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) { } + + void operator()(T *p) //const + { + /* call destructor */ + p->~T(); + getref(m_a).deallocate(p); + } + //private: + arena_storage_type m_a; + }; + + //============================================================ + // owned_ptr: smart pointer with ownership information + //============================================================ + + template <typename SC, typename D> + class owned_ptr + { + public: + + using pointer = SC *; + using element_type = SC; + using deleter_type = D; + + owned_ptr() + : m_ptr(nullptr), m_deleter(), m_is_owned(true) { } + + template <typename, typename> + friend class owned_ptr; + + owned_ptr(pointer p, bool owned) noexcept + : m_ptr(p), m_deleter(), m_is_owned(owned) + { } + + owned_ptr(pointer p, bool owned, D deleter) noexcept + : m_ptr(p), m_deleter(deleter), m_is_owned(owned) + { } + + + owned_ptr(const owned_ptr &r) = delete; + owned_ptr & operator =(owned_ptr &r) = delete; + + template<typename DC, typename DC_D> + owned_ptr & operator =(owned_ptr<DC, DC_D> &&r) + { + if (m_is_owned && (m_ptr != nullptr)) + //delete m_ptr; + m_deleter(m_ptr); + m_is_owned = r.m_is_owned; + m_ptr = r.m_ptr; + m_deleter = r.m_deleter; + r.m_is_owned = false; + r.m_ptr = nullptr; + return *this; + } + + owned_ptr(owned_ptr &&r) noexcept + : m_ptr(r.m_ptr) + , m_deleter(r.m_deleter) + , m_is_owned(r.m_is_owned) + { + r.m_is_owned = false; + r.m_ptr = nullptr; + } + + owned_ptr &operator=(owned_ptr &&r) noexcept + { + if (m_is_owned && (m_ptr != nullptr)) + //delete m_ptr; + m_deleter(m_ptr); + m_is_owned = r.m_is_owned; + m_ptr = r.m_ptr; + m_deleter = std::move(r.m_deleter); + r.m_is_owned = false; + r.m_ptr = nullptr; + return *this; + } + + template<typename DC, typename DC_D> + owned_ptr(owned_ptr<DC, DC_D> &&r) noexcept + : m_ptr(static_cast<pointer >(r.get())) + , m_deleter(r.m_deleter) + , m_is_owned(r.is_owned()) + { + r.release(); + } + + ~owned_ptr() noexcept + { + if (m_is_owned && (m_ptr != nullptr)) + { + //delete m_ptr; + m_deleter(m_ptr); + } + m_is_owned = false; + m_ptr = nullptr; + } + + /** + * \brief Return @c true if the stored pointer is not null. + */ + explicit operator bool() const noexcept { return m_ptr != nullptr; } + + pointer release() + { + pointer tmp = m_ptr; + m_is_owned = false; + m_ptr = nullptr; + return tmp; + } + + bool is_owned() const { return m_is_owned; } + + pointer operator ->() const noexcept { return m_ptr; } + typename std::add_lvalue_reference<element_type>::type operator *() const noexcept { return *m_ptr; } + pointer get() const noexcept { return m_ptr; } + + deleter_type& get_deleter() noexcept { return m_deleter; } + const deleter_type& get_deleter() const noexcept { return m_deleter; } + + private: + pointer m_ptr; + D m_deleter; + bool m_is_owned; + }; + + //============================================================ + // Arena allocator for use with containers + //============================================================ + + template <class ARENA, class T, std::size_t ALIGN = alignof(T)> + class arena_allocator { - if (m_is_owned && (m_ptr != nullptr)) - delete m_ptr; - m_is_owned = r.m_is_owned; - m_ptr = r.m_ptr; - r.m_is_owned = false; - r.m_ptr = nullptr; - return *this; + public: + using value_type = 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, + "ALIGN must be greater than alignof(T) and a multiple"); + + arena_allocator() noexcept + : m_a(arena_type::instance()) + { } + + ~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 + : m_a(rhs.m_a) + { + } + + template <class U> struct rebind + { + using other = arena_allocator<ARENA, U, ALIGN>; + }; + + T* allocate(std::size_t n) + { + return reinterpret_cast<T *>(m_a.allocate(ALIGN, sizeof(T) * n)); + } + + void deallocate(T* p, std::size_t n) noexcept + { + unused_var(n); + m_a.deallocate(p); + } + + template <class AR1, class T1, std::size_t A1, class AR2, class T2, std::size_t A2> + friend bool operator==(const arena_allocator<AR1, T1, A1>& lhs, + const arena_allocator<AR2, T2, A2>& rhs) noexcept; + + template <class AU, class U, std::size_t A> friend class arena_allocator; + private: + arena_type &m_a; + }; + + template <class AR1, class T1, std::size_t A1, class AR2, class T2, std::size_t A2> + inline bool operator==(const arena_allocator<AR1, T1, A1>& lhs, + const arena_allocator<AR2, T2, A2>& rhs) noexcept + { + return A1 == A2 && rhs.m_a == lhs.m_a; + } + template <class AR1, class T1, std::size_t A1, class AR2, class T2, std::size_t A2> + inline bool operator!=(const arena_allocator<AR1, T1, A1>& lhs, + const arena_allocator<AR2, T2, A2>& rhs) noexcept + { + return !(lhs == rhs); } - owned_ptr(owned_ptr &&r) noexcept + //============================================================ + // Memory allocation + //============================================================ + + struct aligned_arena { - m_is_owned = r.m_is_owned; - m_ptr = r.m_ptr; - r.m_is_owned = false; - r.m_ptr = nullptr; + static constexpr const bool is_stateless = true; + template <class T, std::size_t ALIGN = alignof(T)> + using allocator_type = arena_allocator<aligned_arena, T, ALIGN>; + + template <typename T> + using owned_pool_ptr = plib::owned_ptr<T, arena_deleter<aligned_arena, T>>; + + static inline aligned_arena &instance() + { + static aligned_arena s_arena; + return s_arena; + } + + static inline void *allocate( size_t alignment, size_t size ) + { + #if (USE_ALIGNED_ALLOCATION) + #if defined(_WIN32) || defined(_WIN64) || defined(_MSC_VER) + return _aligned_malloc(size, alignment); + #elif defined(__APPLE__) + void* p; + if (::posix_memalign(&p, alignment, size) != 0) { + p = nullptr; + } + return p; + #else + return aligned_alloc(alignment, size); + #endif + #else + unused_var(alignment); + return ::operator new(size); + #endif + } + + static inline void deallocate( void *ptr ) + { + #if (USE_ALIGNED_ALLOCATION) + // NOLINTNEXTLINE(cppcoreguidelines-no-malloc) + free(ptr); + #else + ::operator delete(ptr); + #endif + } + + template<typename T, typename... Args> + owned_pool_ptr<T> make_poolptr(Args&&... args) + { + auto *mem = allocate(alignof(T), sizeof(T)); + return owned_pool_ptr<T>(new (mem) T(std::forward<Args>(args)...), true, arena_deleter<aligned_arena, T>(*this)); + } + + }; + + template <typename T, std::size_t ALIGN> + /*inline */ C14CONSTEXPR T *assume_aligned_ptr(T *p) noexcept + { + 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"); + //auto t = reinterpret_cast<std::uintptr_t>(p); + //if (t & (ALIGN-1)) + // printf("alignment error!"); +#if (USE_ALIGNED_HINTS) + return reinterpret_cast<T *>(__builtin_assume_aligned(p, ALIGN)); +#else + return p; +#endif } - template<typename DC> - owned_ptr(owned_ptr<DC> &&r) noexcept + template <typename T, std::size_t ALIGN> + constexpr const T *assume_aligned_ptr(const T *p) noexcept { - m_ptr = static_cast<SC *>(r.get()); - m_is_owned = r.is_owned(); - r.release(); + 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 (USE_ALIGNED_HINTS) + return reinterpret_cast<const T *>(__builtin_assume_aligned(p, ALIGN)); +#else + return p; +#endif } - ~owned_ptr() + // FIXME: remove + template<typename T, typename... Args> + inline T *pnew(Args&&... args) { - if (m_is_owned && (m_ptr != nullptr)) - delete m_ptr; - m_is_owned = false; - m_ptr = nullptr; + auto *p = aligned_arena::allocate(alignof(T), sizeof(T)); + return new(p) T(std::forward<Args>(args)...); } - template<typename DC, typename... Args> - static owned_ptr Create(Args&&... args) + + template<typename T> + inline void pdelete(T *ptr) { - owned_ptr a; - DC *x = new DC(std::forward<Args>(args)...); - a.m_ptr = static_cast<SC *>(x); - return std::move(a); + ptr->~T(); + aligned_arena::deallocate(ptr); } - template<typename... Args> - static owned_ptr Create(Args&&... args) + + template <typename T> + using unique_ptr = std::unique_ptr<T, arena_deleter<aligned_arena, T>>; + + template<typename T, typename... Args> + plib::unique_ptr<T> make_unique(Args&&... args) { - owned_ptr a; - a.m_ptr = new SC(std::forward<Args>(args)...); - return std::move(a); + return plib::unique_ptr<T>(pnew<T>(std::forward<Args>(args)...)); } - SC * release() + +#if 0 + template<typename T, typename... Args> + static owned_ptr<T> make_owned(Args&&... args) { - SC *tmp = m_ptr; - m_is_owned = false; - m_ptr = nullptr; - return tmp; + return owned_ptr<T>(pnew<T>(std::forward<Args>(args)...), true); } +#endif + - bool is_owned() const { return m_is_owned; } + template <class T, std::size_t ALIGN = alignof(T)> + using aligned_allocator = aligned_arena::allocator_type<T, ALIGN>; - SC * operator ->() const { return m_ptr; } - SC & operator *() const { return *m_ptr; } - SC * get() const { return m_ptr; } -private: - SC *m_ptr; - bool m_is_owned; -}; + //============================================================ + // traits to determine alignment size and stride size + // from types supporting alignment + //============================================================ -class mempool -{ -private: - struct block + PDEFINE_HAS_MEMBER(has_align, align_size); + + template <typename T, typename X = void> + struct align_traits { - block() : m_num_alloc(0), m_free(0), cur_ptr(nullptr), data(nullptr) { } - std::size_t m_num_alloc; - std::size_t m_free; - char *cur_ptr; - char *data; + 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; }; - size_t new_block(); - size_t mininfosize(); - - struct info + template <typename T> + struct align_traits<T, typename std::enable_if<has_align<T>::value, void>::type> { - info() : m_block(0) { } - size_t m_block; + 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; }; - size_t m_min_alloc; - size_t m_min_align; + //============================================================ + // Aligned vector + //============================================================ - std::vector<block> m_blocks; + // FIXME: needs a separate file + template <class T, std::size_t ALIGN = alignof(T)> + class aligned_vector : public std::vector<T, aligned_allocator<T, ALIGN>> + { + public: + using base = std::vector<T, aligned_allocator<T, ALIGN>>; + + 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; -public: - mempool(size_t min_alloc, size_t min_align); - ~mempool(); + using base::base; - void *alloc(size_t size); - void free(void *ptr); + C14CONSTEXPR 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 #endif /* PALLOC_H_ */ diff --git a/src/lib/netlist/plib/parray.h b/src/lib/netlist/plib/parray.h new file mode 100644 index 00000000000..1be37b908cd --- /dev/null +++ b/src/lib/netlist/plib/parray.h @@ -0,0 +1,126 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud +/* + * parray.h + * + */ + +#ifndef PARRAY_H_ +#define PARRAY_H_ + +#include "palloc.h" +#include "pconfig.h" +#include "pexception.h" + +#include <array> +#include <memory> +#include <type_traits> +#include <utility> +#include <vector> + +namespace plib { + + template <typename FT, int SIZE> + struct sizeabs + { + static constexpr std::size_t ABS() { return (SIZE < 0) ? static_cast<std::size_t>(0 - SIZE) : static_cast<std::size_t>(SIZE); } + using container = typename std::array<FT, ABS()> ; + }; + + template <typename FT> + struct sizeabs<FT, 0> + { + static constexpr const std::size_t ABS = 0; + using container = typename std::vector<FT, aligned_allocator<FT, PALIGN_VECTOROPT>>; + }; + + /** + * \brief Array with preallocated or dynamic allocation + * + * Passing SIZE > 0 has the same functionality as a std::array. + * SIZE = 0 is pure dynamic allocation, the actual array size is passed to the + * constructor. + * SIZE < 0 reserves std::abs(SIZE) elements statically in place allocated. The + * actual size is passed in by the constructor. + * This array is purely intended for HPC application where depending on the + * architecture a preference dynamic/static has to be made. + * + * This struct is not intended to be a full replacement to std::array. + * It is a subset to enable switching between dynamic and static allocation. + * I consider > 10% performance difference to be a use case. + */ + + template <typename FT, int SIZE> + struct parray + { + public: + static constexpr std::size_t SIZEABS() { return sizeabs<FT, SIZE>::ABS(); } + + using base_type = typename sizeabs<FT, SIZE>::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; + + template <int X = SIZE > + parray(size_type size, typename std::enable_if<X==0, int>::type = 0) + : m_a(size), m_size(size) + { + } + +#if 1 + /* allow construction in fixed size arrays */ + template <int X = SIZE > + parray(typename std::enable_if<(X > 0), int>::type = 0) + : m_size(X) + { + } +#endif + template <int X = SIZE > + parray(size_type size, typename std::enable_if<X!=0, int>::type = 0) + : m_size(size) + { + if (SIZE < 0 && size > SIZEABS()) + throw plib::pexception("parray: size error " + plib::to_string(size) + ">" + plib::to_string(SIZEABS())); + else if (SIZE > 0 && size != SIZEABS()) + throw plib::pexception("parray: size error"); + } + + inline size_type size() const noexcept { return SIZE <= 0 ? m_size : SIZEABS(); } + + constexpr size_type max_size() const noexcept { return base_type::max_size(); } + + bool empty() const noexcept { return size() == 0; } + +#if 0 + reference operator[](size_type i) /*noexcept*/ + { + if (i >= m_size) throw plib::pexception("limits error " + to_string(i) + ">=" + to_string(m_size)); + return m_a[i]; + } + const_reference operator[](size_type i) const /*noexcept*/ + { + if (i >= m_size) throw plib::pexception("limits error " + to_string(i) + ">=" + to_string(m_size)); + return m_a[i]; + } +#else + C14CONSTEXPR reference operator[](size_type i) noexcept + { + return assume_aligned_ptr<FT, PALIGN_VECTOROPT>(&m_a[0])[i]; + } + constexpr const_reference operator[](size_type i) const noexcept + { + return assume_aligned_ptr<FT, PALIGN_VECTOROPT>(&m_a[0])[i]; + } +#endif + 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()); } + + private: + PALIGNAS_VECTOROPT() + base_type m_a; + size_type m_size; + }; +} // namespace plib + +#endif /* PARRAY_H_ */ diff --git a/src/lib/netlist/plib/pchrono.cpp b/src/lib/netlist/plib/pchrono.cpp index 971d19b3645..953d948e062 100644 --- a/src/lib/netlist/plib/pchrono.cpp +++ b/src/lib/netlist/plib/pchrono.cpp @@ -49,5 +49,5 @@ exact_ticks::type exact_ticks::per_second() #endif -} -} +} // namespace chrono +} // namespace plib diff --git a/src/lib/netlist/plib/pchrono.h b/src/lib/netlist/plib/pchrono.h index a229128e7b8..8ce0eca23b3 100644 --- a/src/lib/netlist/plib/pchrono.h +++ b/src/lib/netlist/plib/pchrono.h @@ -9,16 +9,17 @@ #define PCHRONO_H_ #include "pconfig.h" +#include "ptypes.h" -#include <cstdint> #include <chrono> +#include <cstdint> namespace plib { namespace chrono { template <typename T> struct sys_ticks { - typedef typename T::rep type; + 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; } @@ -145,7 +146,7 @@ namespace chrono { struct counter { counter() : m_count(0) { } - typedef uint_least64_t type; + using type = uint_least64_t; type operator()() const { return m_count; } void inc() { ++m_count; } void reset() { m_count = 0; } @@ -157,7 +158,7 @@ namespace chrono { template<> struct counter<false> { - typedef uint_least64_t type; + using type = uint_least64_t; constexpr type operator()() const { return 0; } void inc() const { } void reset() const { } @@ -168,15 +169,28 @@ namespace chrono { template< typename T, bool enabled_ = true> struct timer { - typedef typename T::type type; - typedef uint_least64_t ctype; + 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 start() { m_time -= T::start(); } - void stop() { m_time += T::stop(); ++m_count; } 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; } @@ -185,7 +199,7 @@ namespace chrono { double as_seconds() const { return static_cast<double>(total()) / static_cast<double>(T::per_second()); } - constexpr static bool enabled = enabled_; + guard_t guard() { return guard_t(*this); } private: type m_time; ctype m_count; @@ -194,19 +208,31 @@ namespace chrono { template<typename T> struct timer<T, false> { - typedef typename T::type type; - typedef uint_least64_t ctype; + 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 start() const { } - void stop() const { } 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 } // namespace plib diff --git a/src/lib/netlist/plib/pconfig.h b/src/lib/netlist/plib/pconfig.h index 0200c305ecd..d66b342f815 100644 --- a/src/lib/netlist/plib/pconfig.h +++ b/src/lib/netlist/plib/pconfig.h @@ -21,18 +21,46 @@ * if PHAS_RDTSCP == 1 */ #ifndef PUSE_ACCURATE_STATS -#define PUSE_ACCURATE_STATS (1) +#define PUSE_ACCURATE_STATS (0) #endif /* * Set this to one if you want to use 128 bit int for ptime. - * This is for tests only. + * This is about 5% slower on a kaby lake processor. */ #ifndef PHAS_INT128 #define PHAS_INT128 (0) #endif +/* + * Set this to one if you want to use aligned storage optimizations. + */ + +#ifndef USE_ALIGNED_OPTIMIZATIONS +#define USE_ALIGNED_OPTIMIZATIONS (0) +#endif + +#define USE_ALIGNED_ALLOCATION (USE_ALIGNED_OPTIMIZATIONS) +#define USE_ALIGNED_HINTS (USE_ALIGNED_OPTIMIZATIONS) +/* + * Standard alignment macros + */ + +#define PALIGN_CACHELINE (64) +#define PALIGN_VECTOROPT (64) + +#define PALIGNAS_CACHELINE() PALIGNAS(PALIGN_CACHELINE) +#define PALIGNAS_VECTOROPT() PALIGNAS(PALIGN_VECTOROPT) + +/* Breaks mame build on windows due to -Wattribute + * FIXME: no error on cross-compile - need further checks */ +#if defined(_WIN32) && defined(__GNUC__) +#define PALIGNAS(x) +#else +#define PALIGNAS(x) alignas(x) +#endif + /*============================================================ * Check for CPP Version * @@ -47,6 +75,13 @@ * *============================================================*/ +#ifndef NVCCBUILD +#define NVCCBUILD (0) +#endif + +#if NVCCBUILD +#define C14CONSTEXPR +#else #if __cplusplus == 201103L #define C14CONSTEXPR #elif __cplusplus == 201402L @@ -58,6 +93,7 @@ #else #error "C++ version not supported" #endif +#endif #ifndef PHAS_INT128 #define PHAS_INT128 (0) @@ -68,17 +104,6 @@ typedef __uint128_t UINT128; typedef __int128_t INT128; #endif -#if defined(__GNUC__) -#ifdef RESTRICT -#undef RESTRICT -#endif -#define RESTRICT __restrict__ -#define ATTR_UNUSED __attribute__((__unused__)) -#else -#define RESTRICT -#define ATTR_UNUSED -#endif - //============================================================ // Standard defines //============================================================ diff --git a/src/lib/netlist/plib/pdynlib.cpp b/src/lib/netlist/plib/pdynlib.cpp index 13827eaf24c..0d32bead51d 100644 --- a/src/lib/netlist/plib/pdynlib.cpp +++ b/src/lib/netlist/plib/pdynlib.cpp @@ -25,7 +25,7 @@ CHAR *astring_from_utf8(const char *utf8string) // convert UTF-16 to "ANSI code page" string char_count = WideCharToMultiByte(CP_ACP, 0, wstring, -1, nullptr, 0, nullptr, nullptr); - result = palloc_array<CHAR>(char_count); + result = new CHAR[char_count]; if (result != nullptr) WideCharToMultiByte(CP_ACP, 0, wstring, -1, result, char_count, nullptr, nullptr); @@ -39,7 +39,7 @@ WCHAR *wstring_from_utf8(const char *utf8string) // convert MAME string (UTF-8) to UTF-16 char_count = MultiByteToWideChar(CP_UTF8, 0, utf8string, -1, nullptr, 0); - result = palloc_array<WCHAR>(char_count); + result = new WCHAR[char_count]; if (result != nullptr) MultiByteToWideChar(CP_UTF8, 0, utf8string, -1, result, char_count); @@ -58,7 +58,7 @@ WCHAR *wstring_from_utf8(const char *utf8string) #endif namespace plib { -dynlib::dynlib(const pstring libname) +dynlib::dynlib(const pstring &libname) : m_isLoaded(false), m_lib(nullptr) { #ifdef _WIN32 @@ -72,7 +72,7 @@ dynlib::dynlib(const pstring libname) m_isLoaded = true; //else // fprintf(stderr, "win: library <%s> not found!\n", libname.c_str()); - pfree_array(buffer); + delete [] buffer; #elif defined(EMSCRIPTEN) //no-op #else @@ -88,9 +88,11 @@ dynlib::dynlib(const pstring libname) #endif } -dynlib::dynlib(const pstring path, const pstring libname) +dynlib::dynlib(const pstring &path, const pstring &libname) : m_isLoaded(false), m_lib(nullptr) { + // FIXME: implement path search + plib::unused_var(path); // printf("win: loading <%s>\n", libname.c_str()); #ifdef _WIN32 TCHAR *buffer = tstring_from_utf8(libname.c_str()); @@ -104,7 +106,7 @@ dynlib::dynlib(const pstring path, const pstring libname) { //printf("win: library <%s> not found!\n", libname.c_str()); } - pfree_array(buffer); + delete [] buffer; #elif defined(EMSCRIPTEN) //no-op #else @@ -139,7 +141,7 @@ bool dynlib::isLoaded() const return m_isLoaded; } -void *dynlib::getsym_p(const pstring name) +void *dynlib::getsym_p(const pstring &name) { #ifdef _WIN32 return (void *) GetProcAddress((HMODULE) m_lib, name.c_str()); @@ -148,4 +150,4 @@ void *dynlib::getsym_p(const pstring name) #endif } -} +} // namespace plib diff --git a/src/lib/netlist/plib/pdynlib.h b/src/lib/netlist/plib/pdynlib.h index 7c9412593c9..1454c053298 100644 --- a/src/lib/netlist/plib/pdynlib.h +++ b/src/lib/netlist/plib/pdynlib.h @@ -8,28 +8,31 @@ #define PDYNLIB_H_ #include "pstring.h" +#include "ptypes.h" namespace plib { // ---------------------------------------------------------------------------------------- // pdynlib: dynamic loading of libraries ... // ---------------------------------------------------------------------------------------- -class dynlib +class dynlib : public nocopyassignmove { public: - explicit dynlib(const pstring libname); - dynlib(const pstring path, const pstring libname); + explicit dynlib(const pstring &libname); + dynlib(const pstring &path, const pstring &libname); + ~dynlib(); + COPYASSIGNMOVE(dynlib, delete) bool isLoaded() const; template <typename T> - T getsym(const pstring name) + T getsym(const pstring &name) { return reinterpret_cast<T>(getsym_p(name)); } private: - void *getsym_p(const pstring name); + void *getsym_p(const pstring &name); bool m_isLoaded; void *m_lib; @@ -64,6 +67,6 @@ private: calltype m_sym; }; -} +} // namespace plib #endif /* PSTRING_H_ */ diff --git a/src/lib/netlist/plib/pexception.cpp b/src/lib/netlist/plib/pexception.cpp index a4ed8f367e0..8d6907d66f2 100644 --- a/src/lib/netlist/plib/pexception.cpp +++ b/src/lib/netlist/plib/pexception.cpp @@ -9,6 +9,7 @@ #include "pfmtlog.h" #include <cfenv> +#include <iostream> #if (defined(__x86_64__) || defined(__i386__)) && defined(__linux__) #define HAS_FEENABLE_EXCEPT (1) @@ -17,127 +18,113 @@ #endif namespace plib { -//============================================================ -// Exceptions -//============================================================ - -pexception::pexception(const pstring &text) -: m_text(text) -{ -} - -pexception::~pexception() noexcept -{ -} - -file_e::file_e(const pstring &fmt, const pstring &filename) - : pexception(pfmt(fmt)(filename)) -{ -} - -file_e::~file_e() noexcept -{ -} - -file_open_e::file_open_e(const pstring &filename) - : file_e("File open failed: {}", filename) -{ -} - -file_open_e::~file_open_e() noexcept -{ - -} - -file_read_e::file_read_e(const pstring &filename) - : file_e("File read failed: {}", filename) -{ -} - -file_read_e::~file_read_e() noexcept -{ - -} - -file_write_e::file_write_e(const pstring &filename) - : file_e("File write failed: {}", filename) -{ -} - -file_write_e::~file_write_e() noexcept -{ -} - -null_argument_e::null_argument_e(const pstring &argument) - : pexception(pfmt("Null argument passed: {}")(argument)) -{ -} - -null_argument_e::~null_argument_e() noexcept -{ -} - -out_of_mem_e::out_of_mem_e(const pstring &location) - : pexception(pfmt("Out of memory: {}")(location)) -{ -} - -out_of_mem_e::~out_of_mem_e() noexcept -{ -} - -fpexception_e::fpexception_e(const pstring &text) - : pexception(pfmt("Out of memory: {}")(text)) -{ -} - -fpexception_e::~fpexception_e() noexcept -{ -} - -bool fpsignalenabler::m_enable = false; - -fpsignalenabler::fpsignalenabler(unsigned fpexceptions) -{ -#if HAS_FEENABLE_EXCEPT - if (m_enable) + + //============================================================ + // terminate + //============================================================ + + void terminate(const pstring &msg) noexcept { - int b = 0; - if (fpexceptions & plib::FP_INEXACT) b = b | FE_INEXACT; - if (fpexceptions & plib::FP_DIVBYZERO) b = b | FE_DIVBYZERO; - if (fpexceptions & plib::FP_UNDERFLOW) b = b | FE_UNDERFLOW; - if (fpexceptions & plib::FP_OVERFLOW) b = b | FE_OVERFLOW; - if (fpexceptions & plib::FP_INVALID) b = b | FE_INVALID; - m_last_enabled = feenableexcept(b); + std::cerr << msg.c_str() << "\n"; + std::terminate(); } -#else - m_last_enabled = 0; -#endif -} -fpsignalenabler::~fpsignalenabler() -{ -#if HAS_FEENABLE_EXCEPT - if (m_enable) + //============================================================ + // Exceptions + //============================================================ + + pexception::pexception(const pstring &text) + : m_text(text) + { + } + + + file_e::file_e(const pstring &fmt, const pstring &filename) + : pexception(pfmt(fmt)(filename)) + { + } + + + file_open_e::file_open_e(const pstring &filename) + : file_e("File open failed: {}", filename) + { + } + + + file_read_e::file_read_e(const pstring &filename) + : file_e("File read failed: {}", filename) { - fedisableexcept(FE_ALL_EXCEPT); // Enable all floating point exceptions but FE_INEXACT - feenableexcept(m_last_enabled); // Enable all floating point exceptions but FE_INEXACT } -#endif -} -bool fpsignalenabler::supported() -{ - return true; -} -bool fpsignalenabler::global_enable(bool enable) -{ - bool old = m_enable; - m_enable = enable; - return old; -} + file_write_e::file_write_e(const pstring &filename) + : file_e("File write failed: {}", filename) + { + } + + + null_argument_e::null_argument_e(const pstring &argument) + : pexception(pfmt("Null argument passed: {}")(argument)) + { + } + + + out_of_mem_e::out_of_mem_e(const pstring &location) + : pexception(pfmt("Out of memory: {}")(location)) + { + } + + + fpexception_e::fpexception_e(const pstring &text) + : pexception(pfmt("Out of memory: {}")(text)) + { + } + + + bool fpsignalenabler::m_enable = false; + + fpsignalenabler::fpsignalenabler(unsigned fpexceptions) + { + #if HAS_FEENABLE_EXCEPT + if (m_enable) + { + int b = 0; + if (fpexceptions & plib::FP_INEXACT) b = b | FE_INEXACT; + if (fpexceptions & plib::FP_DIVBYZERO) b = b | FE_DIVBYZERO; + if (fpexceptions & plib::FP_UNDERFLOW) b = b | FE_UNDERFLOW; + if (fpexceptions & plib::FP_OVERFLOW) b = b | FE_OVERFLOW; + if (fpexceptions & plib::FP_INVALID) b = b | FE_INVALID; + m_last_enabled = feenableexcept(b); + } + #else + m_last_enabled = 0; + #endif + } + + + fpsignalenabler::~fpsignalenabler() + { + #if HAS_FEENABLE_EXCEPT + if (m_enable) + { + fedisableexcept(FE_ALL_EXCEPT); // Enable all floating point exceptions but FE_INEXACT + feenableexcept(m_last_enabled); // Enable all floating point exceptions but FE_INEXACT + } + #endif + } + + bool fpsignalenabler::supported() + { + return true; + } + + bool fpsignalenabler::global_enable(bool enable) + { + bool old = m_enable; + m_enable = enable; + return old; + } -} +} // namespace plib diff --git a/src/lib/netlist/plib/pexception.h b/src/lib/netlist/plib/pexception.h index 4827081b754..28a3ac1adf1 100644 --- a/src/lib/netlist/plib/pexception.h +++ b/src/lib/netlist/plib/pexception.h @@ -9,118 +9,116 @@ #define PEXCEPTION_H_ #include "pstring.h" +#include "ptypes.h" #include <exception> namespace plib { -//============================================================ -// exception base -//============================================================ - -class pexception : public std::exception -{ -public: - explicit pexception(const pstring &text); - pexception(const pexception &e) : std::exception(e), m_text(e.m_text) { } - - virtual ~pexception() noexcept; - - const pstring &text() { return m_text; } - const char* what() const noexcept override { return m_text.c_str(); } - -private: - pstring m_text; -}; - -class file_e : public plib::pexception -{ -public: - file_e(const pstring &fmt, const pstring &filename); - file_e(const file_e &e) : pexception(e) { } - virtual ~file_e() noexcept; -}; - -class file_open_e : public file_e -{ -public: - explicit file_open_e(const pstring &filename); - file_open_e(const file_open_e &e) : file_e(e) { } - virtual ~file_open_e() noexcept; -}; - -class file_read_e : public file_e -{ -public: - explicit file_read_e(const pstring &filename); - file_read_e(const file_read_e &e) : file_e(e) { } - virtual ~file_read_e() noexcept; -}; - -class file_write_e : public file_e -{ -public: - explicit file_write_e(const pstring &filename); - file_write_e(const file_write_e &e) : file_e(e) { } - virtual ~file_write_e() noexcept; -}; - -class null_argument_e : public plib::pexception -{ -public: - explicit null_argument_e(const pstring &argument); - null_argument_e(const null_argument_e &e) : pexception(e) { } - virtual ~null_argument_e() noexcept; -}; - -class out_of_mem_e : public plib::pexception -{ -public: - explicit out_of_mem_e(const pstring &location); - out_of_mem_e(const out_of_mem_e &e) : pexception(e) { } - virtual ~out_of_mem_e() noexcept; -}; - -/* FIXME: currently only a stub for later use. More use could be added by - * using “-fnon-call-exceptions" and sigaction to enable c++ exception supported. - */ - -class fpexception_e : public pexception -{ -public: - explicit fpexception_e(const pstring &text); - fpexception_e(const fpexception_e &e) : pexception(e) { } - virtual ~fpexception_e() noexcept; -}; - -static constexpr unsigned FP_INEXACT = 0x0001; -static constexpr unsigned FP_DIVBYZERO = 0x0002; -static constexpr unsigned FP_UNDERFLOW = 0x0004; -static constexpr unsigned FP_OVERFLOW = 0x0008; -static constexpr unsigned FP_INVALID = 0x00010; -static constexpr unsigned FP_ALL = 0x0001f; - -/* - * Catch SIGFPE on linux for debugging purposes. - */ - -class fpsignalenabler -{ -public: - explicit fpsignalenabler(unsigned fpexceptions); - ~fpsignalenabler(); - - /* is the functionality supported ? */ - static bool supported(); - /* returns last global enable state */ - static bool global_enable(bool enable); - -private: - int m_last_enabled; - - static bool m_enable; -}; - -} + //============================================================ + // terminate + //============================================================ + + /*! Terminate the program + * + * \note could be enhanced by setting a termination handler + */ + [[noreturn]] void terminate(const pstring &msg) noexcept; + + //============================================================ + // exception base + //============================================================ + + class pexception : public std::exception + { + public: + explicit pexception(const pstring &text); + + const pstring &text() { return m_text; } + const char* what() const noexcept override { return m_text.c_str(); } + + private: + pstring m_text; + }; + + class file_e : public plib::pexception + { + public: + file_e(const pstring &fmt, const pstring &filename); + }; + + class file_open_e : public file_e + { + public: + explicit file_open_e(const pstring &filename); + }; + + class file_read_e : public file_e + { + public: + explicit file_read_e(const pstring &filename); + }; + + class file_write_e : public file_e + { + public: + explicit file_write_e(const pstring &filename); + }; + + class null_argument_e : public plib::pexception + { + public: + explicit null_argument_e(const pstring &argument); + }; + + class out_of_mem_e : public plib::pexception + { + public: + explicit out_of_mem_e(const pstring &location); + }; + + /* FIXME: currently only a stub for later use. More use could be added by + * using “-fnon-call-exceptions" and sigaction to enable c++ exception supported. + */ + + class fpexception_e : public pexception + { + public: + explicit fpexception_e(const pstring &text); + }; + + static constexpr unsigned FP_INEXACT = 0x0001; + static constexpr unsigned FP_DIVBYZERO = 0x0002; + static constexpr unsigned FP_UNDERFLOW = 0x0004; + static constexpr unsigned FP_OVERFLOW = 0x0008; + static constexpr unsigned FP_INVALID = 0x00010; + static constexpr unsigned FP_ALL = 0x0001f; + + /* + * Catch SIGFPE on linux for debugging purposes. + */ + + class fpsignalenabler + { + public: + explicit fpsignalenabler(unsigned fpexceptions); + + COPYASSIGNMOVE(fpsignalenabler, delete) + + ~fpsignalenabler(); + + /* is the functionality supported ? */ + static bool supported(); + /* returns last global enable state */ + static bool global_enable(bool enable); + + private: + int m_last_enabled; + + static bool m_enable; + }; + + +} // namespace plib #endif /* PEXCEPTION_H_ */ diff --git a/src/lib/netlist/plib/pfmtlog.cpp b/src/lib/netlist/plib/pfmtlog.cpp index b8b5fcb3b91..af87251fbdf 100644 --- a/src/lib/netlist/plib/pfmtlog.cpp +++ b/src/lib/netlist/plib/pfmtlog.cpp @@ -8,83 +8,96 @@ #include "pfmtlog.h" #include "palloc.h" -#include <cstring> -#include <cstdlib> -#include <cstdarg> #include <algorithm> -#include <locale> +#include <array> +#include <cstdarg> +#include <cstdio> +#include <cstdlib> +#include <cstring> #include <iostream> +#include <locale> namespace plib { pfmt &pfmt::format_element(const char *l, const unsigned cfmt_spec, ...) { va_list ap; - va_start(ap, cfmt_spec); - pstring fmt("%"); - char buf[2048]; // FIXME + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg) + std::array<char, 2048> buf; std::size_t sl; + bool found_abs = false; m_arg++; - pstring search("{"); - search += plib::to_string(m_arg); - sl = search.length(); + do { + pstring fmt("%"); + va_start(ap, cfmt_spec); + found_abs = false; + buf[0] = 0; + pstring search("{"); + search += plib::to_string(m_arg); + sl = search.size(); - auto p = m_str.find(search + ":"); - sl++; // ":" - if (p == pstring::npos) // no further specifiers - { - p = m_str.find(search + "}"); - if (p == pstring::npos) // not found try default - { - sl = 2; - p = m_str.find("{}"); - } - if (p == pstring::npos) + auto p = m_str.find(search + ":"); + sl++; // ":" + if (p == pstring::npos) // no further specifiers { - sl=1; - p = m_str.find("{"); - if (p != pstring:: npos) + p = m_str.find(search + "}"); + if (p == pstring::npos) // not found try default { - auto p1 = m_str.find("}", p); - if (p1 != pstring::npos) + sl = 2; + p = m_str.find("{}"); + } + else + // found absolute positional place holder + found_abs = true; + if (p == pstring::npos) + { + sl=2; + p = m_str.find("{:"); + if (p != pstring:: npos) { - sl = p1 - p + 1; - fmt += m_str.substr(p+1, p1 - p - 1); + auto p1 = m_str.find("}", p); + if (p1 != pstring::npos) + { + sl = p1 - p + 1; + fmt += m_str.substr(p+1, p1 - p - 1); + } } } } - } - else - { - auto p1 = m_str.find("}", p); - if (p1 != pstring::npos) + else + { + // found absolute positional place holder + auto p1 = m_str.find("}", p); + if (p1 != pstring::npos) + { + sl = p1 - p + 1; + fmt += ((m_arg>=10) ? m_str.substr(p+4, p1 - p - 4) : m_str.substr(p+3, p1 - p - 3)); + found_abs = true; + } + } + pstring::value_type pend = fmt.at(fmt.size() - 1); + if (pstring("duxo").find(cfmt_spec) != pstring::npos) { - sl = p1 - p + 1; - fmt += ((m_arg>=10) ? m_str.substr(p+4, p1 - p - 4) : m_str.substr(p+3, p1 - p - 3)); + if (pstring("duxo").find(pend) == pstring::npos) + fmt += (pstring(l) + static_cast<pstring::value_type>(cfmt_spec)); + else + fmt = plib::left(fmt, fmt.size() - 1) + pstring(l) + plib::right(fmt, 1); + } + else if (pstring("fge").find(cfmt_spec) != pstring::npos) + { + if (pstring("fge").find(pend) == pstring::npos) + fmt += cfmt_spec; } - } - pstring::code_t pend = fmt.at(fmt.length() - 1); - if (pstring("duxo").find(cfmt_spec) != pstring::npos) - { - if (pstring("duxo").find(pend) == pstring::npos) - fmt += (pstring(l, pstring::UTF8) + cfmt_spec); else - fmt = fmt.left(fmt.length() - 1) + pstring(l, pstring::UTF8) + fmt.right(1); - } - else if (pstring("fge").find(cfmt_spec) != pstring::npos) - { - if (pstring("fge").find(pend) == pstring::npos) fmt += cfmt_spec; - } - else - fmt += cfmt_spec; - vsprintf(buf, fmt.c_str(), ap); - if (p != pstring::npos) - m_str = m_str.substr(0, p) + pstring(buf, pstring::UTF8) + m_str.substr(p + sl); - va_end(ap); + std::vsnprintf(buf.data(), buf.size(), fmt.c_str(), ap); + if (p != pstring::npos) + m_str = m_str.substr(0, p) + pstring(buf.data()) + m_str.substr(p + sl); + va_end(ap); + } while (found_abs); return *this; } -} +} // namespace plib diff --git a/src/lib/netlist/plib/pfmtlog.h b/src/lib/netlist/plib/pfmtlog.h index 9b7a85d8d8d..cb9b59c01ce 100644 --- a/src/lib/netlist/plib/pfmtlog.h +++ b/src/lib/netlist/plib/pfmtlog.h @@ -9,6 +9,7 @@ #include "pstring.h" #include "ptypes.h" +#include "putil.h" #include <limits> @@ -34,7 +35,6 @@ struct ptype_traits_base template <> struct ptype_traits_base<bool> { - static unsigned int cast(bool &x) { return static_cast<unsigned int>(x); } static unsigned int cast(const bool &x) { return static_cast<unsigned int>(x); } static const bool is_signed = std::numeric_limits<bool>::is_signed; static const char *size_spec() { return ""; } @@ -136,7 +136,6 @@ struct ptype_traits<double> : ptype_traits_base<double> static char32_t fmt_spec() { return 'f'; } }; - template<> struct ptype_traits<char *> : ptype_traits_base<char *> { @@ -144,6 +143,13 @@ struct ptype_traits<char *> : ptype_traits_base<char *> static char32_t fmt_spec() { return 's'; } }; +template<> +struct ptype_traits<std::string> : ptype_traits_base<char *> +{ + static const char *cast(const std::string &x) { return x.c_str(); } + static char32_t fmt_spec() { return 's'; } +}; + class pfmt { public: @@ -151,44 +157,57 @@ public: : m_str(fmt), m_arg(0) { } + COPYASSIGNMOVE(pfmt, default) - pfmt(const pfmt &rhs) : m_str(rhs.m_str), m_arg(rhs.m_arg) { } - - ~pfmt() - { - } + ~pfmt() noexcept = default; operator pstring() const { return m_str; } + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg) pfmt & e(const double &x) {return format_element("", 'e', x); } + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg) pfmt & g(const double &x) {return format_element("", 'g', x); } + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg) pfmt & e(const float &x) {return format_element("", 'e', static_cast<double>(x)); } + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg) pfmt & g(const float &x) {return format_element("", 'g', static_cast<double>(x)); } + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg) pfmt &operator ()(const void *x) {return format_element("", 'p', x); } + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg) pfmt &operator ()(const pstring &x) {return format_element("", 's', x.c_str() ); } template<typename T> pfmt &operator ()(const T &x) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg) return format_element(ptype_traits<T>::size_spec(), ptype_traits<T>::fmt_spec(), ptype_traits<T>::cast(x)); } template<typename T> pfmt &operator ()(const T *x) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg) return format_element(ptype_traits<T *>::size_spec(), ptype_traits<T *>::fmt_spec(), ptype_traits<T *>::cast(x)); } + template<typename X, typename Y, typename... Args> + pfmt &operator()(X&& x, Y && y, Args&&... args) + { + return ((*this)(std::forward<X>(x)))(std::forward<Y>(y), std::forward<Args>(args)...); + } + template<typename T> pfmt &x(const T &x) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg) return format_element(ptype_traits<T>::size_spec(), 'x', x); } template<typename T> pfmt &o(const T &x) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg) return format_element(ptype_traits<T>::size_spec(), 'o', x); } @@ -203,11 +222,13 @@ private: }; template <class T, bool build_enabled = true> -class pfmt_writer_t : plib::nocopyassignmove +class pfmt_writer_t { public: explicit pfmt_writer_t() : m_enabled(true) { } + COPYASSIGNMOVE(pfmt_writer_t, delete) + /* runtime enable */ template<bool enabled, typename... Args> void log(const pstring & fmt, Args&&... args) const @@ -237,7 +258,7 @@ public: bool is_enabled() const { return m_enabled; } protected: - ~pfmt_writer_t() { } + ~pfmt_writer_t() noexcept = default; private: pfmt &xlog(pfmt &fmt) const { return fmt; } @@ -258,7 +279,10 @@ class plog_channel : public pfmt_writer_t<plog_channel<T, L, build_enabled>, bui friend class pfmt_writer_t<plog_channel<T, L, build_enabled>, build_enabled>; public: explicit plog_channel(T &b) : pfmt_writer_t<plog_channel, build_enabled>(), m_base(b) { } - ~plog_channel() { } + + COPYASSIGNMOVE(plog_channel, delete) + + ~plog_channel() noexcept = default; protected: void vdowrite(const pstring &ls) const @@ -283,7 +307,9 @@ public: error(proxy), fatal(proxy) {} - virtual ~plog_base() {} + + COPYASSIGNMOVE(plog_base, default) + virtual ~plog_base() noexcept = default; plog_channel<T, plog_level::DEBUG, debug_enabled> debug; plog_channel<T, plog_level::INFO> info; @@ -293,7 +319,7 @@ public: plog_channel<T, plog_level::FATAL> fatal; }; -} +} // namespace plib template<typename T> plib::pfmt& operator<<(plib::pfmt &p, T&& val) { return p(std::forward<T>(val)); } diff --git a/src/lib/netlist/plib/pfunction.cpp b/src/lib/netlist/plib/pfunction.cpp index 79f09cb4a46..6a2179e0e6f 100644 --- a/src/lib/netlist/plib/pfunction.cpp +++ b/src/lib/netlist/plib/pfunction.cpp @@ -6,9 +6,9 @@ */ #include "pfunction.h" +#include "pexception.h" #include "pfmtlog.h" #include "putil.h" -#include "pexception.h" #include <cmath> #include <stack> @@ -17,7 +17,7 @@ namespace plib { void pfunction::compile(const std::vector<pstring> &inputs, const pstring &expr) { - if (expr.startsWith("rpn:")) + if (plib::startsWith(expr, "rpn:")) compile_postfix(inputs, expr.substr(4)); else compile_infix(inputs, expr); @@ -56,7 +56,7 @@ void pfunction::compile_postfix(const std::vector<pstring> &inputs, { rc.m_cmd = RAND; stk += 1; } else { - for (unsigned i = 0; i < inputs.size(); i++) + for (std::size_t i = 0; i < inputs.size(); i++) { if (inputs[i] == cmd) { @@ -68,9 +68,9 @@ void pfunction::compile_postfix(const std::vector<pstring> &inputs, } if (rc.m_cmd != PUSH_INPUT) { - bool err = false; rc.m_cmd = PUSH_CONST; - rc.m_param = cmd.as_double(&err); + bool err; + rc.m_param = plib::pstonum_ne<decltype(rc.m_param)>(cmd, err); if (err) throw plib::pexception(plib::pfmt("nld_function: unknown/misformatted token <{1}> in <{2}>")(cmd)(expr)); stk += 1; @@ -84,11 +84,11 @@ void pfunction::compile_postfix(const std::vector<pstring> &inputs, throw plib::pexception(plib::pfmt("nld_function: stack count different to one on <{2}>")(expr)); } -static int get_prio(pstring v) +static int get_prio(const pstring &v) { if (v == "(" || v == ")") return 1; - else if (v.left(1) >= "a" && v.left(1) <= "z") + else if (plib::left(v, 1) >= "a" && plib::left(v, 1) <= "z") return 0; else if (v == "*" || v == "/") return 20; @@ -113,12 +113,11 @@ void pfunction::compile_infix(const std::vector<pstring> &inputs, const pstring { // Shunting-yard infix parsing std::vector<pstring> sep = {"(", ")", ",", "*", "/", "+", "-", "^"}; - std::vector<pstring> sexpr(plib::psplit(expr.replace_all(" ",""), sep)); + std::vector<pstring> sexpr(plib::psplit(plib::replace_all(expr, pstring(" "), pstring("")), sep)); std::stack<pstring> opstk; std::vector<pstring> postfix; - //printf("dbg: %s\n", expr.c_str()); - for (unsigned i = 0; i < sexpr.size(); i++) + for (std::size_t i = 0; i < sexpr.size(); i++) { pstring &s = sexpr[i]; if (s=="(") @@ -182,14 +181,15 @@ void pfunction::compile_infix(const std::vector<pstring> &inputs, const pstring #define OP(OP, ADJ, EXPR) \ case OP: \ - ptr-=ADJ; \ - stack[ptr-1] = EXPR; \ + ptr-= (ADJ); \ + stack[ptr-1] = (EXPR); \ break; double pfunction::evaluate(const std::vector<double> &values) { - double stack[20]; + std::array<double, 20> stack = { 0 }; unsigned ptr = 0; + stack[0] = 0.0; for (auto &rc : m_precompiled) { switch (rc.m_cmd) @@ -199,8 +199,8 @@ double pfunction::evaluate(const std::vector<double> &values) OP(SUB, 1, ST2 - ST1) OP(DIV, 1, ST2 / ST1) OP(POW, 1, std::pow(ST2, ST1)) - OP(SIN, 0, std::sin(ST2)); - OP(COS, 0, std::cos(ST2)); + OP(SIN, 0, std::sin(ST2)) + OP(COS, 0, std::cos(ST2)) case RAND: stack[ptr++] = lfsr_random(); break; @@ -215,4 +215,4 @@ double pfunction::evaluate(const std::vector<double> &values) return stack[ptr-1]; } -} +} // namespace plib diff --git a/src/lib/netlist/plib/pfunction.h b/src/lib/netlist/plib/pfunction.h index 7d5984f9d15..fbb6c508333 100644 --- a/src/lib/netlist/plib/pfunction.h +++ b/src/lib/netlist/plib/pfunction.h @@ -8,8 +8,8 @@ #ifndef PFUNCTION_H_ #define PFUNCTION_H_ -#include "pstring.h" #include "pstate.h" +#include "pstring.h" #include <vector> @@ -112,6 +112,6 @@ namespace plib { }; -} +} // namespace plib #endif /* PEXCEPTION_H_ */ diff --git a/src/lib/netlist/plib/plists.h b/src/lib/netlist/plib/plists.h index 5fefa658b83..c2fee9c2f8e 100644 --- a/src/lib/netlist/plib/plists.h +++ b/src/lib/netlist/plib/plists.h @@ -12,6 +12,8 @@ #include "pstring.h" +#include <array> +#include <type_traits> #include <vector> namespace plib { @@ -29,14 +31,13 @@ class uninitialised_array_t { public: - typedef C* iterator; - typedef const C* const_iterator; + using iterator = C *; + using const_iterator = const C *; - uninitialised_array_t() - { - } + uninitialised_array_t() noexcept = default; - ~uninitialised_array_t() + COPYASSIGNMOVE(uninitialised_array_t, delete) + ~uninitialised_array_t() noexcept { for (std::size_t i=0; i<N; i++) (*this)[i].~C(); @@ -51,7 +52,7 @@ public: const C& operator[](const std::size_t &index) const noexcept { - return *reinterpret_cast<C *>(&m_buf[index]); + return *reinterpret_cast<const C *>(&m_buf[index]); } template<typename... Args> @@ -75,7 +76,8 @@ protected: private: /* ensure proper alignment */ - typename std::aligned_storage<sizeof(C), alignof(C)>::type m_buf[N]; + PALIGNAS_VECTOROPT() + std::array<typename std::aligned_storage<sizeof(C), alignof(C)>::type, N> m_buf; }; // ---------------------------------------------------------------------------------------- @@ -83,6 +85,7 @@ private: // the list allows insertions / deletions if used properly // ---------------------------------------------------------------------------------------- +#if 0 template <class LC> class linkedlist_t { @@ -152,9 +155,10 @@ public: void remove(const LC *elem) noexcept { auto p = &m_head; - for ( ; *p != elem; p = &((*p)->m_next)) + while(*p != elem) { //nl_assert(*p != nullptr); + p = &((*p)->m_next); } (*p) = elem->m_next; } @@ -166,7 +170,105 @@ public: private: LC *m_head; }; +#else +template <class LC> +class linkedlist_t +{ +public: + + struct element_t + { + public: + + friend class linkedlist_t<LC>; + + constexpr element_t() : m_next(nullptr), m_prev(nullptr) {} + ~element_t() noexcept = default; + + 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 { iter_t t(rhs); std::swap(*this, t); 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;} + }; + + 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 + { + if (m_head) + m_head->m_prev = elem; + elem->m_next = m_head; + elem->m_prev = nullptr; + 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; } + void clear() noexcept { m_head = nullptr; } + constexpr bool empty() const noexcept { return (m_head == nullptr); } + +private: + LC *m_head; +}; +#endif +} // namespace plib #endif /* PLISTS_H_ */ diff --git a/src/lib/netlist/plib/pmain.cpp b/src/lib/netlist/plib/pmain.cpp index 93c4076bac2..b381d96dca7 100644 --- a/src/lib/netlist/plib/pmain.cpp +++ b/src/lib/netlist/plib/pmain.cpp @@ -23,7 +23,7 @@ namespace plib { char *buf = new char[dst_char_count + 1]; WideCharToMultiByte(CP_UTF8, 0, w, wlen, buf, dst_char_count, nullptr, nullptr); buf[dst_char_count] = 0; - auto ret = pstring(buf, pstring::UTF8); + auto ret = pstring(buf); delete [] buf; return ret; } @@ -37,18 +37,13 @@ namespace plib { : options() , pout_strm() , perr_strm() - , pout(pout_strm) - , perr(perr_strm) + , pout(&pout_strm) + , perr(&perr_strm) { } - app::~app() - { - - } - - int app::main_utfX(int argc, char *argv[]) + int app::main_utfX(int argc, char **argv) { auto r = this->parse(argc, argv); int ret = 0; diff --git a/src/lib/netlist/plib/pmain.h b/src/lib/netlist/plib/pmain.h index e2f84b90de6..4f4be779251 100644 --- a/src/lib/netlist/plib/pmain.h +++ b/src/lib/netlist/plib/pmain.h @@ -10,20 +10,21 @@ #ifndef PMAIN_H_ #define PMAIN_H_ +#include "palloc.h" #include "poptions.h" +#include "pstream.h" #include "pstring.h" #include "putil.h" -#include "pstream.h" -#include <memory> #include <cwchar> +#include <memory> #ifdef _WIN32 #define PMAIN(appclass) \ extern "C" int wmain(int argc, wchar_t *argv[]) { return plib::app::mainrun<appclass, wchar_t>(argc, argv); } #else #define PMAIN(appclass) \ -int main(int argc, char *argv[]) { return plib::app::mainrun<appclass, char>(argc, argv); } +int main(int argc, char **argv) { return plib::app::mainrun<appclass, char>(argc, argv); } #endif @@ -36,7 +37,10 @@ namespace plib { { public: app(); - virtual ~app(); + + COPYASSIGNMOVE(app, delete) + + virtual ~app() = default; virtual pstring usage() = 0; virtual int execute() = 0; @@ -48,21 +52,21 @@ namespace plib { plib::putf8_fmt_writer perr; template <class C, typename T> - static int mainrun(int argc, T *argv[]) + static int mainrun(int argc, T **argv) { - auto a = std::unique_ptr<C>(new C); + auto a = plib::make_unique<C>(); return a->main_utfX(argc, argv); } private: - int main_utfX(int argc, char *argv[]); + int main_utfX(int argc, char **argv); #ifdef _WIN32 int main_utfX(int argc, wchar_t *argv[]); #endif }; -} +} // namespace plib diff --git a/src/lib/netlist/plib/pmatrix2d.h b/src/lib/netlist/plib/pmatrix2d.h new file mode 100644 index 00000000000..eab533688d7 --- /dev/null +++ b/src/lib/netlist/plib/pmatrix2d.h @@ -0,0 +1,85 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud +/* + * pmatrix2d.h + * + * NxM regular matrix + * + */ + +#ifndef PMATRIX2D_H_ +#define PMATRIX2D_H_ + +#include "palloc.h" + +#include <algorithm> +#include <cmath> +#include <cstdlib> +#include <type_traits> +#include <vector> + +namespace plib +{ + + + template<typename T, typename A = aligned_allocator<T>> + class pmatrix2d + { + public: + using value_type = T; + using allocator_type = A; + + static constexpr const std::size_t align_size = align_traits<A>::align_size; + static constexpr const std::size_t stride_size = align_traits<A>::stride_size; + pmatrix2d() + : m_N(0), m_M(0), m_stride(8), m_v() + { + } + + pmatrix2d(std::size_t N, std::size_t M) + : m_N(N), m_M(M), m_v() + { + m_stride = ((M + stride_size-1) / stride_size) * stride_size; + m_v.resize(N * m_stride); + } + + void resize(std::size_t N, std::size_t M) + { + m_N = N; + m_M = M; + m_stride = ((M + stride_size-1) / stride_size) * stride_size; + m_v.resize(N * m_stride); + } + + C14CONSTEXPR T * operator[] (std::size_t row) noexcept + { + return assume_aligned_ptr<T, align_size>(&m_v[m_stride * row]); + } + + constexpr const T * operator[] (std::size_t row) const noexcept + { + return assume_aligned_ptr<T, align_size>(&m_v[m_stride * row]); + } + + T & operator()(std::size_t r, std::size_t c) noexcept + { + return (*this)[r][c]; + } + + const T & operator()(std::size_t r, std::size_t c) const noexcept + { + return (*this)[r][c]; + } + + private: + + std::size_t m_N; + std::size_t m_M; + std::size_t m_stride; + + std::vector<T, A> m_v; + }; + +} // namespace plib + +#endif /* MAT_CR_H_ */ diff --git a/src/lib/netlist/plib/pmempool.h b/src/lib/netlist/plib/pmempool.h new file mode 100644 index 00000000000..f55807c86dc --- /dev/null +++ b/src/lib/netlist/plib/pmempool.h @@ -0,0 +1,187 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud +/* + * pmempool.h + * + */ + +#ifndef PMEMPOOL_H_ +#define PMEMPOOL_H_ + +#include "palloc.h" +#include "pstream.h" +#include "pstring.h" +#include "ptypes.h" +#include "putil.h" + +#include <algorithm> +#include <cstddef> +#include <memory> +#include <unordered_map> +#include <utility> +#include <vector> + +namespace plib { + + //============================================================ + // Memory pool + //============================================================ + + class mempool + { + private: + struct block + { + block(mempool *mp, std::size_t min_bytes) + : m_num_alloc(0) + , m_cur(0) + , m_data(nullptr) + , m_mempool(mp) + { + min_bytes = std::max(mp->m_min_alloc, min_bytes); + m_free = min_bytes; + std::size_t alloc_bytes = (min_bytes + mp->m_min_align - 1) & ~(mp->m_min_align - 1); + m_data_allocated = static_cast<char *>(::operator new(alloc_bytes)); + void *r = m_data_allocated; + std::align(mp->m_min_align, min_bytes, r, alloc_bytes); + m_data = reinterpret_cast<char *>(r); + } + std::size_t m_num_alloc; + std::size_t m_free; + std::size_t m_cur; + char *m_data; + char *m_data_allocated; + mempool *m_mempool; + }; + + struct info + { + info(block *b, std::size_t p) : m_block(b), m_pos(p) { } + ~info() = default; + COPYASSIGNMOVE(info, default) + + block * m_block; + std::size_t m_pos; + }; + + + block * new_block(std::size_t min_bytes) + { + auto *b = plib::pnew<block>(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; + } + + size_t m_min_alloc; + size_t m_min_align; + + std::vector<block *> m_blocks; + + public: + static constexpr const bool is_stateless = false; + template <class T, std::size_t ALIGN = alignof(T)> + using allocator_type = arena_allocator<mempool, T, ALIGN>; + + mempool(size_t min_alloc = (1<<21), size_t min_align = 16) + : m_min_alloc(min_alloc), m_min_align(min_align) + { + } + + COPYASSIGNMOVE(mempool, delete) + + ~mempool() + { + + for (auto & b : m_blocks) + { + if (b->m_num_alloc != 0) + { + plib::perrlogger("Found {} info blocks\n", sinfo().size()); + plib::perrlogger("Found block with {} dangling allocations\n", b->m_num_alloc); + } + ::operator delete(b->m_data); + } + } + + void *allocate(size_t align, size_t size) + { + if (align < m_min_align) + align = m_min_align; + + size_t rs = size + align; + for (auto &b : m_blocks) + { + if (b->m_free > rs) + { + b->m_free -= rs; + b->m_num_alloc++; + auto *ret = reinterpret_cast<void *>(b->m_data + b->m_cur); + auto capacity(rs); + ret = std::align(align, size, ret, capacity); + // FIXME: if (ret == nullptr) + // printf("Oh no\n"); + sinfo().insert({ ret, info(b, b->m_cur)}); + rs -= (capacity - size); + b->m_cur += rs; + + return ret; + } + } + { + block *b = new_block(rs); + b->m_num_alloc = 1; + b->m_free = m_min_alloc - rs; + auto *ret = reinterpret_cast<void *>(b->m_data + b->m_cur); + auto capacity(rs); + ret = std::align(align, size, ret, capacity); + // FIXME: if (ret == nullptr) + // printf("Oh no\n"); + sinfo().insert({ ret, info(b, b->m_cur)}); + rs -= (capacity - size); + b->m_cur += rs; + return ret; + } + } + + static void deallocate(void *ptr) + { + + auto it = sinfo().find(ptr); + if (it == sinfo().end()) + plib::terminate("mempool::free - pointer not found\n"); + info i = it->second; + block *b = i.m_block; + if (b->m_num_alloc == 0) + plib::terminate("mempool::free - double free was called\n"); + else + { + //b->m_free = m_min_alloc; + //b->cur_ptr = b->data; + } + b->m_num_alloc--; + //printf("Freeing in block %p %lu\n", b, b->m_num_alloc); + sinfo().erase(it); + } + + template <typename T> + using owned_pool_ptr = plib::owned_ptr<T, arena_deleter<mempool, T>>; + + template<typename T, typename... Args> + owned_pool_ptr<T> make_poolptr(Args&&... args) + { + auto *mem = this->allocate(alignof(T), sizeof(T)); + return owned_pool_ptr<T>(new (mem) T(std::forward<Args>(args)...), true, arena_deleter<mempool, T>(this)); + } + + }; + +} // namespace plib + +#endif /* PMEMPOOL_H_ */ diff --git a/src/lib/netlist/plib/pomp.h b/src/lib/netlist/plib/pomp.h index 6559207f09d..f8a516df485 100644 --- a/src/lib/netlist/plib/pomp.h +++ b/src/lib/netlist/plib/pomp.h @@ -11,6 +11,8 @@ #include "pconfig.h" +#include <cstddef> + #if HAS_OPENMP #include "omp.h" #endif @@ -18,29 +20,39 @@ namespace plib { namespace omp { -template <class T> -void for_static(const int start, const int end, const T &what) +template <typename I, class T> +void for_static(const I start, const I end, const T &what) { #if HAS_OPENMP && USE_OPENMP #pragma omp parallel #endif { #if HAS_OPENMP && USE_OPENMP - #pragma omp for schedule(static) + #pragma omp for //schedule(static) #endif - for (int i = start; i < end; i++) + for (I i = start; i < end; i++) what(i); } } -inline void set_num_threads(const int threads) +template <typename I, class T> +void for_static_np(const I start, const I end, const T &what) +{ + for (I i = start; i < end; i++) + what(i); +} + + +inline void set_num_threads(const std::size_t threads) { #if HAS_OPENMP && USE_OPENMP omp_set_num_threads(threads); +#else + plib::unused_var(threads); #endif } -inline int get_max_threads() +inline std::size_t get_max_threads() { #if HAS_OPENMP && USE_OPENMP return omp_get_max_threads(); @@ -54,7 +66,7 @@ inline int get_max_threads() // pdynlib: dynamic loading of libraries ... // ---------------------------------------------------------------------------------------- -} -} +} // namespace omp +} // namespace plib #endif /* PSTRING_H_ */ diff --git a/src/lib/netlist/plib/poptions.cpp b/src/lib/netlist/plib/poptions.cpp index 910660acb3d..4a3d32c4723 100644 --- a/src/lib/netlist/plib/poptions.cpp +++ b/src/lib/netlist/plib/poptions.cpp @@ -6,77 +6,39 @@ */ #include "poptions.h" +#include "pexception.h" +#include "ptypes.h" namespace plib { /*************************************************************************** Options ***************************************************************************/ - option_base::option_base(options &parent, pstring help) + option_base::option_base(options &parent, const pstring &help) : m_help(help) { parent.register_option(this); } - option_base::~option_base() - { - } - - option_group::~option_group() - { - } - - option_example::~option_example() - { - } - - option::option(options &parent, pstring ashort, pstring along, pstring help, bool has_argument) + option::option(options &parent, const pstring &ashort, const pstring &along, const pstring &help, bool has_argument) : option_base(parent, help), m_short(ashort), m_long(along), m_has_argument(has_argument), m_specified(false) { } - option::~option() - { - } - int option_str::parse(const pstring &argument) { m_val = argument; return 0; } - int option_str_limit::parse(const pstring &argument) - { - if (plib::container::contains(m_limit, argument)) - { - m_val = argument; - return 0; - } - else - return 1; - } - int option_bool::parse(const pstring &argument) { + unused_var(argument); m_val = true; return 0; } - int option_double::parse(const pstring &argument) - { - bool err = false; - m_val = argument.as_double(&err); - return (err ? 1 : 0); - } - - int option_long::parse(const pstring &argument) - { - bool err = false; - m_val = argument.as_long(&err); - return (err ? 1 : 0); - } - int option_vec::parse(const pstring &argument) { bool err = false; @@ -85,53 +47,88 @@ namespace plib { } options::options() + : m_other_args(nullptr) { } - options::options(option *o[]) + options::options(option **o) + : m_other_args(nullptr) { int i=0; while (o[i] != nullptr) { - m_opts.push_back(o[i]); + register_option(o[i]); i++; } } - options::~options() + void options::register_option(option_base *opt) { - m_opts.clear(); + m_opts.push_back(opt); } - void options::register_option(option_base *opt) + void options::check_consistency() { - m_opts.push_back(opt); + for (auto &opt : m_opts) + { + auto *o = dynamic_cast<option *>(opt); + if (o != nullptr) + { + if (o->short_opt() == "" && o->long_opt() == "") + { + auto *ov = dynamic_cast<option_args *>(o); + if (ov != nullptr) + { + if (m_other_args != nullptr) + { + throw pexception("other args can only be specified once!"); + } + else + { + m_other_args = ov; + } + } + else + throw pexception("found option with neither short or long tag!" ); + } + } + } } - int options::parse(int argc, char *argv[]) + int options::parse(int argc, char **argv) { - m_app = pstring(argv[0], pstring::UTF8); + check_consistency(); + m_app = pstring(argv[0]); + bool seen_other_args = false; for (int i=1; i<argc; ) { - pstring arg(argv[i], pstring::UTF8); + pstring arg(argv[i]); option *opt = nullptr; pstring opt_arg; bool has_equal_arg = false; - if (arg.startsWith("--")) + if (!seen_other_args && plib::startsWith(arg, "--")) { auto v = psplit(arg.substr(2),"="); - opt = getopt_long(v[0]); - has_equal_arg = (v.size() > 1); - if (has_equal_arg) + if (v.size() && v[0] != pstring("")) { - for (unsigned j = 1; j < v.size() - 1; j++) - opt_arg = opt_arg + v[j] + "="; - opt_arg += v[v.size()-1]; + opt = getopt_long(v[0]); + has_equal_arg = (v.size() > 1); + if (has_equal_arg) + { + for (std::size_t j = 1; j < v.size() - 1; j++) + opt_arg = opt_arg + v[j] + "="; + opt_arg += v[v.size()-1]; + } + } + else + { + opt = m_other_args; + seen_other_args = true; } } - else if (arg.startsWith("-")) + else if (!seen_other_args && plib::startsWith(arg, "-")) { std::size_t p = 1; opt = getopt_short(arg.substr(p, 1)); @@ -144,7 +141,11 @@ namespace plib { } else { - return i; + seen_other_args = true; + if (m_other_args == nullptr) + return i; + opt = m_other_args; + i--; // we haven't had an option specifier; } if (opt == nullptr) return i; @@ -158,7 +159,7 @@ namespace plib { else { i++; // FIXME: are there more arguments? - if (opt->do_parse(pstring(argv[i], pstring::UTF8)) != 0) + if (opt->do_parse(pstring(argv[i])) != 0) return i - 1; } } @@ -173,7 +174,7 @@ namespace plib { return argc; } - pstring options::split_paragraphs(pstring text, unsigned width, unsigned indent, + pstring options::split_paragraphs(const pstring &text, unsigned width, unsigned indent, unsigned firstline_indent) { auto paragraphs = psplit(text,"\n"); @@ -181,13 +182,13 @@ namespace plib { for (auto &p : paragraphs) { - pstring line = pstring("").rpad(" ", firstline_indent); + pstring line = plib::rpad(pstring(""), pstring(" "), firstline_indent); for (auto &s : psplit(p, " ")) { if (line.length() + s.length() > width) { ret += line + "\n"; - line = pstring("").rpad(" ", indent); + line = plib::rpad(pstring(""), pstring(" "), indent); } line += s + " "; } @@ -196,8 +197,8 @@ namespace plib { return ret; } - pstring options::help(pstring description, pstring usage, - unsigned width, unsigned indent) + pstring options::help(const pstring &description, const pstring &usage, + unsigned width, unsigned indent) const { pstring ret; @@ -206,6 +207,10 @@ namespace plib { for (auto & optbase : m_opts ) { + // Skip anonymous inputs which are collected in option_args + if (dynamic_cast<option_args *>(optbase) != nullptr) + continue; + if (auto opt = dynamic_cast<option *>(optbase)) { pstring line = ""; @@ -221,20 +226,20 @@ namespace plib { if (opt->has_argument()) { line += "="; - option_str_limit *ol = dynamic_cast<option_str_limit *>(opt); + auto *ol = dynamic_cast<option_str_limit_base *>(opt); if (ol) { for (auto &v : ol->limit()) { line += v + "|"; } - line = line.left(line.length() - 1); + line = plib::left(line, line.length() - 1); } else line += "Value"; } } - line = line.rpad(" ", indent - 2) + " "; + line = plib::rpad(line, pstring(" "), indent - 2) + " "; if (line.length() > indent) { //ret += "TestGroup abc\n def gef\nxyz\n\n" ; @@ -250,6 +255,7 @@ namespace plib { if (grp->help() != "") ret += split_paragraphs(grp->help(), width, 4, 4) + "\n"; } } + // FIXME: other help ... pstring ex(""); for (auto & optbase : m_opts ) { @@ -266,22 +272,22 @@ namespace plib { return ret; } - option *options::getopt_short(pstring arg) + option *options::getopt_short(const pstring &arg) const { for (auto & optbase : m_opts) { auto opt = dynamic_cast<option *>(optbase); - if (opt && opt->short_opt() == arg) + if (opt && arg != "" && opt->short_opt() == arg) return opt; } return nullptr; } - option *options::getopt_long(pstring arg) + option *options::getopt_long(const pstring &arg) const { for (auto & optbase : m_opts) { auto opt = dynamic_cast<option *>(optbase); - if (opt && opt->long_opt() == arg) + if (opt && arg !="" && opt->long_opt() == arg) return opt; } return nullptr; diff --git a/src/lib/netlist/plib/poptions.h b/src/lib/netlist/plib/poptions.h index 491ac0b4d91..086fe32fc8a 100644 --- a/src/lib/netlist/plib/poptions.h +++ b/src/lib/netlist/plib/poptions.h @@ -10,8 +10,8 @@ #ifndef POPTIONS_H_ #define POPTIONS_H_ -#include "pstring.h" #include "plists.h" +#include "pstring.h" #include "putil.h" namespace plib { @@ -24,10 +24,12 @@ class options; class option_base { public: - option_base(options &parent, pstring help); - virtual ~option_base(); + option_base(options &parent, const pstring &help); + virtual ~option_base() = default; + + COPYASSIGNMOVE(option_base, delete) - pstring help() { return m_help; } + pstring help() const { return m_help; } private: pstring m_help; }; @@ -35,11 +37,10 @@ private: class option_group : public option_base { public: - option_group(options &parent, pstring group, pstring help) + option_group(options &parent, const pstring &group, const pstring &help) : option_base(parent, help), m_group(group) { } - ~option_group(); - pstring group() { return m_group; } + pstring group() const { return m_group; } private: pstring m_group; }; @@ -47,11 +48,10 @@ private: class option_example : public option_base { public: - option_example(options &parent, pstring group, pstring help) + option_example(options &parent, const pstring &group, const pstring &help) : option_base(parent, help), m_example(group) { } - ~option_example(); - pstring example() { return m_example; } + pstring example() const { return m_example; } private: pstring m_example; }; @@ -60,8 +60,7 @@ private: class option : public option_base { public: - option(options &parent, pstring ashort, pstring along, pstring help, bool has_argument); - ~option(); + option(options &parent, const pstring &ashort, const pstring &along, const pstring &help, bool has_argument); /* no_argument options will be called with "" argument */ @@ -89,131 +88,177 @@ private: class option_str : public option { public: - option_str(options &parent, pstring ashort, pstring along, pstring defval, pstring help) + option_str(options &parent, const pstring &ashort, const pstring &along, const pstring &defval, const pstring &help) : option(parent, ashort, along, help, true), m_val(defval) {} - pstring operator ()() { return m_val; } + pstring operator ()() const { return m_val; } protected: - virtual int parse(const pstring &argument) override; + int parse(const pstring &argument) override; private: pstring m_val; }; -class option_str_limit : public option +class option_str_limit_base : public option { public: - option_str_limit(options &parent, pstring ashort, pstring along, pstring defval, pstring limit, pstring help) - : option(parent, ashort, along, help, true), m_val(defval) - , m_limit(plib::psplit(limit, ":")) + option_str_limit_base(options &parent, const pstring &ashort, const pstring &along, std::vector<pstring> &&limit, const pstring &help) + : option(parent, ashort, along, help, true) + , m_limit(limit) { } - - pstring operator ()() { return m_val; } - const std::vector<pstring> &limit() { return m_limit; } + const std::vector<pstring> &limit() const { return m_limit; } protected: - virtual int parse(const pstring &argument) override; private: - pstring m_val; std::vector<pstring> m_limit; }; -class option_bool : public option + +template <typename T> +class option_str_limit : public option_str_limit_base { public: - option_bool(options &parent, pstring ashort, pstring along, pstring help) - : option(parent, ashort, along, help, false), m_val(false) - {} + option_str_limit(options &parent, const pstring &ashort, const pstring &along, const T &defval, std::vector<pstring> &&limit, const pstring &help) + : option_str_limit_base(parent, ashort, along, std::move(limit), help), m_val(defval) + { + } + + T operator ()() const { return m_val; } - bool operator ()() { return m_val; } + pstring as_string() const { return limit()[m_val]; } protected: - virtual int parse(const pstring &argument) override; + int parse(const pstring &argument) override + { + auto raw = plib::container::indexof(limit(), argument); + + if (raw != plib::container::npos) + { + m_val = static_cast<T>(raw); + return 0; + } + else + return 1; + } private: - bool m_val; + T m_val; }; -class option_double : public option +class option_bool : public option { public: - option_double(options &parent, pstring ashort, pstring along, double defval, pstring help) - : option(parent, ashort, along, help, true), m_val(defval) + option_bool(options &parent, const pstring &ashort, const pstring &along, const pstring &help) + : option(parent, ashort, along, help, false), m_val(false) {} - double operator ()() { return m_val; } + bool operator ()() const { return m_val; } protected: - virtual int parse(const pstring &argument) override; + int parse(const pstring &argument) override; private: - double m_val; + bool m_val; }; -class option_long : public option +template <typename T> +class option_num : public option { public: - option_long(options &parent, pstring ashort, pstring along, long defval, pstring help) - : option(parent, ashort, along, help, true), m_val(defval) + option_num(options &parent, const pstring &ashort, const pstring &along, T defval, + const pstring &help, + T minval = std::numeric_limits<T>::min(), + T maxval = std::numeric_limits<T>::max() ) + : option(parent, ashort, along, help, true) + , m_val(defval) + , m_min(minval) + , m_max(maxval) {} - long operator ()() { return m_val; } + T operator ()() const { return m_val; } protected: - virtual int parse(const pstring &argument) override; + int parse(const pstring &argument) override + { + bool err; + m_val = pstonum_ne<T>(argument, err); + return (err ? 1 : (m_val < m_min || m_val > m_max)); + } private: - long m_val; + T m_val; + T m_min; + T m_max; }; class option_vec : public option { public: - option_vec(options &parent, pstring ashort, pstring along, pstring help) + option_vec(options &parent, const pstring &ashort, const pstring &along, const pstring &help) : option(parent, ashort, along, help, true) {} - std::vector<pstring> operator ()() { return m_val; } + const std::vector<pstring> &operator ()() const { return m_val; } protected: - virtual int parse(const pstring &argument) override; + int parse(const pstring &argument) override; private: std::vector<pstring> m_val; }; -class options +class option_args : public option_vec { public: + option_args(options &parent, const pstring &help) + : option_vec(parent, "", "", help) + {} +}; - options(); - explicit options(option *o[]); +class options : public nocopyassignmove +{ +public: - ~options(); + options(); + explicit options(option **o); void register_option(option_base *opt); - int parse(int argc, char *argv[]); + int parse(int argc, char **argv); - pstring help(pstring description, pstring usage, - unsigned width = 72, unsigned indent = 20); + pstring help(const pstring &description, const pstring &usage, + unsigned width = 72, unsigned indent = 20) const; - pstring app() { return m_app; } + pstring app() const { return m_app; } private: - static pstring split_paragraphs(pstring text, unsigned width, unsigned indent, + static pstring split_paragraphs(const pstring &text, unsigned width, unsigned indent, unsigned firstline_indent); - option *getopt_short(pstring arg); - option *getopt_long(pstring arg); + void check_consistency(); + + template <typename T> + T *getopt_type() const + { + for (auto & optbase : m_opts ) + { + if (auto opt = dynamic_cast<T *>(optbase)) + return opt; + } + return nullptr; + } + + option *getopt_short(const pstring &arg) const; + option *getopt_long(const pstring &arg) const; std::vector<option_base *> m_opts; pstring m_app; + option_args * m_other_args; }; -} +} // namespace plib #endif /* POPTIONS_H_ */ diff --git a/src/lib/netlist/plib/pparser.cpp b/src/lib/netlist/plib/pparser.cpp index 7547572192d..5e1a231da81 100644 --- a/src/lib/netlist/plib/pparser.cpp +++ b/src/lib/netlist/plib/pparser.cpp @@ -16,16 +16,6 @@ namespace plib { // A simple tokenizer // ---------------------------------------------------------------------------------------- -ptokenizer::ptokenizer(plib::putf8_reader &strm) -: m_strm(strm), m_lineno(0), m_cur_line(""), m_px(m_cur_line.begin()), m_unget(0), m_string('"') -{ -} - -ptokenizer::~ptokenizer() -{ -} - - pstring ptokenizer::currentline_str() { return m_cur_line; @@ -34,7 +24,7 @@ pstring ptokenizer::currentline_str() void ptokenizer::skipeol() { - pstring::code_t c = getc(); + pstring::value_type c = getc(); while (c) { if (c == 10) @@ -49,11 +39,11 @@ void ptokenizer::skipeol() } -pstring::code_t ptokenizer::getc() +pstring::value_type ptokenizer::getc() { if (m_unget != 0) { - pstring::code_t c = m_unget; + pstring::value_type c = m_unget; m_unget = 0; return c; } @@ -66,11 +56,11 @@ pstring::code_t ptokenizer::getc() return 0; return '\n'; } - pstring::code_t c = *(m_px++); + pstring::value_type c = *(m_px++); return c; } -void ptokenizer::ungetc(pstring::code_t c) +void ptokenizer::ungetc(pstring::value_type c) { m_unget = c; } @@ -122,6 +112,7 @@ pstring ptokenizer::get_identifier_or_number() return tok.str(); } +// FIXME: combine into template double ptokenizer::get_number_double() { token_t tok = get_token(); @@ -129,8 +120,8 @@ double ptokenizer::get_number_double() { error(pfmt("Expected a number, got <{1}>")(tok.str()) ); } - bool err = false; - double ret = tok.str().as_double(&err); + bool err; + auto ret = plib::pstonum_ne<double>(tok.str(), err); if (err) error(pfmt("Expected a number, got <{1}>")(tok.str()) ); return ret; @@ -143,8 +134,8 @@ long ptokenizer::get_number_long() { error(pfmt("Expected a long int, got <{1}>")(tok.str()) ); } - bool err = false; - long ret = tok.str().as_long(&err); + bool err; + auto ret = plib::pstonum_ne<long>(tok.str(), err); if (err) error(pfmt("Expected a long int, got <{1}>")(tok.str()) ); return ret; @@ -182,7 +173,7 @@ ptokenizer::token_t ptokenizer::get_token() ptokenizer::token_t ptokenizer::get_token_internal() { /* skip ws */ - pstring::code_t c = getc(); + pstring::value_type c = getc(); while (m_whitespace.find(c) != pstring::npos) { c = getc(); @@ -272,28 +263,31 @@ void ptokenizer::error(const pstring &errs) // A simple preprocessor // ---------------------------------------------------------------------------------------- -ppreprocessor::ppreprocessor(std::vector<define_t> *defines) -: m_ifflag(0), m_level(0), m_lineno(0) +ppreprocessor::ppreprocessor(defines_map_type *defines) +: pistream() +, m_ifflag(0) +, m_level(0) +, m_lineno(0) +, m_pos(0) +, m_state(PROCESS) +, m_comment(false) { - m_expr_sep.push_back("!"); - m_expr_sep.push_back("("); - m_expr_sep.push_back(")"); - m_expr_sep.push_back("+"); - m_expr_sep.push_back("-"); - m_expr_sep.push_back("*"); - m_expr_sep.push_back("/"); - m_expr_sep.push_back("=="); - m_expr_sep.push_back(" "); - m_expr_sep.push_back("\t"); + m_expr_sep.emplace_back("!"); + m_expr_sep.emplace_back("("); + m_expr_sep.emplace_back(")"); + m_expr_sep.emplace_back("+"); + m_expr_sep.emplace_back("-"); + m_expr_sep.emplace_back("*"); + m_expr_sep.emplace_back("/"); + m_expr_sep.emplace_back("&&"); + m_expr_sep.emplace_back("||"); + m_expr_sep.emplace_back("=="); + m_expr_sep.emplace_back(" "); + m_expr_sep.emplace_back("\t"); - m_defines.insert({"__PLIB_PREPROCESSOR__", define_t("__PLIB_PREPROCESSOR__", "1")}); if (defines != nullptr) - { - for (auto & p : *defines) - { - m_defines.insert({p.m_name, p}); - } - } + m_defines = *defines; + m_defines.insert({"__PLIB_PREPROCESSOR__", define_t("__PLIB_PREPROCESSOR__", "1")}); } void ppreprocessor::error(const pstring &err) @@ -301,35 +295,42 @@ void ppreprocessor::error(const pstring &err) throw pexception("PREPRO ERROR: " + err); } +pstream::size_type ppreprocessor::vread(value_type *buf, const pstream::size_type n) +{ + size_type bytes = std::min(m_buf.size() - m_pos, n); + + if (bytes==0) + return 0; + + std::memcpy(buf, m_buf.c_str() + m_pos, bytes); + m_pos += bytes; + return bytes; +} + +#define CHECKTOK2(p_op, p_prio) \ + else if (tok == # p_op) \ + { \ + if (prio < (p_prio)) \ + return val; \ + start++; \ + const auto v2 = expr(sexpr, start, (p_prio)); \ + val = (val p_op v2); \ + } \ +// Operator precedence see https://en.cppreference.com/w/cpp/language/operator_precedence -double ppreprocessor::expr(const std::vector<pstring> &sexpr, std::size_t &start, int prio) +int ppreprocessor::expr(const std::vector<pstring> &sexpr, std::size_t &start, int prio) { - double val; + int val = 0; pstring tok=sexpr[start]; if (tok == "(") { start++; - val = expr(sexpr, start, /*prio*/ 0); + val = expr(sexpr, start, /*prio*/ 255); if (sexpr[start] != ")") error("parsing error!"); start++; } - else if (tok == "!") - { - start++; - val = expr(sexpr, start, 90); - if (val != 0) - val = 0; - else - val = 1; - } - else - { - tok=sexpr[start]; - val = tok.as_double(); - start++; - } while (start < sexpr.size()) { tok=sexpr[start]; @@ -338,36 +339,25 @@ double ppreprocessor::expr(const std::vector<pstring> &sexpr, std::size_t &start // FIXME: catch error return val; } - else if (tok == "+") + else if (tok == "!") { - if (prio > 10) + if (prio < 3) return val; start++; - val = val + expr(sexpr, start, 10); + val = !expr(sexpr, start, 3); } - else if (tok == "-") - { - if (prio > 10) - return val; - start++; - val = val - expr(sexpr, start, 10); - } - else if (tok == "*") - { - start++; - val = val * expr(sexpr, start, 20); - } - else if (tok == "/") - { - start++; - val = val / expr(sexpr, start, 20); - } - else if (tok == "==") + CHECKTOK2(*, 5) + CHECKTOK2(/, 5) + CHECKTOK2(+, 6) + CHECKTOK2(-, 6) + CHECKTOK2(==, 10) + CHECKTOK2(&&, 14) + CHECKTOK2(||, 15) + else { - if (prio > 5) - return val; + // FIXME: error handling + val = plib::pstonum<decltype(val)>(tok); start++; - val = (val == expr(sexpr, start, 5)) ? 1.0 : 0.0; } } return val; @@ -376,10 +366,7 @@ double ppreprocessor::expr(const std::vector<pstring> &sexpr, std::size_t &start ppreprocessor::define_t *ppreprocessor::get_define(const pstring &name) { auto idx = m_defines.find(name); - if (idx != m_defines.end()) - return &idx->second; - else - return nullptr; + return (idx != m_defines.end()) ? &idx->second : nullptr; } pstring ppreprocessor::replace_macros(const pstring &line) @@ -389,78 +376,135 @@ pstring ppreprocessor::replace_macros(const pstring &line) for (auto & elem : elems) { define_t *def = get_define(elem); - if (def != nullptr) - ret += def->m_replace; - else - ret += elem; + ret += (def != nullptr) ? def->m_replace : elem; } return ret; } -static pstring catremainder(const std::vector<pstring> &elems, std::size_t start, pstring sep) +static pstring catremainder(const std::vector<pstring> &elems, std::size_t start, const pstring &sep) { pstring ret(""); - for (auto & elem : elems) + for (std::size_t i = start; i < elems.size(); i++) { - ret += elem; + ret += elems[i]; ret += sep; } return ret; } -pstring ppreprocessor::process_line(const pstring &line) +pstring ppreprocessor::process_comments(pstring line) +{ + bool in_string = false; + + std::size_t e = line.size(); + pstring ret = ""; + for (std::size_t i=0; i < e; ) + { + pstring c = plib::left(line, 1); + line = line.substr(1); + if (!m_comment) + { + if (c=="\"") + { + in_string = !in_string; + ret += c; + } + else if (in_string && c=="\\") + { + i++; + ret += (c + plib::left(line, 1)); + line = line.substr(1); + } + else if (!in_string && c=="/" && plib::left(line,1) == "*") + m_comment = true; + else if (!in_string && c=="/" && plib::left(line,1) == "/") + break; + else + ret += c; + } + else + if (c=="*" && plib::left(line,1) == "/") + { + i++; + line = line.substr(1); + m_comment = false; + } + i++; + } + return ret; +} + +pstring ppreprocessor::process_line(pstring line) { - pstring lt = line.replace_all("\t"," ").trim(); + bool line_cont = plib::right(line, 1) == "\\"; + if (line_cont) + line = plib::left(line, line.size() - 1); + + if (m_state == LINE_CONTINUATION) + m_line += line; + else + m_line = line; + + if (line_cont) + { + m_state = LINE_CONTINUATION; + return ""; + } + else + m_state = PROCESS; + + line = process_comments(m_line); + + pstring lt = plib::trim(plib::replace_all(line, pstring("\t"), pstring(" "))); pstring ret; - m_lineno++; // FIXME ... revise and extend macro handling - if (lt.startsWith("#")) + if (plib::startsWith(lt, "#")) { std::vector<pstring> lti(psplit(lt, " ", true)); - if (lti[0].equals("#if")) + if (lti[0] == "#if") { m_level++; std::size_t start = 0; lt = replace_macros(lt); - std::vector<pstring> t(psplit(lt.substr(3).replace_all(" ",""), m_expr_sep)); - int val = static_cast<int>(expr(t, start, 0)); + std::vector<pstring> t(psplit(replace_all(lt.substr(3), pstring(" "), pstring("")), m_expr_sep)); + auto val = static_cast<int>(expr(t, start, 255)); if (val == 0) m_ifflag |= (1 << m_level); } - else if (lti[0].equals("#ifdef")) + else if (lti[0] == "#ifdef") { m_level++; if (get_define(lti[1]) == nullptr) m_ifflag |= (1 << m_level); } - else if (lti[0].equals("#ifndef")) + else if (lti[0] == "#ifndef") { m_level++; if (get_define(lti[1]) != nullptr) m_ifflag |= (1 << m_level); } - else if (lti[0].equals("#else")) + else if (lti[0] == "#else") { m_ifflag ^= (1 << m_level); } - else if (lti[0].equals("#endif")) + else if (lti[0] == "#endif") { m_ifflag &= ~(1 << m_level); m_level--; } - else if (lti[0].equals("#include")) + else if (lti[0] == "#include") { // ignore } - else if (lti[0].equals("#pragma")) + else if (lti[0] == "#pragma") { - if (m_ifflag == 0 && lti.size() > 3 && lti[1].equals("NETLIST")) + if (m_ifflag == 0 && lti.size() > 3 && lti[1] == "NETLIST") { - if (lti[2].equals("warning")) + if (lti[2] == "warning") error("NETLIST: " + catremainder(lti, 3, " ")); } } - else if (lti[0].equals("#define")) + else if (lti[0] == "#define") { if (m_ifflag == 0) { @@ -470,28 +514,20 @@ pstring ppreprocessor::process_line(const pstring &line) } } else - error(pfmt("unknown directive on line {1}: {2}")(m_lineno)(line)); + { + if (m_ifflag == 0) + error(pfmt("unknown directive on line {1}: {2}")(m_lineno)(replace_macros(line))); + } } else { lt = replace_macros(lt); if (m_ifflag == 0) - { ret += lt; - } } return ret; } -void ppreprocessor::process(putf8_reader &istrm, putf8_writer &ostrm) -{ - pstring line; - while (istrm.readline(line)) - { - line = process_line(line); - ostrm.writeline(line); - } -} -} +} // namespace plib diff --git a/src/lib/netlist/plib/pparser.h b/src/lib/netlist/plib/pparser.h index 7ec517255c8..1eca20e99ad 100644 --- a/src/lib/netlist/plib/pparser.h +++ b/src/lib/netlist/plib/pparser.h @@ -8,20 +8,27 @@ #ifndef PPARSER_H_ #define PPARSER_H_ -#include "pstring.h" #include "plists.h" #include "pstream.h" +#include "pstring.h" -#include <unordered_map> #include <cstdint> +#include <unordered_map> + namespace plib { -class ptokenizer : nocopyassignmove +class ptokenizer { public: - explicit ptokenizer(plib::putf8_reader &strm); + template <typename T> + ptokenizer(T &&strm) // NOLINT(misc-forwarding-reference-overload, bugprone-forwarding-reference-overload) + : m_strm(std::forward<T>(strm)), m_lineno(0), m_cur_line(""), m_px(m_cur_line.begin()), m_unget(0), m_string('"') + { + } + + COPYASSIGNMOVE(ptokenizer, delete) - virtual ~ptokenizer(); + virtual ~ptokenizer() = default; enum token_type { @@ -91,22 +98,23 @@ public: void require_token(const token_id_t &token_num); void require_token(const token_t &tok, const token_id_t &token_num); - token_id_t register_token(pstring token) + token_id_t register_token(const pstring &token) { token_id_t ret(m_tokens.size()); m_tokens.emplace(token, ret); return ret; } - void set_identifier_chars(pstring s) { m_identifier_chars = s; } - void set_number_chars(pstring st, pstring rem) { m_number_chars_start = st; m_number_chars = rem; } - void set_string_char(pstring::code_t c) { m_string = c; } - void set_whitespace(pstring s) { m_whitespace = s; } - void set_comment(pstring start, pstring end, pstring line) + ptokenizer & identifier_chars(pstring s) { m_identifier_chars = std::move(s); return *this; } + ptokenizer & number_chars(pstring st, pstring rem) { m_number_chars_start = std::move(st); m_number_chars = std::move(rem); return *this; } + ptokenizer & string_char(pstring::value_type c) { m_string = c; return *this; } + ptokenizer & whitespace(pstring s) { m_whitespace = std::move(s); return *this; } + ptokenizer & comment(const pstring &start, const pstring &end, const pstring &line) { m_tok_comment_start = register_token(start); m_tok_comment_end = register_token(end); m_tok_line_comment = register_token(line); + return *this; } token_t get_token_internal(); @@ -118,17 +126,17 @@ protected: private: void skipeol(); - pstring::code_t getc(); - void ungetc(pstring::code_t c); + pstring::value_type getc(); + void ungetc(pstring::value_type c); bool eof() { return m_strm.eof(); } - putf8_reader &m_strm; + putf8_reader m_strm; int m_lineno; pstring m_cur_line; pstring::const_iterator m_px; - pstring::code_t m_unget; + pstring::value_type m_unget; /* tokenizer stuff follows ... */ @@ -137,7 +145,7 @@ private: pstring m_number_chars_start; std::unordered_map<pstring, token_id_t> m_tokens; pstring m_whitespace; - pstring::code_t m_string; + pstring::value_type m_string; token_id_t m_tok_comment_start; token_id_t m_tok_comment_end; @@ -145,7 +153,7 @@ private: }; -class ppreprocessor : plib::nocopyassignmove +class ppreprocessor : public pistream { public: @@ -158,29 +166,80 @@ public: pstring m_replace; }; - explicit ppreprocessor(std::vector<define_t> *defines = nullptr); - virtual ~ppreprocessor() {} + using defines_map_type = std::unordered_map<pstring, define_t>; + + explicit ppreprocessor(defines_map_type *defines = nullptr); + ~ppreprocessor() override = default; + + template <typename T> + ppreprocessor & process(T &&istrm) + { + putf8_reader reader(std::forward<T>(istrm)); + pstring line; + while (reader.readline(line)) + { + m_lineno++; + line = process_line(line); + m_buf += decltype(m_buf)(line.c_str()) + static_cast<char>(10); + } + return *this; + } + + COPYASSIGN(ppreprocessor, delete) + ppreprocessor &operator=(ppreprocessor &&src) = delete; - void process(putf8_reader &istrm, putf8_writer &ostrm); + + ppreprocessor(ppreprocessor &&s) noexcept + : 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_lineno(s.m_lineno) + , m_buf(std::move(s.m_buf)) + , m_pos(s.m_pos) + , m_state(s.m_state) + , m_comment(s.m_comment) + { + } protected: - double expr(const std::vector<pstring> &sexpr, std::size_t &start, int prio); + + size_type vread(value_type *buf, const size_type n) override; + void vseek(const pos_type n) override + { + plib::unused_var(n); + /* FIXME throw exception - should be done in base unless implemented */ + } + pos_type vtell() const override { return m_pos; } + + int expr(const std::vector<pstring> &sexpr, std::size_t &start, int prio); define_t *get_define(const pstring &name); pstring replace_macros(const pstring &line); virtual void error(const pstring &err); private: - pstring process_line(const pstring &line); + enum state_e + { + PROCESS, + LINE_CONTINUATION + }; + pstring process_line(pstring line); + pstring process_comments(pstring line); - std::unordered_map<pstring, define_t> m_defines; + defines_map_type m_defines; std::vector<pstring> m_expr_sep; std::uint_least64_t m_ifflag; // 31 if levels int m_level; int m_lineno; + pstring_t<pu8_traits> m_buf; + pos_type m_pos; + state_e m_state; + pstring m_line; + bool m_comment; }; -} +} // namespace plib #endif /* PPARSER_H_ */ diff --git a/src/lib/netlist/plib/ppmf.h b/src/lib/netlist/plib/ppmf.h index dc151d5d6a6..9c5329cccde 100644 --- a/src/lib/netlist/plib/ppmf.h +++ b/src/lib/netlist/plib/ppmf.h @@ -10,9 +10,8 @@ #include "pconfig.h" -#include <utility> #include <cstdint> - +#include <utility> /* * @@ -70,7 +69,8 @@ namespace plib { using generic_function = void (*)(); template<typename MemberFunctionType> - mfp(MemberFunctionType mftp) + mfp(MemberFunctionType mftp) // NOLINT(cppcoreguidelines-pro-type-member-init) + : m_function(0), m_this_delta(0), m_size(sizeof(mfp)) { *reinterpret_cast<MemberFunctionType *>(this) = mftp; @@ -82,7 +82,7 @@ namespace plib { mfp mfpo(mftp); //return mfpo.update_after_bind<FunctionType>(object); generic_function rfunc(nullptr); - generic_class *robject = reinterpret_cast<generic_class *>(object); + auto robject = reinterpret_cast<generic_class *>(object); mfpo.convert_to_generic(rfunc, robject); func = reinterpret_cast<FunctionType>(rfunc); object = reinterpret_cast<ObjectType *>(robject); @@ -95,7 +95,8 @@ namespace plib { if (PHAS_PMF_INTERNAL == 1) { // apply the "this" delta to the object first - generic_class * o_p_delta = reinterpret_cast<generic_class *>(reinterpret_cast<std::uint8_t *>(object) + m_this_delta); + // NOLINTNEXTLINE(clang-analyzer-core.UndefinedBinaryOperatorResult) + auto 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)) @@ -241,23 +242,28 @@ namespace plib { { public: class generic_class; + + template <class C> + using MemberFunctionType = R (C::*)(Targs...); + pmfp() : pmfp_base<R, Targs...>(), m_obj(nullptr) {} - template<typename MemberFunctionType, typename O> - pmfp(MemberFunctionType mftp, O *object) + template<typename O> + pmfp(MemberFunctionType<O> mftp, O *object) : pmfp_base<R, Targs...>() { this->set(mftp, object); } - template<typename MemberFunctionType, typename O> - void set(MemberFunctionType mftp, O *object) + + template<typename O> + void set(MemberFunctionType<O> mftp, O *object) { this->set_base(mftp, object); m_obj = reinterpret_cast<generic_class *>(object); } - inline R operator()(Targs... args) + inline R operator()(Targs ... args) { return this->call(m_obj, std::forward<Targs>(args)...); } @@ -269,6 +275,6 @@ namespace plib { }; -} +} // namespace plib #endif /* PPMF_H_ */ diff --git a/src/lib/netlist/plib/pstate.cpp b/src/lib/netlist/plib/pstate.cpp index 043033ed1ea..3bd93ed4f8e 100644 --- a/src/lib/netlist/plib/pstate.cpp +++ b/src/lib/netlist/plib/pstate.cpp @@ -9,17 +9,6 @@ #include "palloc.h" namespace plib { -state_manager_t::state_manager_t() -{ -} - -state_manager_t::~state_manager_t() -{ - m_save.clear(); - m_custom.clear(); -} - - void state_manager_t::save_state_ptr(const void *owner, const pstring &stname, const datatype_t &dt, const std::size_t count, void *ptr) { @@ -29,46 +18,40 @@ void state_manager_t::save_state_ptr(const void *owner, const pstring &stname, c void state_manager_t::remove_save_items(const void *owner) { - for (auto i = m_save.begin(); i != m_save.end(); ) + auto i = m_save.end(); + while (i != m_save.begin()) { + i--; if (i->get()->m_owner == owner) i = m_save.erase(i); - else - i++; } - for (auto i = m_custom.begin(); i != m_custom.end(); ) + i = m_custom.end(); + while (i > m_custom.begin()) { + i--; if (i->get()->m_owner == owner) i = m_custom.erase(i); - else - i++; } } void state_manager_t::pre_save() { for (auto & s : m_custom) - s->m_callback->on_pre_save(); + s->m_callback->on_pre_save(*this); } void state_manager_t::post_load() { for (auto & s : m_custom) - s->m_callback->on_post_load(); + s->m_callback->on_post_load(*this); } template<> void state_manager_t::save_item(const void *owner, callback_t &state, const pstring &stname) { - //save_state_ptr(stname, DT_CUSTOM, 0, 1, &state); callback_t *state_p = &state; auto p = plib::make_unique<entry_t>(stname, owner, state_p); m_custom.push_back(std::move(p)); state.register_state(*this, stname); } -state_manager_t::callback_t::~callback_t() -{ -} - - -} +} // namespace plib diff --git a/src/lib/netlist/plib/pstate.h b/src/lib/netlist/plib/pstate.h index 9757d6408b7..ac75ca6b69e 100644 --- a/src/lib/netlist/plib/pstate.h +++ b/src/lib/netlist/plib/pstate.h @@ -8,11 +8,13 @@ #ifndef PSTATE_H_ #define PSTATE_H_ +#include "palloc.h" #include "pstring.h" #include "ptypes.h" -#include <vector> +#include <array> #include <memory> +#include <vector> // ---------------------------------------------------------------------------------------- // state saving ... @@ -38,32 +40,31 @@ public: const bool is_custom; }; - template<typename T> struct datatype_f + template<typename T> + static datatype_t dtype() { - static inline const datatype_t f() - { - return datatype_t(sizeof(T), - plib::is_integral<T>::value || std::is_enum<T>::value, - std::is_floating_point<T>::value); - } - }; + return datatype_t(sizeof(T), + plib::is_integral<T>::value || std::is_enum<T>::value, + std::is_floating_point<T>::value); + } class callback_t { public: using list_t = std::vector<callback_t *>; - virtual ~callback_t(); - virtual void register_state(state_manager_t &manager, const pstring &module) = 0; - virtual void on_pre_save() = 0; - virtual void on_post_load() = 0; + virtual void on_pre_save(state_manager_t &manager) = 0; + virtual void on_post_load(state_manager_t &manager) = 0; protected: + callback_t() = default; + ~callback_t() = default; + COPYASSIGNMOVE(callback_t, default) }; struct entry_t { - using list_t = std::vector<std::unique_ptr<entry_t>>; + using list_t = std::vector<plib::unique_ptr<entry_t>>; entry_t(const pstring &stname, const datatype_t &dt, const void *owner, const std::size_t count, void *ptr) @@ -72,8 +73,6 @@ public: entry_t(const pstring &stname, const void *owner, callback_t *callback) : m_name(stname), m_dt(datatype_t(true)), m_owner(owner), m_callback(callback), m_count(0), m_ptr(nullptr) { } - ~entry_t() { } - pstring m_name; const datatype_t m_dt; const void * m_owner; @@ -82,35 +81,49 @@ public: void * m_ptr; }; - state_manager_t(); - ~state_manager_t(); + state_manager_t() = default; - template<typename C> void save_item(const void *owner, C &state, const pstring &stname) + template<typename C> + void save_item(const void *owner, C &state, const pstring &stname) { - save_state_ptr( owner, stname, datatype_f<C>::f(), 1, &state); + save_state_ptr( owner, stname, dtype<C>(), 1, &state); } - template<typename C, std::size_t N> void save_item(const void *owner, C (&state)[N], const pstring &stname) + template<typename C, std::size_t N> + void save_item(const void *owner, C (&state)[N], const pstring &stname) // NOLINT(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) { - save_state_ptr(owner, stname, datatype_f<C>::f(), N, &(state[0])); + save_state_ptr(owner, stname, dtype<C>(), N, &(state[0])); } - template<typename C> void save_item(const void *owner, C *state, const pstring &stname, const std::size_t count) + template<typename C> + void save_item(const void *owner, C *state, const pstring &stname, const std::size_t count) { - save_state_ptr(owner, stname, datatype_f<C>::f(), count, state); + save_state_ptr(owner, stname, dtype<C>(), count, state); } template<typename C> void save_item(const void *owner, std::vector<C> &v, const pstring &stname) { - save_state(v.data(), owner, stname, v.size()); + save_state_ptr(owner, stname, dtype<C>(), v.size(), v.data()); + } + + template<typename C, std::size_t N> + void save_item(const void *owner, std::array<C, N> &a, const pstring &stname) + { + save_state_ptr(owner, stname, dtype<C>(), N, a.data()); } void pre_save(); void post_load(); void remove_save_items(const void *owner); - const entry_t::list_t &save_list() const { return m_save; } + const std::vector<const entry_t *> save_list() const + { + std::vector<const entry_t *> ret; + for (auto &i : m_save) + ret.push_back(i.get()); + return ret; + } void save_state_ptr(const void *owner, const pstring &stname, const datatype_t &dt, const std::size_t count, void *ptr); @@ -124,6 +137,6 @@ private: template<> void state_manager_t::save_item(const void *owner, callback_t &state, const pstring &stname); -} +} // namespace plib #endif /* PSTATE_H_ */ diff --git a/src/lib/netlist/plib/pstream.cpp b/src/lib/netlist/plib/pstream.cpp index 420f63c9e5e..a7acdaafb52 100644 --- a/src/lib/netlist/plib/pstream.cpp +++ b/src/lib/netlist/plib/pstream.cpp @@ -8,9 +8,9 @@ #include "pstream.h" #include "palloc.h" +#include <algorithm> #include <cstdio> #include <cstdlib> -#include <algorithm> // VS2015 prefers _dup #ifdef _WIN32 @@ -21,34 +21,14 @@ namespace plib { -pstream::~pstream() -{ -} - // ----------------------------------------------------------------------------- // pistream: input stream // ----------------------------------------------------------------------------- -pistream::~pistream() -{ -} - // ----------------------------------------------------------------------------- // postream: output stream // ----------------------------------------------------------------------------- -postream::~postream() -{ -} - -void postream::write(pistream &strm) -{ - char buf[1024]; - pos_type r; - while ((r=strm.read(buf, 1024)) > 0) - write(buf, r); -} - // ----------------------------------------------------------------------------- // Input file stream // ----------------------------------------------------------------------------- @@ -91,7 +71,7 @@ pifilestream::~pifilestream() } } -pifilestream::pos_type pifilestream::vread(void *buf, const pos_type n) +pifilestream::pos_type pifilestream::vread(value_type *buf, const pos_type n) { pos_type r = fread(buf, 1, n, static_cast<FILE *>(m_file)); if (r < n) @@ -119,7 +99,7 @@ void pifilestream::vseek(const pos_type n) throw file_e("Generic file operation failed: {}", m_filename); } -pifilestream::pos_type pifilestream::vtell() +pifilestream::pos_type pifilestream::vtell() const { long ret = ftell(static_cast<FILE *>(m_file)); if (ret < 0) @@ -140,10 +120,6 @@ pstdin::pstdin() /* nothing to do */ } -pstdin::~pstdin() -{ -} - // ----------------------------------------------------------------------------- // Output file stream // ----------------------------------------------------------------------------- @@ -180,12 +156,11 @@ pofilestream::~pofilestream() } } -void pofilestream::vwrite(const void *buf, const pos_type n) +void pofilestream::vwrite(const value_type *buf, const pos_type n) { std::size_t r = fwrite(buf, 1, n, static_cast<FILE *>(m_file)); if (r < n) { - //printf("%ld %ld %s\n", r, n, strerror(errno)); if (ferror(static_cast<FILE *>(m_file))) throw file_write_e(m_filename); } @@ -204,7 +179,7 @@ void pofilestream::vseek(const pos_type n) } } -pstream::pos_type pofilestream::vtell() +pstream::pos_type pofilestream::vtell() const { std::ptrdiff_t ret = ftell(static_cast<FILE *>(m_file)); if (ret < 0) @@ -215,11 +190,6 @@ pstream::pos_type pofilestream::vtell() return static_cast<pos_type>(ret); } -postringstream::~postringstream() -{ -} - - // ----------------------------------------------------------------------------- // pstderr: write to stderr // ----------------------------------------------------------------------------- @@ -233,10 +203,6 @@ pstderr::pstderr() { } -pstderr::~pstderr() -{ -} - // ----------------------------------------------------------------------------- // pstdout: write to stdout // ----------------------------------------------------------------------------- @@ -250,35 +216,32 @@ pstdout::pstdout() { } -pstdout::~pstdout() -{ -} - // ----------------------------------------------------------------------------- // Memory stream // ----------------------------------------------------------------------------- pimemstream::pimemstream(const void *mem, const pos_type len) - : pistream(FLAG_SEEKABLE), m_pos(0), m_len(len), m_mem(static_cast<const pstring::mem_t *>(mem)) + : pistream(FLAG_SEEKABLE), m_pos(0), m_len(len), m_mem(static_cast<const char *>(mem)) { } -pimemstream::pimemstream(const pomemstream &ostrm) -: pistream(FLAG_SEEKABLE), m_pos(0), m_len(ostrm.size()), m_mem(reinterpret_cast<pstring::mem_t *>(ostrm.memory())) +pimemstream::pimemstream() + : pistream(FLAG_SEEKABLE), m_pos(0), m_len(0), m_mem(static_cast<const char *>(nullptr)) { } -pimemstream::~pimemstream() +pimemstream::pimemstream(const pomemstream &ostrm) +: pistream(FLAG_SEEKABLE), m_pos(0), m_len(ostrm.size()), m_mem(reinterpret_cast<const char *>(ostrm.memory())) { } -pimemstream::pos_type pimemstream::vread(void *buf, const pos_type n) +pimemstream::pos_type pimemstream::vread(value_type *buf, const pos_type n) { pos_type ret = (m_pos + n <= m_len) ? n : m_len - m_pos; if (ret > 0) { - std::copy(m_mem + m_pos, m_mem + m_pos + ret, static_cast<char *>(buf)); + std::copy(m_mem + m_pos, m_mem + m_pos + ret, reinterpret_cast<char *>(buf)); m_pos += ret; } @@ -295,78 +258,45 @@ void pimemstream::vseek(const pos_type n) } -pimemstream::pos_type pimemstream::vtell() +pimemstream::pos_type pimemstream::vtell() const { return m_pos; } -pistringstream::~pistringstream() -{ -} - // ----------------------------------------------------------------------------- // Output memory stream // ----------------------------------------------------------------------------- pomemstream::pomemstream() -: postream(FLAG_SEEKABLE), m_pos(0), m_capacity(1024), m_size(0) -{ - m_mem = palloc_array<char>(m_capacity); -} - -pomemstream::~pomemstream() +: postream(FLAG_SEEKABLE), m_pos(0), m_mem(1024) { - pfree_array(m_mem); + m_mem.clear(); } -void pomemstream::vwrite(const void *buf, const pos_type n) +void pomemstream::vwrite(const value_type *buf, const pos_type n) { - if (m_pos + n >= m_capacity) - { - while (m_pos + n >= m_capacity) - m_capacity *= 2; - char *o = m_mem; - m_mem = palloc_array<char>(m_capacity); - if (m_mem == nullptr) - { - throw out_of_mem_e("pomemstream::vwrite"); - } - std::copy(o, o + m_pos, m_mem); - pfree_array(o); - } + if (m_pos + n >= m_mem.size()) + m_mem.resize(m_pos + n); - std::copy(static_cast<const char *>(buf), static_cast<const char *>(buf) + n, m_mem + m_pos); + std::copy(buf, buf + n, &m_mem[0] + m_pos); m_pos += n; - m_size = std::max(m_pos, m_size); } void pomemstream::vseek(const pos_type n) { m_pos = n; - m_size = std::max(m_pos, m_size); - if (m_size >= m_capacity) - { - while (m_size >= m_capacity) - m_capacity *= 2; - char *o = m_mem; - m_mem = palloc_array<char>(m_capacity); - if (m_mem == nullptr) - { - throw out_of_mem_e("pomemstream::vseek"); - } - std::copy(o, o + m_pos, m_mem); - pfree_array(o); - } + if (m_pos>=m_mem.size()) + m_mem.resize(m_pos); } -pstream::pos_type pomemstream::vtell() +pstream::pos_type pomemstream::vtell() const { return m_pos; } bool putf8_reader::readline(pstring &line) { - pstring::code_t c = 0; + putf8string::code_t c = 0; m_linebuf = ""; if (!this->readcode(c)) { @@ -378,23 +308,14 @@ bool putf8_reader::readline(pstring &line) if (c == 10) break; else if (c != 13) /* ignore CR */ - m_linebuf += pstring(c); + m_linebuf += putf8string(c); if (!this->readcode(c)) break; } - line = m_linebuf; + line = m_linebuf.c_str(); return true; } -putf8_fmt_writer::putf8_fmt_writer(postream &strm) -: pfmt_writer_t() -, putf8_writer(strm) -{ -} - -putf8_fmt_writer::~putf8_fmt_writer() -{ -} void putf8_fmt_writer::vdowrite(const pstring &ls) const { @@ -403,4 +324,4 @@ void putf8_fmt_writer::vdowrite(const pstring &ls) const -} +} // namespace plib diff --git a/src/lib/netlist/plib/pstream.h b/src/lib/netlist/plib/pstream.h index 3e9ee99cba0..93497eb1423 100644 --- a/src/lib/netlist/plib/pstream.h +++ b/src/lib/netlist/plib/pstream.h @@ -7,46 +7,76 @@ #ifndef PSTREAM_H_ #define PSTREAM_H_ + +#include "palloc.h" #include "pconfig.h" -#include "pstring.h" -#include "pfmtlog.h" #include "pexception.h" +#include "pfmtlog.h" +#include "pstring.h" + +#define USE_CSTREAM (0) +#include <array> +#include <type_traits> #include <vector> +#if USE_CSTREAM +#include <fstream> +//#include <strstream> +#include <sstream> +#endif + namespace plib { + +#if USE_CSTREAM +typedef std::ostream postream; +typedef std::ofstream pofilestream; +typedef std::ostringstream postringstream; +typedef std::ostringstream pomemstream; + +#endif + // ----------------------------------------------------------------------------- // pstream: things common to all streams // ----------------------------------------------------------------------------- -class pstream : nocopyassignmove +class pstream { public: using pos_type = std::size_t; + using size_type = std::size_t; static constexpr pos_type SEEK_EOF = static_cast<pos_type>(-1); + COPYASSIGN(pstream, delete) + pstream &operator=(pstream &&) noexcept = delete; + bool seekable() const { return ((m_flags & FLAG_SEEKABLE) != 0); } - void seek(const pos_type n) + void seekp(const pos_type n) { - return vseek(n); + vseek(n); } - pos_type tell() + pos_type tellp() const { return vtell(); } protected: + pstream() : m_flags(0) + { + } explicit pstream(const unsigned flags) : m_flags(flags) { } - ~pstream(); + pstream(pstream &&src) noexcept = default; + + virtual ~pstream() = default; virtual void vseek(const pos_type n) = 0; - virtual pos_type vtell() = 0; + virtual pos_type vtell() const = 0; static constexpr unsigned FLAG_EOF = 0x01; static constexpr unsigned FLAG_SEEKABLE = 0x04; @@ -69,51 +99,71 @@ private: // pistream: input stream // ----------------------------------------------------------------------------- -class pistream : public pstream +template <typename T> +class pistream_base : public pstream { public: - virtual ~pistream(); + using value_type = T; + + ~pistream_base() noexcept override = default; + + COPYASSIGN(pistream_base, delete) + pistream_base &operator=(pistream_base &&src) noexcept = delete; bool eof() const { return ((flags() & FLAG_EOF) != 0); } - pos_type read(void *buf, const pos_type n) + pos_type read(T *buf, const pos_type n) { return vread(buf, n); } protected: - explicit pistream(const unsigned flags) : pstream(flags) {} - /* read up to n bytes from stream */ - virtual pos_type vread(void *buf, const pos_type n) = 0; + pistream_base() : pstream(0) {} + explicit pistream_base(const unsigned flags) : pstream(flags) {} + pistream_base(pistream_base &&src) noexcept : pstream(std::move(src)) {} + /* read up to n bytes from stream */ + virtual size_type vread(T *buf, const size_type n) = 0; }; +using pistream = pistream_base<char>; + // ----------------------------------------------------------------------------- // postream: output stream // ----------------------------------------------------------------------------- -class postream : public pstream +#if !USE_CSTREAM +template <typename T> +class postream_base : public pstream { public: - virtual ~postream(); + using value_type = T; + + postream_base() = default; + ~postream_base() noexcept override = default; + + COPYASSIGN(postream_base, delete) + postream_base &operator=(postream_base &&src) noexcept = delete; - void write(const void *buf, const pos_type n) + void write(const T *buf, const size_type n) { vwrite(buf, n); } - void write(pistream &strm); - protected: - explicit postream(unsigned flags) : pstream(flags) {} + explicit postream_base(unsigned flags) : pstream(flags) {} + postream_base(postream_base &&src) noexcept : pstream(std::move(src)) {} + /* write n bytes to stream */ - virtual void vwrite(const void *buf, const pos_type n) = 0; + virtual void vwrite(const T *buf, const size_type n) = 0; private: }; +using postream = postream_base<char>; + // ----------------------------------------------------------------------------- // pomemstream: output string stream // ----------------------------------------------------------------------------- @@ -123,22 +173,31 @@ class pomemstream : public postream public: pomemstream(); - virtual ~pomemstream() override; - char *memory() const { return m_mem; } - pos_type size() const { return m_size; } + COPYASSIGN(pomemstream, delete) + + pomemstream(pomemstream &&src) noexcept + : postream(std::move(src)) + , m_pos(src.m_pos) + , m_mem(std::move(src.m_mem)) + { + } + pomemstream &operator=(pomemstream &&src) = delete; + + ~pomemstream() override = default; + + const char *memory() const { return m_mem.data(); } + pos_type size() const { return m_mem.size(); } protected: /* write n bytes to stream */ - virtual void vwrite(const void *buf, const pos_type) override; - virtual void vseek(const pos_type n) override; - virtual pos_type vtell() override; + void vwrite(const value_type *buf, const pos_type) override; + void vseek(const pos_type n) override; + pos_type vtell() const override; private: pos_type m_pos; - pos_type m_capacity; - pos_type m_size; - char *m_mem; + std::vector<char> m_mem; }; class postringstream : public postream @@ -146,18 +205,26 @@ class postringstream : public postream public: postringstream() : postream(0) { } - virtual ~postringstream() override; + postringstream(postringstream &&src) noexcept + : postream(std::move(src)) + , m_buf(std::move(src.m_buf)) + { src.m_buf = ""; } + + COPYASSIGN(postringstream, delete) + postringstream &operator=(postringstream &&src) = delete; + + ~postringstream() override = default; const pstring &str() { return m_buf; } protected: /* write n bytes to stream */ - virtual void vwrite(const void *buf, const pos_type n) override + void vwrite(const value_type *buf, const pos_type n) override { - m_buf += pstring(static_cast<const pstring::mem_t *>(buf), n, pstring::UTF8); + m_buf += pstring(reinterpret_cast<const pstring::mem_t *>(buf), n); } - virtual void vseek(const pos_type n) override { } - virtual pos_type vtell() override { return m_buf.mem_t_size(); } + void vseek(const pos_type n) override { unused_var(n); } + pos_type vtell() const override { return m_buf.size(); } private: pstring m_buf; @@ -171,15 +238,28 @@ class pofilestream : public postream { public: - explicit pofilestream(const pstring &fname); - virtual ~pofilestream() override; + pofilestream(const pstring &fname); + pofilestream(pofilestream &&src) noexcept + : postream(std::move(src)) + , m_file(src.m_file) + , m_pos(src.m_pos) + , m_actually_close(src.m_actually_close) + , m_filename(std::move(src.m_filename)) + { + src.m_file = nullptr; + src.m_actually_close = false; + } + COPYASSIGN(pofilestream, delete) + pofilestream &operator=(pofilestream &&src) = delete; + + ~pofilestream() override; protected: pofilestream(void *file, const pstring &name, const bool do_close); /* write n bytes to stream */ - virtual void vwrite(const void *buf, const pos_type n) override; - virtual void vseek(const pos_type n) override; - virtual pos_type vtell() override; + void vwrite(const value_type *buf, const pos_type n) override; + void vseek(const pos_type n) override; + pos_type vtell() const override; private: void *m_file; @@ -193,12 +273,17 @@ private: // ----------------------------------------------------------------------------- // pstderr: write to stderr // ----------------------------------------------------------------------------- +#endif class pstderr : public pofilestream { public: pstderr(); - virtual ~pstderr(); + pstderr(pstderr &&src) noexcept = default; + pstderr &operator=(pstderr &&src) = delete; + COPYASSIGN(pstderr, delete) + + ~pstderr() noexcept override= default; }; // ----------------------------------------------------------------------------- @@ -209,7 +294,11 @@ class pstdout : public pofilestream { public: pstdout(); - virtual ~pstdout(); + pstdout(pstdout &&src) noexcept = default; + pstdout &operator=(pstdout &&src) = delete; + COPYASSIGN(pstdout, delete) + + ~pstdout() noexcept override = default; }; // ----------------------------------------------------------------------------- @@ -220,16 +309,29 @@ class pifilestream : public pistream { public: - explicit pifilestream(const pstring &fname); - virtual ~pifilestream() override; + pifilestream(const pstring &fname); + ~pifilestream() override; + + pifilestream(pifilestream &&src) noexcept + : pistream(std::move(src)) + , m_file(src.m_file) + , m_pos(src.m_pos) + , m_actually_close(src.m_actually_close) + , m_filename(std::move(src.m_filename)) + { + src.m_actually_close = false; + src.m_file = nullptr; + } + COPYASSIGN(pifilestream, delete) + pifilestream &operator=(pifilestream &&src) = delete; protected: pifilestream(void *file, const pstring &name, const bool do_close); /* read up to n bytes from stream */ - virtual pos_type vread(void *buf, const pos_type n) override; - virtual void vseek(const pos_type n) override; - virtual pos_type vtell() override; + pos_type vread(value_type *buf, const pos_type n) override; + void vseek(const pos_type n) override; + pos_type vtell() const override; private: void *m_file; @@ -249,7 +351,10 @@ class pstdin : public pifilestream public: pstdin(); - virtual ~pstdin() override; + pstdin(pstdin &&src) noexcept = default; + pstdin &operator=(pstdin &&src) = delete; + COPYASSIGN(pstdin, delete) + ~pstdin() override = default; }; // ----------------------------------------------------------------------------- @@ -261,15 +366,36 @@ class pimemstream : public pistream public: pimemstream(const void *mem, const pos_type len); + pimemstream(); + + pimemstream(pimemstream &&src) noexcept + : pistream(std::move(src)) + , m_pos(src.m_pos) + , m_len(src.m_len) + , m_mem(src.m_mem) + { + src.m_mem = nullptr; + } + COPYASSIGN(pimemstream, delete) + pimemstream &operator=(pimemstream &&src) = delete; + explicit pimemstream(const pomemstream &ostrm); - virtual ~pimemstream() override; + + ~pimemstream() override = default; pos_type size() const { return m_len; } protected: + + void set_mem(const void *mem, const pos_type len) + { + m_mem = static_cast<const char *>(mem); + m_len = len; + } + /* read up to n bytes from stream */ - virtual pos_type vread(void *buf, const pos_type n) override; - virtual void vseek(const pos_type n) override; - virtual pos_type vtell() override; + pos_type vread(value_type *buf, const pos_type n) override; + void vseek(const pos_type n) override; + pos_type vtell() const override; private: pos_type m_pos; @@ -284,12 +410,25 @@ private: class pistringstream : public pimemstream { public: - explicit pistringstream(const pstring &str) : pimemstream(str.c_str(), str.mem_t_size()), m_str(str) { } - virtual ~pistringstream() override; + pistringstream(const pstring &str) + : pimemstream() + , m_str(str) + { + set_mem(m_str.c_str(), std::strlen(m_str.c_str())); + } + pistringstream(pistringstream &&src) noexcept + : pimemstream(std::move(src)), m_str(src.m_str) + { + set_mem(m_str.c_str(), std::strlen(m_str.c_str())); + } + COPYASSIGN(pistringstream, delete) + pistringstream &operator=(pistringstream &&src) = delete; + + ~pistringstream() override = default; private: /* only needed for a reference till destruction */ - pstring m_str; + const pstring m_str; }; // ----------------------------------------------------------------------------- @@ -298,47 +437,84 @@ private: /* this digests linux & dos/windows text files */ -class putf8_reader : plib::nocopyassignmove + +template <typename T> +struct constructor_helper +{ + plib::unique_ptr<pistream> operator()(T &&s) { return std::move(plib::make_unique<T>(std::move(s))); } +}; + +// NOLINTNEXTLINE(cppcoreguidelines-special-member-functions) +class putf8_reader { public: - explicit putf8_reader(pistream &strm) : m_strm(strm) {} - virtual ~putf8_reader() {} - bool eof() const { return m_strm.eof(); } + COPYASSIGN(putf8_reader, delete) + putf8_reader &operator=(putf8_reader &&src) = delete; + virtual ~putf8_reader() = default; + + template <typename T> + friend struct constructor_helper; + + template <typename T> + putf8_reader(T &&strm) // NOLINT(cppcoreguidelines-special-member-functions, misc-forwarding-reference-overload, bugprone-forwarding-reference-overload) + : m_strm(std::move(constructor_helper<T>()(std::move(strm)))) // NOLINT(bugprone-move-forwarding-reference) + {} + + bool eof() const { return m_strm->eof(); } bool readline(pstring &line); - bool readbyte1(char &b) + bool readbyte1(pistream::value_type &b) { - return (m_strm.read(&b, 1) == 1); + return (m_strm->read(&b, 1) == 1); } - bool readcode(pstring::code_t &c) + bool readcode(putf8string::traits_type::code_t &c) { - char b[4]; - if (m_strm.read(&b[0], 1) != 1) + std::array<pistream::value_type, 4> b{0}; + if (m_strm->read(&b[0], 1) != 1) return false; - const std::size_t l = pstring::traits_type::codelen(b); + const std::size_t l = putf8string::traits_type::codelen(reinterpret_cast<putf8string::traits_type::mem_t *>(&b)); for (std::size_t i = 1; i < l; i++) - if (m_strm.read(&b[i], 1) != 1) + if (m_strm->read(&b[i], 1) != 1) return false; - c = pstring::traits_type::code(b); + c = putf8string::traits_type::code(reinterpret_cast<putf8string::traits_type::mem_t *>(&b)); return true; } private: - pistream &m_strm; - pstring m_linebuf; + plib::unique_ptr<pistream> m_strm; + putf8string m_linebuf; }; +template <> +struct constructor_helper<putf8_reader> +{ + plib::unique_ptr<pistream> operator()(putf8_reader &&s) { return std::move(s.m_strm); } +}; + +template <> +struct constructor_helper<plib::unique_ptr<pistream>> +{ + plib::unique_ptr<pistream> operator()(plib::unique_ptr<pistream> &&s) { return std::move(s); } +}; + + // ----------------------------------------------------------------------------- // putf8writer_t: writer on top of ostream // ----------------------------------------------------------------------------- -class putf8_writer : plib::nocopyassignmove +class putf8_writer { public: - explicit putf8_writer(postream &strm) : m_strm(strm) {} - virtual ~putf8_writer() {} + explicit putf8_writer(postream *strm) : m_strm(strm) {} + + putf8_writer(putf8_writer &&src) noexcept : m_strm(src.m_strm) {} + + COPYASSIGN(putf8_writer, delete) + putf8_writer &operator=(putf8_writer &&src) = delete; + + virtual ~putf8_writer() = default; void writeline(const pstring &line) const { @@ -348,24 +524,34 @@ public: void write(const pstring &text) const { - m_strm.write(text.c_str(), text.mem_t_size()); + // NOLINTNEXTLINE(performance-unnecessary-copy-initialization) + const putf8string conv_utf8(text); + m_strm->write(reinterpret_cast<const pistream::value_type *>(conv_utf8.c_str()), conv_utf8.mem_t_size()); } - void write(const pstring::code_t c) const + void write(const pstring::value_type c) const { - write(pstring(c)); + pstring t = pstring("") + c; + write(t); } private: - postream &m_strm; + postream *m_strm; }; class putf8_fmt_writer : public pfmt_writer_t<putf8_fmt_writer>, public putf8_writer { public: - explicit putf8_fmt_writer(postream &strm); - virtual ~putf8_fmt_writer() override; + explicit putf8_fmt_writer(postream *strm) + : pfmt_writer_t() + , putf8_writer(strm) + { + } + + COPYASSIGNMOVE(putf8_fmt_writer, delete) + + ~putf8_fmt_writer() override = default; //protected: void vdowrite(const pstring &ls) const; @@ -377,22 +563,29 @@ private: // pbinary_writer_t: writer on top of ostream // ----------------------------------------------------------------------------- -class pbinary_writer : plib::nocopyassignmove +class pbinary_writer { public: explicit pbinary_writer(postream &strm) : m_strm(strm) {} - virtual ~pbinary_writer() {} + pbinary_writer(pbinary_writer &&src) noexcept : m_strm(src.m_strm) {} + + COPYASSIGN(pbinary_writer, delete) + postringstream &operator=(pbinary_writer &&src) = delete; + + virtual ~pbinary_writer() = default; template <typename T> - void write(const T val) + void write(const T &val) { - m_strm.write(&val, sizeof(T)); + m_strm.write(reinterpret_cast<const postream::value_type *>(&val), sizeof(T)); } void write(const pstring &s) { - write(s.mem_t_size()); - m_strm.write(s.c_str(), s.mem_t_size()); + const auto sm = reinterpret_cast<const postream::value_type *>(s.c_str()); + const std::size_t sl = std::strlen(s.c_str()); + write(sl); + m_strm.write(sm, sl); } template <typename T> @@ -400,34 +593,38 @@ public: { std::size_t sz = val.size(); write(sz); - m_strm.write(val.data(), sizeof(T) * sz); + m_strm.write(reinterpret_cast<const postream::value_type *>(val.data()), sizeof(T) * sz); } private: postream &m_strm; }; -class pbinary_reader : plib::nocopyassignmove +class pbinary_reader { public: explicit pbinary_reader(pistream &strm) : m_strm(strm) {} - virtual ~pbinary_reader() {} + pbinary_reader(pbinary_reader &&src) noexcept : m_strm(src.m_strm) { } + + COPYASSIGN(pbinary_reader, delete) + pbinary_reader &operator=(pbinary_reader &&src) = delete; + + virtual ~pbinary_reader() = default; template <typename T> void read(T &val) { - m_strm.read(&val, sizeof(T)); + m_strm.read(reinterpret_cast<pistream::value_type *>(&val), sizeof(T)); } void read( pstring &s) { std::size_t sz = 0; read(sz); - pstring::mem_t *buf = new pstring::mem_t[sz+1]; - m_strm.read(buf, sz); + std::vector<plib::string_info<pstring>::mem_t> buf(sz+1); + m_strm.read(buf.data(), sz); buf[sz] = 0; - s = pstring(buf, pstring::UTF8); - delete [] buf; + s = pstring(buf.data()); } template <typename T> @@ -436,13 +633,38 @@ public: std::size_t sz = 0; read(sz); val.resize(sz); - m_strm.read(val.data(), sizeof(T) * sz); + m_strm.read(reinterpret_cast<pistream::value_type *>(val.data()), sizeof(T) * sz); } private: pistream &m_strm; }; +inline void copystream(postream &dest, pistream &src) +{ + std::array<postream::value_type, 1024> buf; // NOLINT(cppcoreguidelines-pro-type-member-init) + pstream::pos_type r; + while ((r=src.read(buf.data(), 1024)) > 0) + dest.write(buf.data(), r); } +struct perrlogger +{ + template <typename ... Args> + explicit perrlogger(Args&& ... args) + { + h()(std::forward<Args>(args)...); + } +private: + static putf8_fmt_writer &h() + { + static plib::pstderr perr_strm; + static plib::putf8_fmt_writer perr(&perr_strm); + return perr; + } +}; + + +} // namespace plib + #endif /* PSTREAM_H_ */ diff --git a/src/lib/netlist/plib/pstring.cpp b/src/lib/netlist/plib/pstring.cpp index 47d35d7c82f..c304f11d1fd 100644 --- a/src/lib/netlist/plib/pstring.cpp +++ b/src/lib/netlist/plib/pstring.cpp @@ -10,17 +10,8 @@ #include "plists.h" #include <algorithm> -#include <stack> #include <atomic> - -template <typename T> -std::size_t strlen_mem(const T *s) -{ - std::size_t len(0); - while (*s++) - ++len; - return len; -} +#include <stack> template<typename F> int pstring_t<F>::compare(const pstring_t &right) const @@ -67,18 +58,6 @@ pstring_t<F> pstring_t<F>::substr(size_type start, size_type nlen) const } template<typename F> -pstring_t<F> pstring_t<F>::ucase() const -{ - pstring_t ret; - for (const auto &c : *this) - if (c >= 'a' && c <= 'z') - ret += (c - 'a' + 'A'); - else - ret += c; - return ret; -} - -template<typename F> typename pstring_t<F>::size_type pstring_t<F>::find_first_not_of(const pstring_t &no) const { size_type pos = 0; @@ -150,114 +129,6 @@ typename pstring_t<F>::size_type pstring_t<F>::find(code_t search, size_type sta return find(ss, start); } - -template<typename F> -pstring_t<F> pstring_t<F>::replace_all(const pstring_t &search, const pstring_t &replace) const -{ - pstring_t ret; - const size_type slen = search.length(); - - size_type last_s = 0; - size_type s = find(search, last_s); - while (s != npos) - { - ret += substr(last_s, s - last_s); - ret += replace; - last_s = s + slen; - s = find(search, last_s); - } - ret += substr(last_s); - return ret; -} - -template<typename F> -pstring_t<F> pstring_t<F>::rpad(const pstring_t &ws, const size_type cnt) const -{ - // FIXME: pstringbuffer ret(*this); - - pstring_t ret(*this); - size_type wsl = ws.length(); - for (auto i = ret.length(); i < cnt; i+=wsl) - ret += ws; - return ret; -} - -static double pstod(const pstring_t<pu8_traits> &str, std::size_t *e) -{ - return std::stod(str.cpp_string(), e); -} - -static double pstod(const pstring &str, std::size_t *e) -{ - return std::stod(str.cpp_string(), e); -} - -static double pstod(const pwstring &str, std::size_t *e) -{ - return std::stod(str.cpp_string(), e); -} - -static double pstod(const pu16string &str, std::size_t *e) -{ - pstring c; - c = str; - return std::stod(c.cpp_string(), e); -} - -static long pstol(const pstring_t<pu8_traits> &str, std::size_t *e, int base = 10) -{ - return std::stol(str.cpp_string(), e, base); -} - -static long pstol(const pstring &str, std::size_t *e, int base = 10) -{ - return std::stol(str.cpp_string(), e, base); -} - -static long pstol(const pwstring &str, std::size_t *e, int base = 10) -{ - return std::stol(str.cpp_string(), e, base); -} - -static long pstol(const pu16string &str, std::size_t *e, int base = 10) -{ - pstring c; - c = str; - return std::stol(c.cpp_string(), e, base); -} - -template<typename F> -double pstring_t<F>::as_double(bool *error) const -{ - std::size_t e = 0; - if (error != nullptr) - *error = false; - double ret = pstod(*this, &e); - if (e != mem_t_size()) - if (error != nullptr) - *error = true; - return ret; -} - -template<typename F> -long pstring_t<F>::as_long(bool *error) const -{ - static pstring_t prefix(pstring("0x")); - long ret; - std::size_t e = 0; - - if (error != nullptr) - *error = false; - if (startsWith(prefix)) - ret = pstol(substr(2), &e, 16); - else - ret = pstol(*this, &e, 10); - if (e != mem_t_size()) - if (error != nullptr) - *error = true; - return ret; -} - // ---------------------------------------------------------------------------------------- // template stuff ... // ---------------------------------------------------------------------------------------- diff --git a/src/lib/netlist/plib/pstring.h b/src/lib/netlist/plib/pstring.h index cabce0e7b93..c4caeab8e8f 100644 --- a/src/lib/netlist/plib/pstring.h +++ b/src/lib/netlist/plib/pstring.h @@ -7,45 +7,50 @@ #ifndef PSTRING_H_ #define PSTRING_H_ -#include <iterator> +#include "ptypes.h" + +#include <cstring> #include <exception> +#include <iterator> +#include <limits> +#include <stdexcept> #include <string> +#include <type_traits> // ---------------------------------------------------------------------------------------- // pstring: semi-immutable strings ... // // The only reason this class exists is the absence of support for multi-byte -// strings in std:: which I would consider usuable for the use-cases I encounter. +// strings in std:: which I would consider sub-optimal for the use-cases I encounter. // ---------------------------------------------------------------------------------------- +// enable this to use std::string instead of pstring globally. + +#define PSTRING_USE_STD_STRING (0) + template <typename T> class pstring_const_iterator final { public: - typedef typename T::ref_value_type value_type; + using value_type = typename T::ref_value_type; - typedef value_type const *pointer; - typedef value_type const &reference; - typedef std::ptrdiff_t difference_type; - typedef std::forward_iterator_tag iterator_category; - typedef typename T::string_type string_type; - typedef typename T::traits_type traits_type; + using pointer = value_type const *; + using reference = value_type const &; + using difference_type = std::ptrdiff_t; + using iterator_category = std::forward_iterator_tag; + using string_type = typename T::string_type; + using traits_type = typename T::traits_type; - pstring_const_iterator() noexcept : p() { } + constexpr pstring_const_iterator() noexcept : p() { } explicit constexpr pstring_const_iterator(const typename string_type::const_iterator &x) noexcept : p(x) { } -#if !defined(_MSC_VER) || !defined(_ITERATOR_DEBUG_LEVEL) || (0 == _ITERATOR_DEBUG_LEVEL) // debug iterators are broken - pstring_const_iterator(const pstring_const_iterator &rhs) noexcept = default; - pstring_const_iterator(pstring_const_iterator &&rhs) noexcept = default; - pstring_const_iterator &operator=(const pstring_const_iterator &rhs) noexcept = default; - pstring_const_iterator &operator=(pstring_const_iterator &&rhs) noexcept = default; -#endif pstring_const_iterator& operator++() noexcept { p += static_cast<difference_type>(traits_type::codelen(&(*p))); return *this; } - pstring_const_iterator operator++(int) noexcept { pstring_const_iterator tmp(*this); operator++(); return tmp; } + // NOLINTNEXTLINE(cert-dcl21-cpp) + pstring_const_iterator operator++(int) & noexcept { pstring_const_iterator tmp(*this); operator++(); return tmp; } - bool operator==(const pstring_const_iterator& rhs) const noexcept { return p == rhs.p; } - bool operator!=(const pstring_const_iterator& rhs) const noexcept { return p != rhs.p; } + constexpr bool operator==(const pstring_const_iterator& rhs) const noexcept { return p == rhs.p; } + constexpr bool operator!=(const pstring_const_iterator& rhs) const noexcept { return p != rhs.p; } reference operator*() const noexcept { return *reinterpret_cast<pointer>(&(*p)); } pointer operator->() const noexcept { return reinterpret_cast<pointer>(&(*p)); } @@ -60,18 +65,21 @@ template <typename F> struct pstring_t { public: - typedef F traits_type; + using traits_type = F; - typedef typename traits_type::mem_t mem_t; - typedef typename traits_type::code_t code_t; - typedef std::size_t size_type; - typedef std::ptrdiff_t difference_type; - typedef typename traits_type::string_type string_type; + using mem_t = typename traits_type::mem_t; + using code_t = typename traits_type::code_t; + using value_type = typename traits_type::code_t; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using string_type = typename traits_type::string_type; - class ref_value_type final + // FIXME: this is ugly + struct ref_value_type final { public: ref_value_type() = delete; + ~ref_value_type() = delete; ref_value_type(const ref_value_type &) = delete; ref_value_type(ref_value_type &&) = delete; ref_value_type &operator=(const ref_value_type &) = delete; @@ -80,37 +88,27 @@ public: private: const mem_t m; }; - typedef const ref_value_type& const_reference; - typedef const_reference reference; - - enum enc_t - { - UTF8, - UTF16 - }; + using const_reference = const ref_value_type &; + using reference = const_reference; // simple construction/destruction - pstring_t() - { - } - ~pstring_t() - { - } + pstring_t() = default; + ~pstring_t() noexcept = default; // FIXME: Do something with encoding - pstring_t(const mem_t *string, const enc_t enc) + pstring_t(const mem_t *string) : m_str(string) { } - pstring_t(const mem_t *string, const size_type len, const enc_t enc) + pstring_t(const mem_t *string, const size_type len) : m_str(string, len) { } template<typename C, std::size_t N, class = typename std::enable_if<std::is_same<C, const mem_t>::value>::type> - pstring_t(C (&string)[N]) + pstring_t(C (&string)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) { static_assert(N > 0,"pstring from array of length 0"); if (string[N-1] != 0) @@ -118,17 +116,15 @@ public: m_str.assign(string, N - 1); } - pstring_t(const pstring_t &string) - : m_str(string.m_str) - { } - explicit pstring_t(const string_type &string, const enc_t enc) + explicit pstring_t(const string_type &string) : m_str(string) { } - pstring_t(pstring_t &&string) - : m_str(string.m_str) - { } + pstring_t(const pstring_t &string) = default; + pstring_t(pstring_t &&string) noexcept = default; + pstring_t &operator=(const pstring_t &string) = default; + pstring_t &operator=(pstring_t &&string) noexcept = default; explicit pstring_t(code_t code) { @@ -144,7 +140,8 @@ public: *this += static_cast<code_t>(c); // FIXME: codepage conversion for u8 } - pstring_t &operator=(const pstring_t &string) { m_str = string.m_str; return *this; } + operator string_type () const { return m_str; } + template <typename T, class = typename std::enable_if<!std::is_same<T, pstring_t::traits_type>::value>::type> @@ -157,8 +154,8 @@ public: } // no non-const const_iterator for now - typedef pstring_const_iterator<pstring_t> iterator; - typedef pstring_const_iterator<pstring_t> const_iterator; + using iterator = pstring_const_iterator<pstring_t<F> >; + using const_iterator = pstring_const_iterator<pstring_t<F> >; iterator begin() { return iterator(m_str.begin()); } iterator end() { return iterator(m_str.end()); } @@ -201,67 +198,26 @@ public: const_reference at(const size_type pos) const { return *reinterpret_cast<const ref_value_type *>(F::nthcode(m_str.c_str(),pos)); } - /* The following is not compatible to std::string */ - - bool equals(const pstring_t &string) const { return (compare(string) == 0); } - - bool startsWith(const pstring_t &arg) const { return arg.mem_t_size() > mem_t_size() ? false : m_str.compare(0, arg.mem_t_size(), arg.m_str) == 0; } - bool endsWith(const pstring_t &arg) const { return arg.mem_t_size() > mem_t_size() ? false : m_str.compare(mem_t_size()-arg.mem_t_size(), arg.mem_t_size(), arg.m_str) == 0; } - - pstring_t replace_all(const pstring_t &search, const pstring_t &replace) const; - pstring_t cat(const pstring_t &s) const { return *this + s; } - pstring_t cat(code_t c) const { return *this + c; } - - // conversions - - double as_double(bool *error = nullptr) const; - long as_long(bool *error = nullptr) const; - /* the following are extensions to <string> */ size_type mem_t_size() const { return m_str.size(); } - pstring_t left(size_type len) const { return substr(0, len); } - pstring_t right(size_type nlen) const - { - return nlen >= length() ? *this : substr(length() - nlen, nlen); - } - - pstring_t ltrim(const pstring_t &ws = pstring_t(" \t\n\r")) const - { - return substr(find_first_not_of(ws)); - } - - pstring_t rtrim(const pstring_t &ws = pstring_t(" \t\n\r")) const - { - auto f = find_last_not_of(ws); - return f == npos ? pstring_t() : substr(0, f + 1); - } - - pstring_t trim(const pstring_t &ws = pstring_t(" \t\n\r")) const { return this->ltrim(ws).rtrim(ws); } - - pstring_t rpad(const pstring_t &ws, const size_type cnt) const; - - pstring_t ucase() const; - const string_type &cpp_string() const { return m_str; } - static const size_type npos = static_cast<size_type>(-1); - -protected: - string_type m_str; + static constexpr const size_type npos = static_cast<size_type>(-1); private: + string_type m_str; }; struct pu8_traits { - typedef char mem_t; - typedef char code_t; - typedef std::string string_type; + using mem_t = char; + using code_t = char; + using string_type = std::string; static std::size_t len(const string_type &p) { return p.size(); } - static std::size_t codelen(const mem_t *p) { return 1; } - static std::size_t codelen(const code_t c) { return 1; } + static std::size_t codelen(const mem_t *p) { plib::unused_var(p); return 1; } + static std::size_t codelen(const code_t c) { plib::unused_var(c); return 1; } static code_t code(const mem_t *p) { return *p; } static void encode(const code_t c, string_type &s) { s += static_cast<mem_t>(c); } static const mem_t *nthcode(const mem_t *p, const std::size_t n) { return &(p[n]); } @@ -270,9 +226,9 @@ struct pu8_traits /* No checking, this may deliver invalid codes */ struct putf8_traits { - typedef char mem_t; - typedef char32_t code_t; - typedef std::string string_type; + using mem_t = char; + using code_t = char32_t; + using string_type = std::string; static std::size_t len(const string_type &p) { std::size_t ret = 0; @@ -285,7 +241,7 @@ struct putf8_traits } static std::size_t codelen(const mem_t *p) { - const unsigned char *p1 = reinterpret_cast<const unsigned char *>(p); + const auto p1 = reinterpret_cast<const unsigned char *>(p); if ((*p1 & 0x80) == 0x00) return 1; else if ((*p1 & 0xE0) == 0xC0) @@ -312,7 +268,7 @@ struct putf8_traits } static code_t code(const mem_t *p) { - const unsigned char *p1 = reinterpret_cast<const unsigned char *>(p); + const auto p1 = reinterpret_cast<const unsigned char *>(p); if ((*p1 & 0x80) == 0x00) return *p1; else if ((*p1 & 0xE0) == 0xC0) @@ -361,9 +317,9 @@ struct putf8_traits struct putf16_traits { - typedef char16_t mem_t; - typedef char32_t code_t; - typedef std::u16string string_type; + using mem_t = char16_t; + using code_t = char32_t; + using string_type = std::u16string; static std::size_t len(const string_type &p) { std::size_t ret = 0; @@ -371,7 +327,7 @@ struct putf16_traits while (i != p.end()) { // FIXME: check that size is equal - uint16_t c = static_cast<uint16_t>(*i++); + auto c = static_cast<uint16_t>(*i++); if (!((c & 0xd800) == 0xd800)) ret++; } @@ -379,7 +335,7 @@ struct putf16_traits } static std::size_t codelen(const mem_t *p) { - uint16_t c = static_cast<uint16_t>(*p); + auto c = static_cast<uint16_t>(*p); return ((c & 0xd800) == 0xd800) ? 2 : 1; } static std::size_t codelen(const code_t c) @@ -391,7 +347,7 @@ struct putf16_traits } static code_t code(const mem_t *p) { - uint32_t c = static_cast<uint32_t>(*p++); + auto c = static_cast<uint32_t>(*p++); if ((c & 0xd800) == 0xd800) { c = (c - 0xd800) << 10; @@ -401,7 +357,7 @@ struct putf16_traits } static void encode(code_t c, string_type &s) { - uint32_t cu = static_cast<uint32_t>(c); + auto cu = static_cast<uint32_t>(c); if (c > 0xffff) { //make a surrogate pair uint32_t t = ((cu - 0x10000) >> 10) + 0xd800; @@ -425,9 +381,9 @@ struct putf16_traits struct pwchar_traits { - typedef wchar_t mem_t; - typedef char32_t code_t; - typedef std::wstring string_type; + using mem_t = wchar_t; + using code_t = char32_t; + using string_type = std::wstring; static std::size_t len(const string_type &p) { if (sizeof(wchar_t) == 2) @@ -437,7 +393,7 @@ struct pwchar_traits while (i != p.end()) { // FIXME: check that size is equal - uint32_t c = static_cast<uint32_t>(*i++); + auto c = static_cast<uint32_t>(*i++); if (!((c & 0xd800) == 0xd800)) ret++; } @@ -451,7 +407,7 @@ struct pwchar_traits { if (sizeof(wchar_t) == 2) { - uint16_t c = static_cast<uint16_t>(*p); + auto c = static_cast<uint16_t>(*p); return ((c & 0xd800) == 0xd800) ? 2 : 1; } else @@ -470,7 +426,7 @@ struct pwchar_traits { if (sizeof(wchar_t) == 2) { - uint32_t c = static_cast<uint32_t>(*p++); + auto c = static_cast<uint32_t>(*p++); if ((c & 0xd800) == 0xd800) { c = (c - 0xd800) << 10; @@ -486,7 +442,7 @@ struct pwchar_traits { if (sizeof(wchar_t) == 2) { - uint32_t cu = static_cast<uint32_t>(c); + auto cu = static_cast<uint32_t>(c); if (c > 0xffff) { //make a surrogate pair uint32_t t = ((cu - 0x10000) >> 10) + 0xd800; @@ -519,41 +475,280 @@ extern template struct pstring_t<putf8_traits>; extern template struct pstring_t<putf16_traits>; extern template struct pstring_t<pwchar_traits>; -typedef pstring_t<putf8_traits> pstring; -typedef pstring_t<putf16_traits> pu16string; -typedef pstring_t<pwchar_traits> pwstring; +#if (PSTRING_USE_STD_STRING) +typedef std::string pstring; +#else +using pstring = pstring_t<putf8_traits>; +#endif +using putf8string = pstring_t<putf8_traits>; +using pu16string = pstring_t<putf16_traits>; +using pwstring = pstring_t<pwchar_traits>; namespace plib { + template<class T> + struct string_info + { + using mem_t = typename T::mem_t; + }; + + template<> + struct string_info<std::string> + { + using mem_t = char; + }; + template<typename T> pstring to_string(const T &v) { - return pstring(std::to_string(v), pstring::UTF8); + return pstring(std::to_string(v)); } template<typename T> pwstring to_wstring(const T &v) { - return pwstring(std::to_wstring(v), pwstring::UTF16); + return pwstring(std::to_wstring(v)); + } + + template <typename T, typename E = void> + struct pstonum_helper; + + template<typename T> + struct pstonum_helper<T, typename std::enable_if<std::is_integral<T>::value + && std::is_signed<T>::value>::type> + { + template <typename S> + long long operator()(const S &arg, std::size_t *idx) + { + return std::stoll(arg, idx); + } + }; + + template<typename T> + struct pstonum_helper<T, typename std::enable_if<std::is_integral<T>::value + && !std::is_signed<T>::value>::type> + { + template <typename S> + unsigned long long operator()(const S &arg, std::size_t *idx) + { + return std::stoull(arg, idx); + } + }; + + template<typename T> + struct pstonum_helper<T, typename std::enable_if<std::is_floating_point<T>::value>::type> + { + template <typename S> + long double operator()(const S &arg, std::size_t *idx) + { + return std::stold(arg, idx); + } + }; + + template<typename T, typename S> + T pstonum(const S &arg) + { + decltype(arg.c_str()) cstr = arg.c_str(); + std::size_t idx(0); + auto ret = pstonum_helper<T>()(cstr, &idx); + using ret_type = decltype(ret); + if (ret >= static_cast<ret_type>(std::numeric_limits<T>::lowest()) + && ret <= static_cast<ret_type>(std::numeric_limits<T>::max())) + //&& (ret == T(0) || std::abs(ret) >= std::numeric_limits<T>::min() )) + { + if (cstr[idx] != 0) + throw std::invalid_argument(std::string("Continuation after numeric value ends: ") + cstr); + } + else + { + throw std::out_of_range(std::string("Out of range: ") + cstr); + } + return static_cast<T>(ret); + } + + template<typename R, typename T> + R pstonum_ne(const T &str, bool &err) noexcept + { + try + { + err = false; + return pstonum<R>(str); + } + catch (...) + { + err = true; + return R(0); + } + } + + template<typename T> + typename T::size_type find_first_not_of(const T &str, const T &no) + { + typename T::size_type pos = 0; + for (auto it = str.begin(); it != str.end(); ++it, ++pos) + { + bool f = true; + for (typename T::value_type const jt : no) + { + if (*it == jt) + { + f = false; + break; + } + } + if (f) + return pos; + } + return T::npos; + } + + template<typename T> + typename T::size_type find_last_not_of(const T &str, const T &no) + { + /* FIXME: reverse iterator */ + typename T::size_type last_found = T::npos; + typename T::size_type pos = 0; + for (auto it = str.begin(); it != str.end(); ++it, ++pos) + { + bool f = true; + for (typename T::value_type const jt : no) + { + if (*it == jt) + { + f = false; + break; + } + } + if (f) + last_found = pos; + } + return last_found; + } + + template<typename T> + T ltrim(const T &str, const T &ws = T(" \t\n\r")) + { + auto f = find_first_not_of(str, ws); + return (f == T::npos) ? T() : str.substr(f); } -} + + template<typename T> + T rtrim(const T &str, const T &ws = T(" \t\n\r")) + { + auto f = find_last_not_of(str, ws); + return (f == T::npos) ? T() : str.substr(0, f + 1); + } + + template<typename T> + T trim(const T &str, const T &ws = T(" \t\n\r")) + { + return rtrim(ltrim(str, ws), ws); + } + + template<typename T> + T left(const T &str, typename T::size_type len) + { + return str.substr(0, len); + } + + template<typename T> + T right(const T &str, typename T::size_type nlen) + { + return nlen >= str.length() ? str : str.substr(str.length() - nlen, nlen); + } + + template<typename T> + bool startsWith(const T &str, const T &arg) + { + return (arg == left(str, arg.length())); + } + + template<typename T> + bool endsWith(const T &str, const T &arg) + { + return (right(str, arg.length()) == arg); + } + + template<typename T> + bool startsWith(const T &str, const char *arg) + { + return (left(str, std::strlen(arg)) == arg); + } + + template<typename T> + bool endsWith(const T &str, const char *arg) + { + return (right(str, std::strlen(arg)) == arg); + } + + template<typename T> + T ucase(const T &str) + { + T ret; + for (const auto &c : str) + if (c >= 'a' && c <= 'z') + ret += (c - 'a' + 'A'); + else + ret += c; + return ret; + } + + template<typename T> + T rpad(const T &str, const T &ws, const typename T::size_type cnt) + { + // FIXME: pstringbuffer ret(*this); + + T ret(str); + typename T::size_type wsl = ws.length(); + for (auto i = ret.length(); i < cnt; i+=wsl) + ret += ws; + return ret; + } + + template<typename T> + T replace_all(const T &str, const T &search, const T &replace) + { + T ret; + const typename T::size_type slen = search.length(); + + typename T::size_type last_s = 0; + typename T::size_type s = str.find(search, last_s); + while (s != T::npos) + { + ret += str.substr(last_s, s - last_s); + ret += replace; + last_s = s + slen; + s = str.find(search, last_s); + } + ret += str.substr(last_s); + return ret; + } + + template<typename T, typename T1, typename T2> + T replace_all(const T &str, const T1 &search, const T2 &replace) + { + return replace_all(str, static_cast<T>(search), static_cast<T>(replace)); + } + +} // namespace plib // custom specialization of std::hash can be injected in namespace std namespace std { + template<typename T> struct hash<pstring_t<T>> { - typedef pstring_t<T> argument_type; - typedef std::size_t result_type; + using argument_type = pstring_t<T>; + using result_type = std::size_t; result_type operator()(argument_type const& s) const { - const pstring::mem_t *string = s.c_str(); + const typename argument_type::mem_t *string = s.c_str(); result_type result = 5381; - for (pstring::mem_t c = *string; c != 0; c = *string++) + for (typename argument_type::mem_t c = *string; c != 0; c = *string++) result = ((result << 5) + result ) ^ (result >> (32 - 5)) ^ static_cast<result_type>(c); return result; } }; -} +} // namespace std #endif /* PSTRING_H_ */ diff --git a/src/lib/netlist/plib/ptime.h b/src/lib/netlist/plib/ptime.h new file mode 100644 index 00000000000..32ccc4f7b0d --- /dev/null +++ b/src/lib/netlist/plib/ptime.h @@ -0,0 +1,136 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud +/* + * ptime.h + */ + +#ifndef PTIME_H_ +#define PTIME_H_ + +#include "pconfig.h" +#include "ptypes.h" + +#include <cstdint> + +// ---------------------------------------------------------------------------------------- +// netlist_time +// ---------------------------------------------------------------------------------------- + +namespace plib +{ + + template <typename TYPE, TYPE RES> + struct ptime final + { + public: + + using internal_type = TYPE; + using mult_type = TYPE; + + constexpr ptime() noexcept : m_time(0) {} + + ~ptime() noexcept = default; + + constexpr ptime(const ptime &rhs) noexcept = default; + constexpr ptime(ptime &&rhs) noexcept = default; + constexpr explicit ptime(const internal_type &time) noexcept : m_time(time) {} + constexpr explicit ptime(internal_type &&time) noexcept : m_time(time) {} + C14CONSTEXPR ptime &operator=(const ptime &rhs) noexcept = default; + C14CONSTEXPR ptime &operator=(ptime &&rhs) noexcept = default; + + constexpr explicit ptime(const double t) = delete; + //: m_time((internal_type) ( t * (double) resolution)) { } + constexpr explicit ptime(const internal_type nom, const internal_type den) noexcept + : m_time(nom * (RES / den)) { } + + C14CONSTEXPR ptime &operator+=(const ptime rhs) noexcept { m_time += rhs.m_time; return *this; } + C14CONSTEXPR ptime &operator-=(const ptime rhs) noexcept { m_time -= rhs.m_time; return *this; } + C14CONSTEXPR ptime &operator*=(const mult_type factor) noexcept { m_time *= static_cast<internal_type>(factor); return *this; } + + friend constexpr const ptime operator-(ptime lhs, const ptime rhs) noexcept + { + return ptime(lhs.m_time - rhs.m_time); + } + + friend constexpr const ptime operator+(ptime lhs, const ptime rhs) noexcept + { + return ptime(lhs.m_time + rhs.m_time); + } + + friend constexpr const ptime operator*(ptime lhs, const mult_type &factor) noexcept + { + return ptime(lhs.m_time * factor); + } + + friend constexpr mult_type operator/(const ptime lhs, const ptime rhs) noexcept + { + return static_cast<mult_type>(lhs.m_time / rhs.m_time); + } + + friend constexpr bool operator<(const ptime lhs, const ptime rhs) noexcept + { + return (lhs.m_time < rhs.m_time); + } + + friend constexpr bool operator>(const ptime lhs, const ptime rhs) noexcept + { + return (rhs < lhs); + } + + friend constexpr bool operator<=(const ptime lhs, const ptime rhs) noexcept + { + return !(lhs > rhs); + } + + friend constexpr bool operator>=(const ptime lhs, const ptime rhs) noexcept + { + return !(lhs < rhs); + } + + friend constexpr bool operator==(const ptime lhs, const ptime rhs) noexcept + { + return lhs.m_time == rhs.m_time; + } + + friend constexpr bool operator!=(const ptime lhs, const ptime rhs) noexcept + { + return !(lhs == rhs); + } + + constexpr internal_type as_raw() const noexcept { return m_time; } + constexpr double as_double() const noexcept + { + return static_cast<double>(m_time) * inv_res; + } + + // for save states .... + C14CONSTEXPR internal_type *get_internaltype_ptr() noexcept { return &m_time; } + + static constexpr ptime from_nsec(const internal_type ns) noexcept { return ptime(ns, UINT64_C(1000000000)); } + static constexpr ptime from_usec(const internal_type us) noexcept { return ptime(us, UINT64_C( 1000000)); } + static constexpr ptime from_msec(const internal_type ms) noexcept { return ptime(ms, UINT64_C( 1000)); } + static constexpr ptime from_sec(const internal_type s) noexcept { return ptime(s, UINT64_C( 1)); } + static constexpr ptime from_hz(const internal_type hz) noexcept { return ptime(1 , hz); } + static constexpr ptime from_raw(const internal_type raw) noexcept { return ptime(raw); } + static constexpr ptime from_double(const double t) noexcept { return ptime(static_cast<internal_type>( t * static_cast<double>(RES)), RES); } + + static constexpr ptime zero() noexcept { return ptime(0, RES); } + static constexpr ptime quantum() noexcept { return ptime(1, RES); } + static constexpr ptime never() noexcept { return ptime(plib::numeric_limits<internal_type>::max(), RES); } + static constexpr internal_type resolution() noexcept { return RES; } + + constexpr internal_type in_nsec() const noexcept { return m_time / (RES / UINT64_C(1000000000)); } + constexpr internal_type in_usec() const noexcept { return m_time / (RES / UINT64_C( 1000000)); } + constexpr internal_type in_msec() const noexcept { return m_time / (RES / UINT64_C( 1000)); } + constexpr internal_type in_sec() const noexcept { return m_time / (RES / UINT64_C( 1)); } + + private: + static constexpr const double inv_res = 1.0 / static_cast<double>(RES); + internal_type m_time; + }; + + +} // namespace plib + + +#endif /* PTIME_H_ */ diff --git a/src/lib/netlist/plib/ptypes.h b/src/lib/netlist/plib/ptypes.h index 0934a86fdf2..bda62099150 100644 --- a/src/lib/netlist/plib/ptypes.h +++ b/src/lib/netlist/plib/ptypes.h @@ -9,10 +9,20 @@ #define PTYPES_H_ #include "pconfig.h" -#include "pstring.h" -#include <type_traits> #include <limits> +#include <string> +#include <type_traits> + +#define COPYASSIGNMOVE(name, def) \ + name(const name &) = def; \ + name(name &&) noexcept = def; \ + name &operator=(const name &) = def; \ + name &operator=(name &&) noexcept = def; + +#define COPYASSIGN(name, def) \ + name(const name &) = def; \ + name &operator=(const name &) = def; \ namespace plib { @@ -25,14 +35,14 @@ namespace plib template<> struct is_integral<INT128> { static constexpr bool value = true; }; template<> struct numeric_limits<UINT128> { - static inline constexpr UINT128 max() + static constexpr UINT128 max() { return ~((UINT128)0); } }; template<> struct numeric_limits<INT128> { - static inline constexpr INT128 max() + static constexpr INT128 max() { return (~((UINT128)0)) >> 1; } @@ -45,56 +55,98 @@ namespace plib struct nocopyassignmove { - protected: - nocopyassignmove() = default; - ~nocopyassignmove() = default; - private: nocopyassignmove(const nocopyassignmove &) = delete; nocopyassignmove(nocopyassignmove &&) = delete; nocopyassignmove &operator=(const nocopyassignmove &) = delete; nocopyassignmove &operator=(nocopyassignmove &&) = delete; + protected: + nocopyassignmove() = default; + ~nocopyassignmove() = default; }; struct nocopyassign { + nocopyassign(const nocopyassign &) = delete; + nocopyassign &operator=(const nocopyassign &) = delete; protected: nocopyassign() = default; ~nocopyassign() = default; - private: - nocopyassign(const nocopyassign &) = delete; - nocopyassign &operator=(const nocopyassign &) = delete; + nocopyassign(nocopyassign &&) = default; + nocopyassign &operator=(nocopyassign &&) = default; }; //============================================================ - // penum - strongly typed enumeration + // Avoid unused variable warnings //============================================================ + template<typename... Ts> + inline void unused_var(Ts&&...) {} - struct penum_base + //============================================================ + // is_pow2 + //============================================================ + template <typename T> + constexpr bool is_pow2(T v) noexcept { - protected: - static int from_string_int(const char *str, const char *x); - static pstring nthstr(int n, const char *str); - }; + static_assert(is_integral<T>::value, "is_pow2 needs integer arguments"); + return !(v & (v-1)); + } + + + //============================================================ + // abs, lcd, gcm + //============================================================ + + template<typename T> + constexpr + typename std::enable_if<std::is_integral<T>::value && std::is_signed<T>::value, T>::type + abs(T v) + { + return v < 0 ? -v : v; + } + + template<typename T> + constexpr + typename std::enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value, T>::type + abs(T v) + { + return v; + } + + template<typename M, typename N> + constexpr typename std::common_type<M, N>::type + gcd(M m, N n) + { + 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"); + + return m == 0 ? plib::abs(n) + : n == 0 ? plib::abs(m) + : gcd(n, m % n); + } + + template<typename M, typename N> + constexpr typename std::common_type<M, N>::type + lcm(M m, N n) + { + 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"); + + return (m != 0 && n != 0) ? (plib::abs(m) / gcd(m, n)) * plib::abs(n) : 0; + } + +} // namespace plib -} - -#define P_ENUM(ename, ...) \ - struct ename : public plib::penum_base { \ - enum E { __VA_ARGS__ }; \ - ename (E v) : m_v(v) { } \ - bool set_from_string (const pstring &s) { \ - static char const *const strings = # __VA_ARGS__; \ - int f = from_string_int(strings, s.c_str()); \ - if (f>=0) { m_v = static_cast<E>(f); return true; } else { return false; } \ - } \ - operator E() const {return m_v;} \ - bool operator==(const ename &rhs) const {return m_v == rhs.m_v;} \ - bool operator==(const E &rhs) const {return m_v == rhs;} \ - const pstring name() const { \ - static char const *const strings = # __VA_ARGS__; \ - return nthstr(static_cast<int>(m_v), strings); \ - } \ - private: E m_v; }; +//============================================================ +// Define a "has member" trait. +//============================================================ +#define PDEFINE_HAS_MEMBER(name, member) \ + template <typename T> class name \ + { \ + template <typename U> static long test(decltype(&U:: member)); \ + template <typename U> static char test(...); \ + public: \ + static constexpr const bool value = sizeof(test<T>(nullptr)) == sizeof(long); \ + } #endif /* PTYPES_H_ */ diff --git a/src/lib/netlist/plib/putil.cpp b/src/lib/netlist/plib/putil.cpp index c34102417ec..b62cbf60865 100644 --- a/src/lib/netlist/plib/putil.cpp +++ b/src/lib/netlist/plib/putil.cpp @@ -2,13 +2,13 @@ // copyright-holders:Couriersud #include "putil.h" -#include "ptypes.h" #include "plists.h" +#include "ptypes.h" -#include <cstdlib> #include <algorithm> -#include <initializer_list> +#include <cstdlib> #include <cstring> +#include <initializer_list> namespace plib { @@ -17,7 +17,7 @@ namespace plib const pstring buildpath(std::initializer_list<pstring> list ) { pstring ret = ""; - for( auto elem : list ) + for( const auto &elem : list ) { if (ret == "") ret = elem; @@ -33,12 +33,12 @@ namespace plib const pstring environment(const pstring &var, const pstring &default_val) { - if (getenv(var.c_str()) == nullptr) + if (std::getenv(var.c_str()) == nullptr) return default_val; else - return pstring(getenv(var.c_str()), pstring::UTF8); + return pstring(std::getenv(var.c_str())); } - } + } // namespace util std::vector<pstring> psplit(const pstring &str, const pstring &onstr, bool ignore_empty) { @@ -64,6 +64,36 @@ namespace plib return ret; } + std::vector<std::string> psplit_r(const std::string &stri, + const std::string &token, + const std::size_t maxsplit) + { + std::string str(stri); + std::vector<std::string> result; + std::size_t splits = 0; + + while(str.size()) + { + std::size_t index = str.rfind(token); + bool found = index!=std::string::npos; + if (found) + splits++; + if ((splits <= maxsplit || maxsplit == 0) && found) + { + result.push_back(str.substr(index+token.size())); + str = str.substr(0, index); + if (str.size()==0) + result.push_back(str); + } + else + { + result.push_back(str); + str = ""; + } + } + return result; + } + std::vector<pstring> psplit(const pstring &str, const std::vector<pstring> &onstrl) { pstring col = ""; @@ -72,7 +102,7 @@ namespace plib auto i = str.begin(); while (i != str.end()) { - std::size_t p = static_cast<std::size_t>(-1); + auto p = static_cast<std::size_t>(-1); for (std::size_t j=0; j < onstrl.size(); j++) { if (std::equal(onstrl[j].begin(), onstrl[j].end(), i)) @@ -92,7 +122,7 @@ namespace plib } else { - pstring::code_t c = *i; + pstring::value_type c = *i; col += c; i++; } @@ -131,31 +161,8 @@ namespace plib return cnt; return -1; } - pstring penum_base::nthstr(int n, const char *str) + std::string penum_base::nthstr(int n, const char *str) { - char buf[64]; - char *bufp = buf; - int cur = 0; - while (*str) - { - if (cur == n) - { - if (*str == ',') - { - *bufp = 0; - return pstring(buf, pstring::UTF8); - } - else if (*str != ' ') - *bufp++ = *str; - } - else - { - if (*str == ',') - cur++; - } - str++; - } - *bufp = 0; - return pstring(buf, pstring::UTF8); + return psplit(str, ",", false)[static_cast<std::size_t>(n)]; } } // namespace plib diff --git a/src/lib/netlist/plib/putil.h b/src/lib/netlist/plib/putil.h index 8d59c0357e2..e8145361d9d 100644 --- a/src/lib/netlist/plib/putil.h +++ b/src/lib/netlist/plib/putil.h @@ -5,27 +5,32 @@ * */ -#ifndef P_UTIL_H_ -#define P_UTIL_H_ +#ifndef PUTIL_H_ +#define PUTIL_H_ #include "pstring.h" -#include <initializer_list> #include <algorithm> -#include <vector> // <<= needed by windows build +#include <initializer_list> +#include <vector> + +#define PSTRINGIFY_HELP(y) # y +#define PSTRINGIFY(x) PSTRINGIFY_HELP(x) + namespace plib { + namespace util { const pstring buildpath(std::initializer_list<pstring> list ); const pstring environment(const pstring &var, const pstring &default_val); - } + } // namespace util namespace container { - template <class C> - bool contains(C &con, const typename C::value_type &elem) + template <class C, class T> + bool contains(C &con, const T &elem) { return std::find(con.begin(), con.end(), elem) != con.end(); } @@ -51,7 +56,51 @@ namespace plib { con.erase(std::remove(con.begin(), con.end(), elem), con.end()); } - } + } // namespace container + + /* May be further specialized .... This is the generic version */ + template <typename T> + struct constants + { + static constexpr T zero() noexcept { return static_cast<T>(0); } + static constexpr T one() noexcept { return static_cast<T>(1); } + static constexpr T two() noexcept { return static_cast<T>(2); } + + /*! + * \brief Electric constant of vacuum + */ + static constexpr T eps_0() noexcept { return static_cast<T>(8.854187817e-12); } + /*! + * \brief Relative permittivity of Silicon dioxide + */ + static constexpr T eps_SiO2() noexcept { return static_cast<T>(3.9); } + /*! + * \brief Relative permittivity of Silicon + */ + static constexpr T eps_Si() noexcept { return static_cast<T>(11.7); } + /*! + * \brief Boltzmann constant + */ + static constexpr T k_b() noexcept { return static_cast<T>(1.38064852e-23); } + /*! + * \brief room temperature (gives VT = 0.02585 at T=300) + */ + static constexpr T T0() noexcept { return static_cast<T>(300); } + /*! + * \brief Elementary charge + */ + static constexpr T Q_e() noexcept { return static_cast<T>(1.6021765314e-19); } + /*! + * \brief Intrinsic carrier concentration in 1/m^3 of Silicon + */ + static constexpr T NiSi() noexcept { return static_cast<T>(1.45e16); } + + template <typename V> + static constexpr const T cast(V &&v) noexcept { return static_cast<T>(v); } + }; + + static_assert(noexcept(constants<double>::one()) == true, "Not evaluated as constexpr"); + template <class C> struct indexed_compare @@ -69,7 +118,41 @@ namespace plib std::vector<pstring> psplit(const pstring &str, const pstring &onstr, bool ignore_empty = false); std::vector<pstring> psplit(const pstring &str, const std::vector<pstring> &onstrl); + std::vector<std::string> psplit_r(const std::string &stri, + const std::string &token, + const std::size_t maxsplit); + + + //============================================================ + // penum - strongly typed enumeration + //============================================================ + + struct penum_base + { + protected: + static int from_string_int(const char *str, const char *x); + static std::string nthstr(int n, const char *str); + }; + +} // namespace plib + +#define P_ENUM(ename, ...) \ + struct ename : public plib::penum_base { \ + enum E { __VA_ARGS__ }; \ + ename (E v) : m_v(v) { } \ + bool set_from_string (const std::string &s) { \ + static char const *const strings = # __VA_ARGS__; \ + int f = from_string_int(strings, s.c_str()); \ + if (f>=0) { m_v = static_cast<E>(f); return true; } else { return false; } \ + } \ + operator E() const {return m_v;} \ + bool operator==(const ename &rhs) const {return m_v == rhs.m_v;} \ + bool operator==(const E &rhs) const {return m_v == rhs;} \ + std::string name() const { \ + static char const *const strings = # __VA_ARGS__; \ + return nthstr(static_cast<int>(m_v), strings); \ + } \ + private: E m_v; }; -} -#endif /* P_UTIL_H_ */ +#endif /* PUTIL_H_ */ diff --git a/src/lib/netlist/plib/vector_ops.h b/src/lib/netlist/plib/vector_ops.h new file mode 100644 index 00000000000..8043c48f61c --- /dev/null +++ b/src/lib/netlist/plib/vector_ops.h @@ -0,0 +1,151 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud +/* + * vector_ops.h + * + * Base vector operations + * + */ + +#ifndef PLIB_VECTOR_OPS_H_ +#define PLIB_VECTOR_OPS_H_ + +#include "pconfig.h" + +#include <algorithm> +#include <cmath> +#include <type_traits> + +#if !defined(__clang__) && !defined(_MSC_VER) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 6)) +#if !(__GNUC__ > 7 || (__GNUC__ == 7 && __GNUC_MINOR__ > 3)) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +#endif +#endif + +namespace plib +{ + template<typename VT, typename T> + void vec_set_scalar(const std::size_t n, VT &v, T && scalar) + { + const typename std::remove_reference<decltype(v[0])>::type s(std::forward<T>(scalar)); + for ( std::size_t i = 0; i < n; i++ ) + v[i] = s; + } + + template<typename VT, typename VS> + void vec_set(const std::size_t n, VT &v, const VS & source) + { + for ( std::size_t i = 0; i < n; i++ ) + v[i] = source[i]; + } + + template<typename T, typename V1, typename V2> + T vec_mult(const std::size_t n, const V1 & v1, const V2 & v2 ) + { + using b8 = T[8]; + PALIGNAS_VECTOROPT() b8 value = {0}; + for (std::size_t i = 0; i < n ; i++ ) + { + value[i & 7] += v1[i] * v2[i]; + } + return value[0] + value[1] + value[2] + value[3] + value[4] + value[5] + value[6] + value[7]; + } + + template<typename T, typename VT> + T vec_mult2(const std::size_t n, const VT &v) + { + using b8 = T[8]; + PALIGNAS_VECTOROPT() b8 value = {0}; + for (std::size_t i = 0; i < n ; i++ ) + { + value[i & 7] += v[i] * v[i]; + } + return value[0] + value[1] + value[2] + value[3] + value[4] + value[5] + value[6] + value[7]; + } + + template<typename T, typename VT> + T vec_sum(const std::size_t n, const VT &v) + { + if (n<8) + { + T value(0); + for (std::size_t i = 0; i < n ; i++ ) + value += v[i]; + + return value; + } + else + { + using b8 = T[8]; + PALIGNAS_VECTOROPT() b8 value = {0}; + for (std::size_t i = 0; i < n ; i++ ) + value[i & 7] += v[i]; + + return ((value[0] + value[1]) + (value[2] + value[3])) + ((value[4] + value[5]) + (value[6] + value[7])); + } + } + + template<typename VV, typename T, typename VR> + void vec_mult_scalar(const std::size_t n, VR & result, const VV & v, T && scalar) + { + const typename std::remove_reference<decltype(v[0])>::type s(std::forward<T>(scalar)); + for ( std::size_t i = 0; i < n; i++ ) + result[i] = s * v[i]; + } + + template<typename VR, typename VV, typename T> + void vec_add_mult_scalar(const std::size_t n, VR & result, const VV & v, T && scalar) + { + const typename std::remove_reference<decltype(v[0])>::type s(std::forward<T>(scalar)); + for ( std::size_t i = 0; i < n; i++ ) + result[i] += s * v[i]; + } + + template<typename T> + void vec_add_mult_scalar_p(const std::size_t n, T * result, const T * v, T scalar) + { + for ( std::size_t i = 0; i < n; i++ ) + result[i] += scalar * v[i]; + } + + template<typename R, typename V> + void vec_add_ip(const std::size_t n, R & result, const V & v) + { + for ( std::size_t i = 0; i < n; i++ ) + result[i] += v[i]; + } + + template<typename VR, typename V1, typename V2> + void vec_sub(const std::size_t n, VR & result, const V1 &v1, const V2 & v2) + { + for ( std::size_t i = 0; i < n; i++ ) + result[i] = v1[i] - v2[i]; + } + + template<typename V, typename T> + void vec_scale(const std::size_t n, V & v, T &&scalar) + { + const typename std::remove_reference<decltype(v[0])>::type s(std::forward<T>(scalar)); + for ( std::size_t i = 0; i < n; i++ ) + v[i] *= s; + } + + template<typename T, typename V> + T vec_maxabs(const std::size_t n, const V & v) + { + T ret = 0.0; + for ( std::size_t i = 0; i < n; i++ ) + ret = std::max(ret, std::abs(v[i])); + + return ret; + } +} // namespace plib + +#if !defined(__clang__) && !defined(_MSC_VER) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 6)) +#if !(__GNUC__ > 7 || (__GNUC__ == 7 && __GNUC_MINOR__ > 3)) +#pragma GCC diagnostic pop +#endif +#endif + +#endif /* PLIB_VECTOR_OPS_H_ */ |