diff options
author | 2019-10-29 19:55:53 +0100 | |
---|---|---|
committer | 2019-10-29 19:55:53 +0100 | |
commit | cac86fb1b4e23602ebf3b84465b687b6301736e3 (patch) | |
tree | 1990e822ff2c8f0ed2d57fd44dd0807562095586 /src/lib/netlist/plib | |
parent | 316ee65978963211783fab69b089ef750f989060 (diff) |
netlist: code maintenance. (nw)
- Removed code no longer used
- Add noexcept where appropriate
- split pparser.[c|h] into ppreprocessor and ptokenizer
- smaller optimizations, e.g. use of std::size_t
- fix lint warnings
Diffstat (limited to 'src/lib/netlist/plib')
-rw-r--r-- | src/lib/netlist/plib/mat_cr.h | 82 | ||||
-rw-r--r-- | src/lib/netlist/plib/palloc.h | 33 | ||||
-rw-r--r-- | src/lib/netlist/plib/parray.h | 16 | ||||
-rw-r--r-- | src/lib/netlist/plib/pchrono.h | 30 | ||||
-rw-r--r-- | src/lib/netlist/plib/pexception.h | 2 | ||||
-rw-r--r-- | src/lib/netlist/plib/pfmtlog.cpp | 8 | ||||
-rw-r--r-- | src/lib/netlist/plib/pfmtlog.h | 2 | ||||
-rw-r--r-- | src/lib/netlist/plib/pfunction.cpp | 4 | ||||
-rw-r--r-- | src/lib/netlist/plib/pfunction.h | 4 | ||||
-rw-r--r-- | src/lib/netlist/plib/plists.h | 38 | ||||
-rw-r--r-- | src/lib/netlist/plib/pmempool.h | 2 | ||||
-rw-r--r-- | src/lib/netlist/plib/pomp.h | 10 | ||||
-rw-r--r-- | src/lib/netlist/plib/poptions.h | 2 | ||||
-rw-r--r-- | src/lib/netlist/plib/pparser.cpp | 919 | ||||
-rw-r--r-- | src/lib/netlist/plib/pparser.h | 318 | ||||
-rw-r--r-- | src/lib/netlist/plib/ppreprocessor.cpp | 628 | ||||
-rw-r--r-- | src/lib/netlist/plib/ppreprocessor.h | 173 | ||||
-rw-r--r-- | src/lib/netlist/plib/ptokenizer.cpp | 301 | ||||
-rw-r--r-- | src/lib/netlist/plib/ptokenizer.h | 169 | ||||
-rw-r--r-- | src/lib/netlist/plib/putil.cpp | 4 | ||||
-rw-r--r-- | src/lib/netlist/plib/putil.h | 47 | ||||
-rw-r--r-- | src/lib/netlist/plib/vector_ops.h | 24 |
22 files changed, 1446 insertions, 1370 deletions
diff --git a/src/lib/netlist/plib/mat_cr.h b/src/lib/netlist/plib/mat_cr.h index b21c53671a2..3a6c59f24ab 100644 --- a/src/lib/netlist/plib/mat_cr.h +++ b/src/lib/netlist/plib/mat_cr.h @@ -27,9 +27,6 @@ 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 pmatrix_cr_t { @@ -51,9 +48,9 @@ namespace plib parray<index_type, NSQ> col_idx; // column index array nz_num, initially (n * n) parray<value_type, NSQ> A; // Matrix elements nz_num, initially (n * n) - index_type nz_num; + std::size_t nz_num; - explicit pmatrix_cr_t(const index_type n) + explicit pmatrix_cr_t(std::size_t n) : diag(n) , row_idx(n+1) , col_idx(n*n) @@ -63,7 +60,7 @@ namespace plib , nzbd(n) , m_size(n) { - for (index_type i=0; i<n+1; i++) + for (std::size_t i=0; i<n+1; i++) { row_idx[i] = 0; } @@ -71,22 +68,22 @@ namespace plib ~pmatrix_cr_t() = default; - constexpr index_type size() const { return static_cast<index_type>((N>0) ? N : m_size); } + constexpr std::size_t size() const noexcept { return (N>0) ? static_cast<std::size_t>(N) : m_size; } - void clear() + void clear() noexcept { nz_num = 0; - for (index_type i=0; i < size() + 1; i++) + for (std::size_t i=0; i < size() + 1; i++) row_idx[i] = 0; } - void set_scalar(const T scalar) + void set_scalar(T scalar) noexcept { - for (index_type i=0, e=nz_num; i<e; i++) + for (std::size_t i=0, e=nz_num; i<e; i++) A[i] = scalar; } - void set(C r, C c, T val) + void set(C r, C c, T val) noexcept { C ri = row_idx[r]; while (ri < row_idx[r+1] && col_idx[ri] < c) @@ -148,18 +145,18 @@ namespace plib } template <typename VTV, typename VTR> - void mult_vec(VTR & res, const VTV & x) + void mult_vec(VTR & res, const VTV & x) const noexcept { /* * res = A * x */ #if 0 //plib::omp::set_num_threads(4); - plib::omp::for_static(0, constants<index_type>::zero(), m_size, [this, &res, &x](index_type row) + plib::omp::for_static(0, constants<std::size_t>::zero(), m_size, [this, &res, &x](std::size_t row) { T tmp(0.0); - const index_type e(row_idx[row+1]); - for (index_type k = row_idx[row]; k < e; k++) + const std::size_t e(row_idx[row+1]); + for (std::size_t k = row_idx[row]; k < e; k++) tmp += A[k] * x[col_idx[k]]; res[row] = tmp; }); @@ -181,7 +178,7 @@ namespace plib /* throws error if P(source)>P(destination) */ template <typename LUMAT> - void slim_copy_from(LUMAT & src) + void slim_copy_from(LUMAT & src) noexcept { for (std::size_t r=0; r<src.size(); r++) { @@ -203,10 +200,10 @@ namespace plib /* only copies common elements */ template <typename LUMAT> - void reduction_copy_from(LUMAT & src) + void reduction_copy_from(LUMAT & src) noexcept { C sp(0); - for (index_type r=0; r<src.size(); r++) + for (std::size_t r=0; r<src.size(); r++) { C dp(row_idx[r]); while(sp < src.row_idx[r+1]) @@ -227,9 +224,9 @@ namespace plib /* no checks at all - may crash */ template <typename LUMAT> - void raw_copy_from(LUMAT & src) + void raw_copy_from(LUMAT & src) noexcept { - for (index_type k = 0; k < nz_num; k++) + for (std::size_t k = 0; k < nz_num; k++) A[k] = src.A[k]; } @@ -237,7 +234,7 @@ namespace plib parray<std::vector<index_type>, N > nzbd; // Support for gaussian elimination private: //parray<C, N < 0 ? -N * (N-1) / 2 : N * (N+1) / 2 > nzbd; // Support for gaussian elimination - index_type m_size; + std::size_t m_size; }; template<typename B> @@ -248,7 +245,7 @@ namespace plib COPYASSIGNMOVE(pGEmatrix_cr_t, default) - explicit pGEmatrix_cr_t(const index_type n) + explicit pGEmatrix_cr_t(std::size_t n) : B(n) { } @@ -419,10 +416,10 @@ namespace plib void build_parallel_gaussian_execution_scheme(const M &fill) { // calculate parallel scheme for gaussian elimination - std::vector<std::vector<index_type>> rt(base::size()); - for (index_type k = 0; k < base::size(); k++) + std::vector<std::vector<std::size_t>> rt(base::size()); + for (std::size_t k = 0; k < base::size(); k++) { - for (index_type j = k+1; j < base::size(); j++) + for (std::size_t j = k+1; j < base::size(); j++) { if (fill[j][k] < base::FILL_INFINITY) { @@ -431,15 +428,15 @@ namespace plib } } - std::vector<index_type> levGE(base::size(), 0); - index_type cl = 0; + std::vector<std::size_t> levGE(base::size(), 0); + std::size_t cl = 0; - for (index_type k = 0; k < base::size(); k++ ) + for (std::size_t k = 0; k < base::size(); k++ ) { if (levGE[k] >= cl) { - std::vector<index_type> t = rt[k]; - for (index_type j = k+1; j < base::size(); j++ ) + std::vector<std::size_t> t = rt[k]; + for (std::size_t j = k+1; j < base::size(); j++ ) { bool overlap = false; // is there overlap @@ -466,13 +463,12 @@ namespace plib m_ge_par.clear(); m_ge_par.resize(cl+1); - for (index_type k = 0; k < base::size(); k++) + for (std::size_t k = 0; k < base::size(); k++) m_ge_par[levGE[k]].push_back(k); //for (std::size_t k = 0; k < m_ge_par.size(); k++) // printf("%d %d\n", (int) k, (int) m_ge_par[k].size()); } - // contains elimination rows below the diagonal - std::vector<std::vector<index_type>> m_ge_par; // parallel execution support for Gauss + std::vector<std::vector<std::size_t>> m_ge_par; // parallel execution support for Gauss }; template<typename B> @@ -483,7 +479,7 @@ namespace plib COPYASSIGNMOVE(pLUmatrix_cr_t, default) - explicit pLUmatrix_cr_t(const index_type n) + explicit pLUmatrix_cr_t(std::size_t n) : B(n) , ilu_rows(n+1) , m_ILUp(0) @@ -495,7 +491,7 @@ namespace plib template <typename M> void build(M &fill, std::size_t ilup) { - index_type p(0); + std::size_t p(0); /* build ilu_rows */ for (decltype(fill.size()) i=1; i < fill.size(); i++) { @@ -554,7 +550,7 @@ namespace plib else this->reduction_copy_from(mat); - index_type p(0); + std::size_t p(0); while (auto i = ilu_rows[p++]) // NOLINT(bugprone-infinite-loop) { const auto p_i_end = base::row_idx[i + 1]; @@ -567,13 +563,13 @@ namespace plib const auto p_k_end(base::row_idx[k + 1]); const typename base::value_type LUp_i_k = base::A[i_k] = base::A[i_k] / base::A[base::diag[k]]; - index_type k_j(base::diag[k] + 1); - index_type i_j(i_k + 1); + std::size_t k_j(base::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 index_type c_i_j(base::col_idx[i_j]); // row i, column j + const std::size_t c_i_j(base::col_idx[i_j]); // row i, column j const auto c_k_j(base::col_idx[k_j]); // row k, column j if (c_k_j == c_i_j) @@ -610,7 +606,7 @@ namespace plib * This can be solved for x using backwards elimination in U. * */ - for (index_type i = 1; i < base::size(); ++i ) + for (std::size_t i = 1; i < base::size(); ++i ) { typename base::value_type tmp(0); const auto j1(base::row_idx[i]); @@ -621,12 +617,12 @@ namespace plib r[i] -= tmp; } // i now is equal to n; - for (index_type i = base::size(); i-- > 0; ) + for (std::size_t i = base::size(); i-- > 0; ) { typename base::value_type tmp(0); const auto di(base::diag[i]); const auto j2(base::row_idx[i+1]); - for (index_type j = di + 1; j < j2; j++ ) + for (std::size_t j = di + 1; j < j2; j++ ) tmp += base::A[j] * r[base::col_idx[j]]; r[i] = (r[i] - tmp) / base::A[di]; } diff --git a/src/lib/netlist/plib/palloc.h b/src/lib/netlist/plib/palloc.h index aa1aac5544d..5189d86f476 100644 --- a/src/lib/netlist/plib/palloc.h +++ b/src/lib/netlist/plib/palloc.h @@ -36,29 +36,31 @@ namespace plib { 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;} + typename std::enable_if<!X::is_stateless, X&>::type getref(X *x) const noexcept + { 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) + getref(X &x, Y y = nullptr) const noexcept { unused_var(y); return x; } - constexpr arena_deleter(arena_storage_type a = arena_storage_type()) + constexpr arena_deleter(arena_storage_type a = arena_storage_type()) noexcept : m_a(a) { } #if 1 template<typename U, typename = typename std::enable_if<std::is_convertible< U*, T*>::value>::type> - arena_deleter(const arena_deleter<P, U> &rhs) : m_a(rhs.m_a) { } + arena_deleter(const arena_deleter<P, U> &rhs) noexcept + : m_a(rhs.m_a) { } #else template<typename PU, typename U, typename = typename std::enable_if<std::is_convertible< U*, T*>::value>::type> arena_deleter(const arena_deleter<PU, U> &rhs) : m_a(rhs.m_a) { } #endif - void operator()(T *p) //const + void operator()(T *p) noexcept //const { /* call destructor */ p->~T(); @@ -202,19 +204,20 @@ namespace plib { : m_a(arena_type::instance()) { } - ~arena_allocator() noexcept = default; + //~arena_allocator() noexcept = default; arena_allocator(arena_type & a) noexcept : m_a(a) { } template <class U> - arena_allocator(const arena_allocator<ARENA, U, ALIGN>& rhs) + arena_allocator(const arena_allocator<ARENA, U, ALIGN>& rhs) noexcept : m_a(rhs.m_a) { } - template <class U> struct rebind + template <class U> + struct rebind { using other = arena_allocator<ARENA, U, ALIGN>; }; @@ -224,7 +227,7 @@ namespace plib { return reinterpret_cast<T *>(m_a.allocate(ALIGN, sizeof(T) * n)); } - void deallocate(T* p, std::size_t n) + void deallocate(T* p, std::size_t n) noexcept { unused_var(n); m_a.deallocate(p); @@ -234,7 +237,9 @@ namespace plib { 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; + template <class AU, class U, std::size_t A> + friend class arena_allocator; + private: arena_type &m_a; }; @@ -268,7 +273,7 @@ namespace plib { template <typename T> using owned_pool_ptr = plib::owned_ptr<T, arena_deleter<aligned_arena, T>>; - static inline aligned_arena &instance() + static inline aligned_arena &instance() noexcept { static aligned_arena s_arena; return s_arena; @@ -294,7 +299,7 @@ namespace plib { #endif } - static inline void deallocate( void *ptr ) + static inline void deallocate( void *ptr ) noexcept { #if (PUSE_ALIGNED_ALLOCATION) // NOLINTNEXTLINE(cppcoreguidelines-no-malloc) @@ -336,7 +341,7 @@ namespace plib { } } - bool operator ==(const aligned_arena &rhs) const + bool operator ==(const aligned_arena &rhs) const noexcept { plib::unused_var(rhs); return true; @@ -380,7 +385,7 @@ namespace plib { } template<typename T> - inline void pdelete(T *ptr) + inline void pdelete(T *ptr) noexcept { ptr->~T(); aligned_arena::deallocate(ptr); diff --git a/src/lib/netlist/plib/parray.h b/src/lib/netlist/plib/parray.h index d8f7a441f6f..c1196e1e7d4 100644 --- a/src/lib/netlist/plib/parray.h +++ b/src/lib/netlist/plib/parray.h @@ -82,9 +82,20 @@ namespace plib { parray(const parray &rhs) : m_a(rhs.m_a), m_size(rhs.m_size) {} parray(parray &&rhs) noexcept : m_a(std::move(rhs.m_a)), m_size(std::move(rhs.m_size)) {} - parray &operator=(const parray &rhs) { m_a = rhs.m_a; m_size = rhs.m_size; return *this; } + parray &operator=(const parray &rhs) noexcept + { + if (this != &rhs) + { + m_a = rhs.m_a; + m_size = rhs.m_size; + } + return *this; + } + parray &operator=(parray &&rhs) noexcept { std::swap(m_a,rhs.m_a); std::swap(m_size, rhs.m_size); return *this; } + ~parray() noexcept = default; + template <int X = SIZE > parray(size_type size, typename std::enable_if<(X != 0), int>::type = 0) : m_size(size) @@ -137,6 +148,9 @@ namespace plib { } COPYASSIGNMOVE(parray2D, default) + + ~parray2D() noexcept = default; + }; } // namespace plib diff --git a/src/lib/netlist/plib/pchrono.h b/src/lib/netlist/plib/pchrono.h index 4e0bb071431..8eb2e64d358 100644 --- a/src/lib/netlist/plib/pchrono.h +++ b/src/lib/netlist/plib/pchrono.h @@ -35,7 +35,7 @@ namespace plib { struct base_ticks { using ret_type = R; - static ret_type per_second() + static ret_type per_second() noexcept { static ret_type persec = 0; if (persec == 0) @@ -179,9 +179,9 @@ namespace plib { struct counter<false> { using type = uint_least64_t; - constexpr type operator()() const { return 0; } - void inc() const { } - void reset() const { } + constexpr type operator()() const noexcept { return 0; } + void inc() const noexcept { } + void reset() const noexcept { } constexpr static bool enabled = false; }; @@ -212,14 +212,14 @@ namespace plib { type operator()() const { return m_time; } void reset() { m_time = 0; m_count = 0; } - type average() const { return (m_count == 0) ? 0 : m_time / m_count; } - type total() const { return m_time; } - ctype count() const { return m_count; } + type average() const noexcept { return (m_count == 0) ? 0 : m_time / m_count; } + type total() const noexcept { return m_time; } + ctype count() const noexcept { return m_count; } - double as_seconds() const { return static_cast<double>(total()) + double as_seconds() const noexcept { return static_cast<double>(total()) / static_cast<double>(T::per_second()); } - guard_t guard() { return guard_t(*this); } + guard_t guard() noexcept { return guard_t(*this); } private: type m_time; ctype m_count; @@ -242,12 +242,12 @@ namespace plib { ~guard_t() { } }; - constexpr type operator()() const { return 0; } - void reset() const { } - constexpr type average() const { return 0; } - constexpr type total() const { return 0; } - constexpr ctype count() const { return 0; } - constexpr double as_seconds() const { return 0.0; } + constexpr type operator()() const noexcept { return 0; } + void reset() const noexcept { } + constexpr type average() const noexcept { return 0; } + constexpr type total() const noexcept { return 0; } + constexpr ctype count() const noexcept { return 0; } + constexpr double as_seconds() const noexcept { return 0.0; } constexpr static bool enabled = false; guard_t guard() { return guard_t(); } }; diff --git a/src/lib/netlist/plib/pexception.h b/src/lib/netlist/plib/pexception.h index 28a3ac1adf1..e6c350a04b3 100644 --- a/src/lib/netlist/plib/pexception.h +++ b/src/lib/netlist/plib/pexception.h @@ -34,7 +34,7 @@ namespace plib { public: explicit pexception(const pstring &text); - const pstring &text() { return m_text; } + const pstring &text() const noexcept { return m_text; } const char* what() const noexcept override { return m_text.c_str(); } private: diff --git a/src/lib/netlist/plib/pfmtlog.cpp b/src/lib/netlist/plib/pfmtlog.cpp index 250ead34cb3..2158d10cb2d 100644 --- a/src/lib/netlist/plib/pfmtlog.cpp +++ b/src/lib/netlist/plib/pfmtlog.cpp @@ -108,14 +108,14 @@ pfmt::rtype pfmt::setfmt(std::stringstream &strm, char32_t cfmt_spec) auto pdot(fmt.find('.')); if (pdot==0) - strm << std::setprecision(pstonum<int>(fmt.substr(1))); + strm << std::setprecision(pstonum_ne_def<int>(fmt.substr(1), 6)); else if (pdot != pstring::npos) { - strm << std::setprecision(pstonum<int>(fmt.substr(pdot + 1))); - r.width = pstonum<int>(left(fmt,pdot)); + strm << std::setprecision(pstonum_ne_def<int>(fmt.substr(pdot + 1), 6)); + r.width = pstonum_ne_def<int>(left(fmt,pdot), 0); } else if (fmt != "") - r.width = pstonum<int>(fmt); + r.width = pstonum_ne_def<int>(fmt, 0); switch (r.pend) { diff --git a/src/lib/netlist/plib/pfmtlog.h b/src/lib/netlist/plib/pfmtlog.h index 7bf10173857..13ec2396a8a 100644 --- a/src/lib/netlist/plib/pfmtlog.h +++ b/src/lib/netlist/plib/pfmtlog.h @@ -248,7 +248,7 @@ protected: strm << std::forward<T>(val); const pstring ps(strm.str()); pstring pad(""); - std::size_t aw(std::abs(ret.width)); + auto aw(static_cast<std::size_t>(std::abs(ret.width))); if (aw > ps.length()) pad = pstring(aw - ps.length(), ' '); diff --git a/src/lib/netlist/plib/pfunction.cpp b/src/lib/netlist/plib/pfunction.cpp index 6ad2627f0db..e4ea2d57163 100644 --- a/src/lib/netlist/plib/pfunction.cpp +++ b/src/lib/netlist/plib/pfunction.cpp @@ -73,7 +73,7 @@ void pfunction::compile_postfix(const std::vector<pstring> &inputs, { rc.m_cmd = PUSH_CONST; bool err(false); - rc.m_param = plib::pstonum_ne<decltype(rc.m_param), true>(cmd, err); + rc.m_param = plib::pstonum_ne<decltype(rc.m_param)>(cmd, err); if (err) throw plib::pexception(plib::pfmt("pfunction: unknown/misformatted token <{1}> in <{2}>")(cmd)(expr)); stk += 1; @@ -188,7 +188,7 @@ case OP: \ stack[ptr-1] = (EXPR); \ break; -double pfunction::evaluate(const std::vector<double> &values) +double pfunction::evaluate(const std::vector<double> &values) noexcept { std::array<double, 20> stack = { 0 }; unsigned ptr = 0; diff --git a/src/lib/netlist/plib/pfunction.h b/src/lib/netlist/plib/pfunction.h index bc81ef0c5a6..8c6d71f33e4 100644 --- a/src/lib/netlist/plib/pfunction.h +++ b/src/lib/netlist/plib/pfunction.h @@ -91,14 +91,14 @@ namespace plib { * @param values for input variables, e.g. {1.1, 2.2} * @return value of expression */ - double evaluate(const std::vector<double> &values); + double evaluate(const std::vector<double> &values) noexcept; private: void compile_postfix(const std::vector<pstring> &inputs, const std::vector<pstring> &cmds, const pstring &expr); - double lfsr_random() + double lfsr_random() noexcept { std::uint16_t lsb = m_lfsr & 1; m_lfsr >>= 1; diff --git a/src/lib/netlist/plib/plists.h b/src/lib/netlist/plib/plists.h index 4b2b7d41471..7a9e0cb0edb 100644 --- a/src/lib/netlist/plib/plists.h +++ b/src/lib/netlist/plib/plists.h @@ -35,8 +35,17 @@ namespace plib { { public: - using iterator = C *; - using const_iterator = const C *; + typedef C value_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* iterator; + typedef const value_type* const_iterator; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; //uninitialised_array_t() noexcept = default; uninitialised_array_t() noexcept @@ -48,24 +57,24 @@ namespace plib { ~uninitialised_array_t() noexcept { if (m_initialized>=N) - for (std::size_t i=0; i<N; i++) + for (size_type i=0; i<N; i++) (*this)[i].~C(); } - size_t size() const { return N; } + size_t size() const noexcept { return N; } - C& operator[](const std::size_t &index) noexcept + reference operator[](size_type index) noexcept { - return *reinterpret_cast<C *>(&m_buf[index]); + return *reinterpret_cast<pointer>(&m_buf[index]); } - const C& operator[](const std::size_t &index) const noexcept + const_reference operator[](size_type index) const noexcept { - return *reinterpret_cast<const C *>(&m_buf[index]); + return *reinterpret_cast<const_pointer>(&m_buf[index]); } template<typename... Args> - void emplace(const std::size_t index, Args&&... args) + void emplace(size_type index, Args&&... args) { m_initialized++; // allocate on buffer @@ -125,7 +134,14 @@ namespace plib { explicit constexpr iter_t(LC* x) noexcept : p(x) { } constexpr iter_t(iter_t &rhs) noexcept : p(rhs.p) { } iter_t(iter_t &&rhs) noexcept { std::swap(*this, rhs); } - iter_t& operator=(const iter_t &rhs) noexcept { if (this != &rhs) p = rhs.p; return *this; } + + iter_t& operator=(const iter_t &rhs) noexcept + { + if (this != &rhs) + p = rhs.p; + return *this; + } + iter_t& operator=(iter_t &&rhs) noexcept { std::swap(*this, rhs); return *this; } ~iter_t() = default; @@ -386,7 +402,7 @@ namespace plib { const T *listptr() const noexcept { return &m_list[1]; } std::size_t size() const noexcept { return static_cast<std::size_t>(m_end - &m_list[1]); } - const T & operator[](const std::size_t index) const noexcept { return m_list[ 1 + index]; } + const T & operator[](std::size_t index) const noexcept { return m_list[ 1 + index]; } private: using mutex_type = pspin_mutex<TS>; using lock_guard_type = std::lock_guard<mutex_type>; diff --git a/src/lib/netlist/plib/pmempool.h b/src/lib/netlist/plib/pmempool.h index a4ac4fd393f..562b4a15625 100644 --- a/src/lib/netlist/plib/pmempool.h +++ b/src/lib/netlist/plib/pmempool.h @@ -226,7 +226,7 @@ namespace plib { } } - bool operator ==(const mempool &rhs) { return this == &rhs; } + bool operator ==(const mempool &rhs) noexcept { return this == &rhs; } }; diff --git a/src/lib/netlist/plib/pomp.h b/src/lib/netlist/plib/pomp.h index 79fa0f4bf9b..26e037bca1d 100644 --- a/src/lib/netlist/plib/pomp.h +++ b/src/lib/netlist/plib/pomp.h @@ -22,7 +22,7 @@ namespace plib { namespace omp { template <typename I, class T> -void for_static(std::size_t numops, const I start, const I end, const T &what) +void for_static(std::size_t numops, const I start, const I end, const T &what) noexcept(noexcept(what)) { if (numops>1000) { @@ -38,7 +38,7 @@ void for_static(std::size_t numops, const I start, const I end, const T &what) } template <typename I, class T> -void for_static(const I start, const I end, const T &what) +void for_static(const I start, const I end, const T &what) noexcept(noexcept(what)) { #if PHAS_OPENMP && PUSE_OPENMP #pragma omp parallel for schedule(static) @@ -48,14 +48,14 @@ void for_static(const I start, const I end, const T &what) } template <typename I, class T> -void for_static_np(const I start, const I end, const T &what) +void for_static_np(const I start, const I end, const T &what) noexcept(noexcept(what)) { for (I i = start; i < end; i++) what(i); } -inline void set_num_threads(const std::size_t threads) +inline void set_num_threads(const std::size_t threads) noexcept { #if PHAS_OPENMP && PUSE_OPENMP omp_set_num_threads(threads); @@ -64,7 +64,7 @@ inline void set_num_threads(const std::size_t threads) #endif } -inline std::size_t get_max_threads() +inline std::size_t get_max_threads() noexcept { #if PHAS_OPENMP && PUSE_OPENMP return omp_get_max_threads(); diff --git a/src/lib/netlist/plib/poptions.h b/src/lib/netlist/plib/poptions.h index e3ab42b060f..4a92f721e76 100644 --- a/src/lib/netlist/plib/poptions.h +++ b/src/lib/netlist/plib/poptions.h @@ -185,7 +185,7 @@ protected: int parse(const pstring &argument) override { bool err(false); - m_val = pstonum_ne<T, true>(argument, err); + m_val = pstonum_ne<T>(argument, err); return (err ? 1 : (m_val < m_min || m_val > m_max)); } diff --git a/src/lib/netlist/plib/pparser.cpp b/src/lib/netlist/plib/pparser.cpp deleted file mode 100644 index 3480a8e3bea..00000000000 --- a/src/lib/netlist/plib/pparser.cpp +++ /dev/null @@ -1,919 +0,0 @@ -// license:GPL-2.0+ -// copyright-holders:Couriersud -/* - * pparser.c - * - */ - -#include "pparser.h" -#include "palloc.h" -#include "putil.h" - - -namespace plib { -// ---------------------------------------------------------------------------------------- -// A simple tokenizer -// ---------------------------------------------------------------------------------------- - -pstring ptokenizer::currentline_str() -{ - return m_cur_line; -} - -void ptokenizer::skipeol() -{ - pstring::value_type c = getc(); - while (c) - { - if (c == 10) - { - c = getc(); - if (c != 13) - ungetc(c); - return; - } - c = getc(); - } -} - -pstring::value_type ptokenizer::getc() -{ - if (m_unget != 0) - { - pstring::value_type c = m_unget; - m_unget = 0; - return c; - } - if (m_px == m_cur_line.end()) - { - ++m_source_location.back(); - if (m_strm.readline(m_cur_line)) - m_px = m_cur_line.begin(); - else - return 0; - return '\n'; - } - pstring::value_type c = *(m_px++); - return c; -} - -void ptokenizer::ungetc(pstring::value_type c) -{ - m_unget = c; -} - -void ptokenizer::require_token(const token_id_t &token_num) -{ - require_token(get_token(), token_num); -} - -void ptokenizer::require_token(const token_t &tok, const token_id_t &token_num) -{ - if (!tok.is(token_num)) - { - pstring val(""); - for (auto &i : m_tokens) - if (i.second.id() == token_num.id()) - val = i.first; - error(pfmt("Expected token <{1}> got <{2}>")(val)(tok.str()) ); - } -} - -pstring ptokenizer::get_string() -{ - token_t tok = get_token(); - if (!tok.is_type(STRING)) - { - error(pfmt("Expected a string, got <{1}>")(tok.str()) ); - } - return tok.str(); -} - -pstring ptokenizer::get_identifier() -{ - token_t tok = get_token(); - if (!tok.is_type(IDENTIFIER)) - { - error(pfmt("Expected an identifier, got <{1}>")(tok.str()) ); - } - return tok.str(); -} - -pstring ptokenizer::get_identifier_or_number() -{ - token_t tok = get_token(); - if (!(tok.is_type(IDENTIFIER) || tok.is_type(NUMBER))) - { - error(pfmt("Expected an identifier or number, got <{1}>")(tok.str()) ); - } - return tok.str(); -} - -// FIXME: combine into template -double ptokenizer::get_number_double() -{ - token_t tok = get_token(); - if (!tok.is_type(NUMBER)) - { - error(pfmt("Expected a number, got <{1}>")(tok.str()) ); - } - bool err(false); - auto ret = plib::pstonum_ne<double, true>(tok.str(), err); - if (err) - error(pfmt("Expected a number, got <{1}>")(tok.str()) ); - return ret; -} - -long ptokenizer::get_number_long() -{ - token_t tok = get_token(); - if (!tok.is_type(NUMBER)) - { - error(pfmt("Expected a long int, got <{1}>")(tok.str()) ); - } - bool err(false); - auto ret = plib::pstonum_ne<long, true>(tok.str(), err); - if (err) - error(pfmt("Expected a long int, got <{1}>")(tok.str()) ); - return ret; -} - -ptokenizer::token_t ptokenizer::get_token() -{ - token_t ret = get_token_internal(); - while (true) - { - if (ret.is_type(ENDOFFILE)) - return ret; - else if (m_support_line_markers && ret.is_type(LINEMARKER)) - { - bool benter(false); - bool bexit(false); - pstring file; - unsigned lineno; - - ret = get_token_internal(); - if (!ret.is_type(NUMBER)) - error(pfmt("Expected line number after line marker but got <{1}>")(ret.str()) ); - lineno = pstonum<unsigned>(ret.str()); - ret = get_token_internal(); - if (!ret.is_type(STRING)) - error(pfmt("Expected file name after line marker but got <{1}>")(ret.str()) ); - file = ret.str(); - ret = get_token_internal(); - while (ret.is_type(NUMBER)) - { - if (ret.str() == "1") - benter = true; - if (ret.str() == "2") - bexit = false; - // FIXME: process flags; actually only 1 (file enter) and 2 (after file exit) - ret = get_token_internal(); - } - if (bexit) // pop the last location - m_source_location.pop_back(); - if (!benter) // new location! - m_source_location.pop_back(); - m_source_location.emplace_back(plib::source_location(file, lineno)); - } - else if (ret.is(m_tok_comment_start)) - { - do { - ret = get_token_internal(); - } while (ret.is_not(m_tok_comment_end)); - ret = get_token_internal(); - } - else if (ret.is(m_tok_line_comment)) - { - skipeol(); - ret = get_token_internal(); - } - else - { - return ret; - } - } -} - -ptokenizer::token_t ptokenizer::get_token_internal() -{ - /* skip ws */ - pstring::value_type c = getc(); - while (m_whitespace.find(c) != pstring::npos) - { - c = getc(); - if (eof()) - { - return token_t(ENDOFFILE); - } - } - if (m_support_line_markers && c == '#') - return token_t(LINEMARKER, "#"); - else if (m_number_chars_start.find(c) != pstring::npos) - { - /* read number while we receive number or identifier chars - * treat it as an identifier when there are identifier chars in it - * - */ - token_type ret = NUMBER; - pstring tokstr = ""; - while (true) { - if (m_identifier_chars.find(c) != pstring::npos && m_number_chars.find(c) == pstring::npos) - ret = IDENTIFIER; - else if (m_number_chars.find(c) == pstring::npos) - break; - tokstr += c; - c = getc(); - } - ungetc(c); - return token_t(ret, tokstr); - } - else if (m_identifier_chars.find(c) != pstring::npos) - { - /* read identifier till non identifier char */ - pstring tokstr = ""; - while (m_identifier_chars.find(c) != pstring::npos) - { - tokstr += c; - c = getc(); - } - ungetc(c); - auto id = m_tokens.find(tokstr); - if (id != m_tokens.end()) - return token_t(id->second, tokstr); - else - return token_t(IDENTIFIER, tokstr); - } - else if (c == m_string) - { - pstring tokstr = ""; - c = getc(); - while (c != m_string) - { - tokstr += c; - c = getc(); - } - return token_t(STRING, tokstr); - } - else - { - /* read identifier till first identifier char or ws */ - pstring tokstr = ""; - while ((m_identifier_chars.find(c) == pstring::npos) && (m_whitespace.find(c) == pstring::npos)) - { - tokstr += c; - /* expensive, check for single char tokens */ - if (tokstr.length() == 1) - { - auto id = m_tokens.find(tokstr); - if (id != m_tokens.end()) - return token_t(id->second, tokstr); - } - c = getc(); - } - ungetc(c); - auto id = m_tokens.find(tokstr); - if (id != m_tokens.end()) - return token_t(id->second, tokstr); - else - return token_t(UNKNOWN, tokstr); - } -} - -void ptokenizer::error(const pstring &errs) -{ - pstring s(""); - pstring trail (" from "); - pstring trail_first("In file included from "); - pstring e = plib::pfmt("{1}:{2}:0: error: {3}\n") - (m_source_location.back().file_name(), m_source_location.back().line(), errs); - m_source_location.pop_back(); - while (m_source_location.size() > 0) - { - if (m_source_location.size() == 1) - trail = trail_first; - s = trail + plib::pfmt("{1}:{2}:0\n")(m_source_location.back().file_name(), m_source_location.back().line()) + s; - m_source_location.pop_back(); - } - verror("\n" + s + e + " " + currentline_str() + "\n"); -} - - -// ---------------------------------------------------------------------------------------- -// A simple preprocessor -// ---------------------------------------------------------------------------------------- - -ppreprocessor::ppreprocessor(psource_collection_t<> &sources, defines_map_type *defines) -: std::istream(new readbuffer(this)) -, m_sources(sources) -, m_if_flag(0) -, m_if_level(0) -, m_pos(0) -, m_state(PROCESS) -, m_comment(false) -{ - 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(";"); - 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_expr_sep.emplace_back("\""); - - if (defines != nullptr) - m_defines = *defines; - m_defines.insert({"__PLIB_PREPROCESSOR__", define_t("__PLIB_PREPROCESSOR__", "1")}); - auto idx = m_defines.find("__PREPROCESSOR_DEBUG__"); - m_debug_out = idx != m_defines.end(); - -} - -void ppreprocessor::error(const pstring &err) -{ - pstring s(""); - pstring trail (" from "); - pstring trail_first("In file included from "); - pstring e = plib::pfmt("{1}:{2}:0: error: {3}\n") - (m_stack.back().m_name, m_stack.back().m_lineno, err); - m_stack.pop_back(); - while (m_stack.size() > 0) - { - if (m_stack.size() == 1) - trail = trail_first; - s = trail + plib::pfmt("{1}:{2}:0\n")(m_stack.back().m_name, m_stack.back().m_lineno) + s; - m_stack.pop_back(); - } - throw pexception("\n" + s + e + " " + m_line + "\n"); -} - - - -template <typename PP, typename L = ppreprocessor::string_list> -struct simple_iter -{ - simple_iter(PP *parent, const L &tokens) - : m_tokens(tokens), m_parent(parent), m_pos(0) - {} - - /**! skip white space in token list - * - */ - void skip_ws() - { - while (m_pos < m_tokens.size() && (m_tokens[m_pos] == " " || m_tokens[m_pos] == "\t")) - m_pos++; - } - - /**! return next token skipping white space - * - * @return next token - */ - pstring next() - { - skip_ws(); - if (m_pos >= m_tokens.size()) - error("unexpected end of line"); - return m_tokens[m_pos++]; - } - - /**! return next token including white space - * - * @return next token - */ - pstring next_ws() - { - if (m_pos >= m_tokens.size()) - error("unexpected end of line"); - return m_tokens[m_pos++]; - } - - pstring peek_ws() - { - if (m_pos >= m_tokens.size()) - error("unexpected end of line"); - return m_tokens[m_pos]; - } - - pstring last() - { - if (m_pos == 0) - error("no last token at beginning of line"); - if (m_pos > m_tokens.size()) - error("unexpected end of line"); - return m_tokens[m_pos-1]; - } - - bool eod() - { - return (m_pos >= m_tokens.size()); - } - - void error(pstring err) - { - m_parent->error(err); - } -private: - L m_tokens; - PP *m_parent; - std::size_t m_pos; -}; - -#define CHECKTOK2(p_op, p_prio) \ - else if (tok == # p_op) \ - { \ - if (!has_val) \ - { sexpr.error("parsing error!"); return 1;} \ - if (prio < (p_prio)) \ - return val; \ - sexpr.next(); \ - const auto v2 = prepro_expr(sexpr, (p_prio)); \ - val = (val p_op v2); \ - } \ - -// Operator precedence see https://en.cppreference.com/w/cpp/language/operator_precedence - -template <typename PP> -static int prepro_expr(simple_iter<PP> &sexpr, int prio) -{ - int val(0); - bool has_val(false); - - pstring tok=sexpr.peek_ws(); - if (tok == "(") - { - sexpr.next(); - val = prepro_expr(sexpr, 255); - if (sexpr.next() != ")") - sexpr.error("expected ')'"); - has_val = true; - } - while (!sexpr.eod()) - { - tok = sexpr.peek_ws(); - if (tok == ")") - { - if (!has_val) - sexpr.error("Found ')' but have no value computed"); - else - return val; - } - else if (tok == "!") - { - if (prio < 3) - { - if (!has_val) - sexpr.error("parsing error!"); - else - return val; - } - sexpr.next(); - val = !prepro_expr(sexpr, 3); - has_val = true; - } - CHECKTOK2(*, 5) - CHECKTOK2(/, 5) // NOLINT(clang-analyzer-core.DivideZero) - CHECKTOK2(+, 6) - CHECKTOK2(-, 6) - CHECKTOK2(==, 10) - CHECKTOK2(&&, 14) - CHECKTOK2(||, 15) - else - { - val = plib::pstonum<decltype(val)>(tok); - has_val = true; - sexpr.next(); - } - } - if (!has_val) - sexpr.error("No value computed. Empty expression ?"); - return val; -} - -ppreprocessor::define_t *ppreprocessor::get_define(const pstring &name) -{ - auto idx = m_defines.find(name); - return (idx != m_defines.end()) ? &idx->second : nullptr; -} - -ppreprocessor::string_list ppreprocessor::tokenize(const pstring &str, - const string_list &sep, bool remove_ws, bool concat) -{ - const pstring STR = "\""; - string_list tmpret; - string_list tmp(psplit(str, sep)); - std::size_t pi(0); - - while (pi < tmp.size()) - { - if (tmp[pi] == STR) - { - pstring s(STR); - pi++; - // FIXME : \" - while (pi < tmp.size() && tmp[pi] != STR) - { - s += tmp[pi]; - pi++; - } - s += STR; - tmpret.push_back(s); - } - else - if (!remove_ws || (tmp[pi] != " " && tmp[pi] != "\t")) - tmpret.push_back(tmp[pi]); - pi++; - } - if (!concat) - return tmpret; - else - { - // FIXME: error if concat at beginning or end - string_list ret; - pi = 0; - while (pi<tmpret.size()) - { - if (tmpret[pi] == "##") - { - while (ret.back() == " " || ret.back() == "\t") - ret.pop_back(); - pstring cc = ret.back(); - ret.pop_back(); - pi++; - while (pi < tmpret.size() && (tmpret[pi] == " " || tmpret[pi] == "\t")) - pi++; - if (pi == tmpret.size()) - error("## found at end of sequence"); - ret.push_back(cc + tmpret[pi]); - } - else - ret.push_back(tmpret[pi]); - pi++; - } - return ret; - } -} - -bool ppreprocessor::is_valid_token(const pstring &str) -{ - if (str.length() == 0) - return false; - char c = str.at(0); - return ((c>='a' && c<='z') || (c>='A' && c<='Z') || c == '_'); -} - -pstring ppreprocessor::replace_macros(const pstring &line) -{ - //std::vector<pstring> elems(psplit(line, m_expr_sep)); - bool repeat(false); - pstring tmpret(line); - do - { - repeat = false; - auto elems(simple_iter<ppreprocessor>(this, tokenize(tmpret, m_expr_sep, false, true))); - tmpret = ""; - while (!elems.eod()) - { - auto token(elems.next_ws()); - define_t *def = get_define(token); - if (def == nullptr) - tmpret += token; - else if (!def->m_has_params) - { - tmpret += def->m_replace; - repeat = true; - } - else - { - token = elems.next(); - if (token != "(") - error("expected '(' in macro expansion of " + def->m_name); - string_list rep; - token = elems.next(); - while (token != ")") - { - pstring par(""); - int pcnt(1); - while (true) - { - if (pcnt==1 && token == ",") - { - token = elems.next(); - break; - } - if (token == "(") - pcnt++; - if (token == ")") - if (--pcnt == 0) - break; - par += token; - token = elems.next(); - } - rep.push_back(par); - } - repeat = true; - if (def->m_params.size() != rep.size()) - error(pfmt("Expected {1} parameters, got {2}")(def->m_params.size(), rep.size())); - auto r(simple_iter<ppreprocessor>(this, tokenize(def->m_replace, m_expr_sep, false, false))); - bool stringify_next = false; - while (!r.eod()) - { - pstring token(r.next()); - if (token == "#") - stringify_next = true; - else if (token != " " && token != "\t") - { - for (std::size_t i=0; i<def->m_params.size(); i++) - if (def->m_params[i] == token) - { - if (stringify_next) - { - stringify_next = false; - token = "\"" + rep[i] + "\""; - } - else - token = rep[i]; - break; - } - if (stringify_next) - error("'#' is not followed by a macro parameter"); - tmpret += token; - tmpret += " "; // make sure this is not concatenated with next token - } - else - tmpret += token; - } - } - } - } while (repeat); - - return tmpret; -} - -static pstring catremainder(const std::vector<pstring> &elems, std::size_t start, const pstring &sep) -{ - pstring ret(""); - for (std::size_t i = start; i < elems.size(); i++) - { - ret += elems[i]; - ret += sep; - } - return ret; -} - -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; -} - -std::pair<pstring,bool> ppreprocessor::process_line(pstring line) -{ - 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 {"", false}; - } - else - m_state = PROCESS; - - line = process_comments(m_line); - - pstring lt = plib::trim(plib::replace_all(line, "\t", " ")); - // FIXME ... revise and extend macro handling - if (plib::startsWith(lt, "#")) - { - string_list lti(psplit(lt, " ", true)); - if (lti[0] == "#if") - { - m_if_level++; - lt = replace_macros(lt); - //std::vector<pstring> t(psplit(replace_all(lt.substr(3), " ", ""), m_expr_sep)); - auto t(simple_iter<ppreprocessor>(this, tokenize(lt.substr(3), m_expr_sep, true, true))); - auto val = static_cast<int>(prepro_expr(t, 255)); - t.skip_ws(); - if (!t.eod()) - error("found unprocessed content at end of line"); - if (val == 0) - m_if_flag |= (1 << m_if_level); - } - else if (lti[0] == "#ifdef") - { - m_if_level++; - if (get_define(lti[1]) == nullptr) - m_if_flag |= (1 << m_if_level); - } - else if (lti[0] == "#ifndef") - { - m_if_level++; - if (get_define(lti[1]) != nullptr) - m_if_flag |= (1 << m_if_level); - } - else if (lti[0] == "#else") - { - m_if_flag ^= (1 << m_if_level); - } - else if (lti[0] == "#endif") - { - m_if_flag &= ~(1 << m_if_level); - m_if_level--; - } - else if (lti[0] == "#include") - { - if (m_if_flag == 0) - { - pstring arg(""); - for (std::size_t i=1; i<lti.size(); i++) - arg += (lti[i] + " "); - - arg = plib::trim(arg); - - if (startsWith(arg, "\"") && endsWith(arg, "\"")) - { - arg = arg.substr(1, arg.length() - 2); - /* first try local context */ - auto l(plib::util::buildpath({m_stack.back().m_local_path, arg})); - auto lstrm(m_sources.get_stream<>(l)); - if (lstrm) - { - m_stack.emplace_back(input_context(std::move(lstrm), plib::util::path(l), l)); - } - else - { - auto strm(m_sources.get_stream<>(arg)); - if (strm) - { - m_stack.emplace_back(input_context(std::move(strm), plib::util::path(arg), arg)); - } - else - error("include not found:" + arg); - } - } - else - error("include misspelled:" + arg); - pstring linemarker = pfmt("# {1} \"{2}\" 1\n")(m_stack.back().m_lineno, m_stack.back().m_name); - push_out(linemarker); - } - } - else if (lti[0] == "#pragma") - { - if (m_if_flag == 0 && lti.size() > 3 && lti[1] == "NETLIST") - { - if (lti[2] == "warning") - error("NETLIST: " + catremainder(lti, 3, " ")); - } - } - else if (lti[0] == "#define") - { - if (m_if_flag == 0) - { - if (lti.size() < 2) - error("define needs at least one argument"); - auto args(simple_iter<ppreprocessor>(this, tokenize(lt.substr(8), m_expr_sep, false, false))); - pstring n = args.next(); - if (!is_valid_token(n)) - error("define expected identifier"); - if (args.next_ws() == "(") - { - define_t def(n); - def.m_has_params = true; - auto token(args.next()); - while (true) - { - if (token == ")") - break; - def.m_params.push_back(token); - token = args.next(); - if (token != "," && token != ")") - error(pfmt("expected , or ), found <{1}>")(token)); - if (token == ",") - token = args.next(); - } - pstring r; - while (!args.eod()) - r += args.next_ws(); - def.m_replace = r; - m_defines.insert({n, def}); - } - else - { - pstring r; - while (!args.eod()) - r += args.next_ws(); - m_defines.insert({n, define_t(n, r)}); - } - } - } - else - { - if (m_if_flag == 0) - error("unknown directive"); - } - return { "", false }; - } - else - { - if (m_if_flag == 0) - return { replace_macros(lt), true }; - else - return { "", false }; - } -} - -void ppreprocessor::push_out(pstring s) -{ - m_outbuf += decltype(m_outbuf)(s.c_str()); - if (m_debug_out) - std::cerr << s; -} - - -void ppreprocessor::process_stack() -{ - while (m_stack.size() > 0) - { - pstring line; - pstring linemarker = pfmt("# {1} \"{2}\"\n")(m_stack.back().m_lineno, m_stack.back().m_name); - push_out(linemarker); - bool last_skipped=false; - while (m_stack.back().m_reader.readline(line)) - { - m_stack.back().m_lineno++; - auto r(process_line(line)); - if (r.second) - { - if (last_skipped) - push_out(pfmt("# {1} \"{2}\"\n")(m_stack.back().m_lineno, m_stack.back().m_name)); - push_out(r.first + "\n"); - last_skipped = false; - } - else - last_skipped = true; - } - m_stack.pop_back(); - if (m_stack.size() > 0) - { - linemarker = pfmt("# {1} \"{2}\" 2\n")(m_stack.back().m_lineno, m_stack.back().m_name); - push_out(linemarker); - } - } -} - - - -} // namespace plib diff --git a/src/lib/netlist/plib/pparser.h b/src/lib/netlist/plib/pparser.h deleted file mode 100644 index ed67289dea8..00000000000 --- a/src/lib/netlist/plib/pparser.h +++ /dev/null @@ -1,318 +0,0 @@ -// license:GPL-2.0+ -// copyright-holders:Couriersud -/* - * pparser.h - * - */ - -#ifndef PPARSER_H_ -#define PPARSER_H_ - -#include "plists.h" -#include "pstream.h" -#include "pstring.h" - -#include "putil.h" // psource_t - -//#include <cstdint> -#include <unordered_map> -#include <vector> - -namespace plib { -class ptokenizer -{ -public: - template <typename T> - ptokenizer(T &&strm) // NOLINT(misc-forwarding-reference-overload, bugprone-forwarding-reference-overload) - : m_strm(std::forward<T>(strm)) - , m_cur_line("") - , m_px(m_cur_line.begin()) - , m_unget(0) - , m_string('"') - , m_support_line_markers(true) // FIXME - { - // add a first entry to the stack - m_source_location.emplace_back(plib::source_location("Unknown", 0)); - } - - COPYASSIGNMOVE(ptokenizer, delete) - - virtual ~ptokenizer() = default; - - enum token_type - { - IDENTIFIER, - NUMBER, - TOKEN, - STRING, - COMMENT, - LINEMARKER, - UNKNOWN, - ENDOFFILE - }; - - struct token_id_t - { - public: - - static constexpr std::size_t npos = static_cast<std::size_t>(-1); - - token_id_t() : m_id(npos) {} - explicit token_id_t(const std::size_t id) : m_id(id) {} - std::size_t id() const { return m_id; } - private: - std::size_t m_id; - }; - - struct token_t - { - explicit token_t(token_type type) - : m_type(type), m_id(), m_token("") - { - } - token_t(token_type type, const pstring &str) - : m_type(type), m_id(), m_token(str) - { - } - token_t(const token_id_t &id, const pstring &str) - : m_type(TOKEN), m_id(id), m_token(str) - { - } - - bool is(const token_id_t &tok_id) const { return m_id.id() == tok_id.id(); } - bool is_not(const token_id_t &tok_id) const { return !is(tok_id); } - - bool is_type(const token_type type) const { return m_type == type; } - - pstring str() const { return m_token; } - - private: - token_type m_type; - token_id_t m_id; - pstring m_token; - }; - - pstring currentline_str(); - - /* tokenizer stuff follows ... */ - - token_t get_token(); - pstring get_string(); - pstring get_identifier(); - pstring get_identifier_or_number(); - double get_number_double(); - long get_number_long(); - - 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(const pstring &token) - { - token_id_t ret(m_tokens.size()); - m_tokens.emplace(token, ret); - return ret; - } - - ptokenizer & identifier_chars(const pstring &s) { m_identifier_chars = s; return *this; } - ptokenizer & number_chars(const pstring &st, const pstring & rem) { m_number_chars_start = st; m_number_chars = rem; return *this; } - ptokenizer & string_char(pstring::value_type c) { m_string = c; return *this; } - ptokenizer & whitespace(const pstring & s) { m_whitespace = 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(); - void error(const pstring &errs); - - putf8_reader &stream() { return m_strm; } -protected: - virtual void verror(const pstring &msg) = 0; - -private: - void skipeol(); - - pstring::value_type getc(); - void ungetc(pstring::value_type c); - - bool eof() { return m_strm.eof(); } - - putf8_reader m_strm; - - pstring m_cur_line; - pstring::const_iterator m_px; - pstring::value_type m_unget; - - /* tokenizer stuff follows ... */ - - pstring m_identifier_chars; - pstring m_number_chars; - pstring m_number_chars_start; - std::unordered_map<pstring, token_id_t> m_tokens; - pstring m_whitespace; - pstring::value_type m_string; - - token_id_t m_tok_comment_start; - token_id_t m_tok_comment_end; - token_id_t m_tok_line_comment; - - /* source locations, vector used as stack because we need to loop through stack */ - bool m_support_line_markers; - std::vector<plib::source_location> m_source_location; -}; - - -class ppreprocessor : public std::istream -{ -public: - - using string_list = std::vector<pstring>; - - struct define_t - { - define_t(const pstring &name, const pstring &replace) - : m_name(name), m_replace(replace), m_has_params(false) - {} - define_t(const pstring &name) - : m_name(name), m_replace(""), m_has_params(false) - {} - pstring m_name; - pstring m_replace; - bool m_has_params; - string_list m_params; - }; - - using defines_map_type = std::unordered_map<pstring, define_t>; - - explicit ppreprocessor(psource_collection_t<> &sources, defines_map_type *defines = nullptr); - - COPYASSIGN(ppreprocessor, delete) - ppreprocessor &operator=(ppreprocessor &&src) = delete; - - ppreprocessor(ppreprocessor &&s) noexcept - : std::istream(new readbuffer(this)) - , m_defines(std::move(s.m_defines)) - , m_sources(s.m_sources) - , m_expr_sep(std::move(s.m_expr_sep)) - , m_if_flag(s.m_if_flag) - , m_if_level(s.m_if_level) - , m_outbuf(std::move(s.m_outbuf)) - , m_pos(s.m_pos) - , m_state(s.m_state) - , m_comment(s.m_comment) - , m_debug_out(s.m_debug_out) - { - } - - ~ppreprocessor() override - { - delete rdbuf(); - } - - template <typename T> - ppreprocessor & process(T &&istrm) - { - m_stack.emplace_back(input_context(std::forward<T>(istrm),"","<stream>")); - process_stack(); - return *this; - } - - void error(const pstring &err); - -protected: - - class readbuffer : public std::streambuf - { - public: - readbuffer(ppreprocessor *strm) : m_strm(strm), m_buf() { setg(nullptr, nullptr, nullptr); } - readbuffer(readbuffer &&rhs) noexcept : m_strm(rhs.m_strm), m_buf() {} - COPYASSIGN(readbuffer, delete) - readbuffer &operator=(readbuffer &&src) = delete; - ~readbuffer() override = default; - - int_type underflow() override - { - if (this->gptr() == this->egptr()) - { - /* clang reports sign error - weird */ - std::size_t bytes = pstring_mem_t_size(m_strm->m_outbuf) - static_cast<std::size_t>(m_strm->m_pos); - - if (bytes > m_buf.size()) - bytes = m_buf.size(); - std::copy(m_strm->m_outbuf.c_str() + m_strm->m_pos, m_strm->m_outbuf.c_str() + m_strm->m_pos + bytes, m_buf.data()); - //printf("%ld\n", (long int)bytes); - this->setg(m_buf.data(), m_buf.data(), m_buf.data() + bytes); - - m_strm->m_pos += static_cast</*pos_type*/long>(bytes); - } - - return this->gptr() == this->egptr() - ? std::char_traits<char>::eof() - : std::char_traits<char>::to_int_type(*this->gptr()); - } - - private: - ppreprocessor *m_strm; - std::array<char_type, 1024> m_buf; - }; - define_t *get_define(const pstring &name); - pstring replace_macros(const pstring &line); - -private: - - enum state_e - { - PROCESS, - LINE_CONTINUATION - }; - - void push_out(pstring s); - - void process_stack(); - - string_list tokenize(const pstring &str, const string_list &sep, bool remove_ws, bool concat); - bool is_valid_token(const pstring &str); - - std::pair<pstring,bool> process_line(pstring line); - pstring process_comments(pstring line); - - defines_map_type m_defines; - psource_collection_t<> &m_sources; - string_list m_expr_sep; - - std::uint_least64_t m_if_flag; // 31 if levels - int m_if_level; - - struct input_context - { - template <typename T> - input_context(T &&istrm, const pstring &local_path, const pstring &name) - : m_reader(std::forward<T>(istrm)) - , m_lineno(0) - , m_local_path(local_path) - , m_name(name) - {} - - putf8_reader m_reader; - int m_lineno; - pstring m_local_path; - pstring m_name; - }; - - /* vector used as stack because we need to loop through stack */ - std::vector<input_context> m_stack; - pstring_t<pu8_traits> m_outbuf; - std::istream::pos_type m_pos; - state_e m_state; - pstring m_line; - bool m_comment; - bool m_debug_out; - -}; - -} // namespace plib - -#endif /* PPARSER_H_ */ diff --git a/src/lib/netlist/plib/ppreprocessor.cpp b/src/lib/netlist/plib/ppreprocessor.cpp new file mode 100644 index 00000000000..e29be1757ed --- /dev/null +++ b/src/lib/netlist/plib/ppreprocessor.cpp @@ -0,0 +1,628 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud +/* + * ppreprocessor.cpp + * + */ + +#include "ppreprocessor.h" +#include "palloc.h" +#include "putil.h" + +namespace plib { + + // ---------------------------------------------------------------------------------------- + // A simple preprocessor + // ---------------------------------------------------------------------------------------- + + ppreprocessor::ppreprocessor(psource_collection_t<> &sources, defines_map_type *defines) + : std::istream(new readbuffer(this)) + , m_sources(sources) + , m_if_flag(0) + , m_if_level(0) + , m_pos(0) + , m_state(PROCESS) + , m_comment(false) + { + 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(";"); + 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_expr_sep.emplace_back("\""); + + if (defines != nullptr) + m_defines = *defines; + m_defines.insert({"__PLIB_PREPROCESSOR__", define_t("__PLIB_PREPROCESSOR__", "1")}); + auto idx = m_defines.find("__PREPROCESSOR_DEBUG__"); + m_debug_out = idx != m_defines.end(); + + } + + void ppreprocessor::error(const pstring &err) + { + pstring s(""); + pstring trail (" from "); + pstring trail_first("In file included from "); + pstring e = plib::pfmt("{1}:{2}:0: error: {3}\n") + (m_stack.back().m_name, m_stack.back().m_lineno, err); + m_stack.pop_back(); + while (m_stack.size() > 0) + { + if (m_stack.size() == 1) + trail = trail_first; + s = trail + plib::pfmt("{1}:{2}:0\n")(m_stack.back().m_name, m_stack.back().m_lineno) + s; + m_stack.pop_back(); + } + throw pexception("\n" + s + e + " " + m_line + "\n"); + } + + template <typename PP, typename L = ppreprocessor::string_list> + struct simple_iter + { + simple_iter(PP *parent, const L &tokens) + : m_tokens(tokens), m_parent(parent), m_pos(0) + {} + + /**! skip white space in token list + * + */ + void skip_ws() + { + while (m_pos < m_tokens.size() && (m_tokens[m_pos] == " " || m_tokens[m_pos] == "\t")) + m_pos++; + } + + /**! return next token skipping white space + * + * @return next token + */ + pstring next() + { + skip_ws(); + if (m_pos >= m_tokens.size()) + error("unexpected end of line"); + return m_tokens[m_pos++]; + } + + /**! return next token including white space + * + * @return next token + */ + pstring next_ws() + { + if (m_pos >= m_tokens.size()) + error("unexpected end of line"); + return m_tokens[m_pos++]; + } + + pstring peek_ws() + { + if (m_pos >= m_tokens.size()) + error("unexpected end of line"); + return m_tokens[m_pos]; + } + + pstring last() + { + if (m_pos == 0) + error("no last token at beginning of line"); + if (m_pos > m_tokens.size()) + error("unexpected end of line"); + return m_tokens[m_pos-1]; + } + + bool eod() + { + return (m_pos >= m_tokens.size()); + } + + void error(pstring err) + { + m_parent->error(err); + } + private: + L m_tokens; + PP *m_parent; + std::size_t m_pos; + }; + + #define CHECKTOK2(p_op, p_prio) \ + else if (tok == # p_op) \ + { \ + if (!has_val) \ + { sexpr.error("parsing error!"); return 1;} \ + if (prio < (p_prio)) \ + return val; \ + sexpr.next(); \ + const auto v2 = prepro_expr(sexpr, (p_prio)); \ + val = (val p_op v2); \ + } \ + + // Operator precedence see https://en.cppreference.com/w/cpp/language/operator_precedence + + template <typename PP> + static int prepro_expr(simple_iter<PP> &sexpr, int prio) + { + int val(0); + bool has_val(false); + + pstring tok=sexpr.peek_ws(); + if (tok == "(") + { + sexpr.next(); + val = prepro_expr(sexpr, 255); + if (sexpr.next() != ")") + sexpr.error("expected ')'"); + has_val = true; + } + while (!sexpr.eod()) + { + tok = sexpr.peek_ws(); + if (tok == ")") + { + if (!has_val) + sexpr.error("Found ')' but have no value computed"); + else + return val; + } + else if (tok == "!") + { + if (prio < 3) + { + if (!has_val) + sexpr.error("parsing error!"); + else + return val; + } + sexpr.next(); + val = !prepro_expr(sexpr, 3); + has_val = true; + } + CHECKTOK2(*, 5) + CHECKTOK2(/, 5) // NOLINT(clang-analyzer-core.DivideZero) + CHECKTOK2(+, 6) + CHECKTOK2(-, 6) + CHECKTOK2(==, 10) + CHECKTOK2(&&, 14) + CHECKTOK2(||, 15) + else + { + val = plib::pstonum<decltype(val)>(tok); + has_val = true; + sexpr.next(); + } + } + if (!has_val) + sexpr.error("No value computed. Empty expression ?"); + return val; + } + + ppreprocessor::define_t *ppreprocessor::get_define(const pstring &name) + { + auto idx = m_defines.find(name); + return (idx != m_defines.end()) ? &idx->second : nullptr; + } + + ppreprocessor::string_list ppreprocessor::tokenize(const pstring &str, + const string_list &sep, bool remove_ws, bool concat) + { + const pstring STR = "\""; + string_list tmpret; + string_list tmp(psplit(str, sep)); + std::size_t pi(0); + + while (pi < tmp.size()) + { + if (tmp[pi] == STR) + { + pstring s(STR); + pi++; + // FIXME : \" + while (pi < tmp.size() && tmp[pi] != STR) + { + s += tmp[pi]; + pi++; + } + s += STR; + tmpret.push_back(s); + } + else + if (!remove_ws || (tmp[pi] != " " && tmp[pi] != "\t")) + tmpret.push_back(tmp[pi]); + pi++; + } + if (!concat) + return tmpret; + else + { + // FIXME: error if concat at beginning or end + string_list ret; + pi = 0; + while (pi<tmpret.size()) + { + if (tmpret[pi] == "##") + { + while (ret.back() == " " || ret.back() == "\t") + ret.pop_back(); + pstring cc = ret.back(); + ret.pop_back(); + pi++; + while (pi < tmpret.size() && (tmpret[pi] == " " || tmpret[pi] == "\t")) + pi++; + if (pi == tmpret.size()) + error("## found at end of sequence"); + ret.push_back(cc + tmpret[pi]); + } + else + ret.push_back(tmpret[pi]); + pi++; + } + return ret; + } + } + + bool ppreprocessor::is_valid_token(const pstring &str) + { + if (str.length() == 0) + return false; + pstring::value_type c(str.at(0)); + return ((c>='a' && c<='z') || (c>='A' && c<='Z') || c == '_'); + } + + pstring ppreprocessor::replace_macros(const pstring &line) + { + //std::vector<pstring> elems(psplit(line, m_expr_sep)); + bool repeat(false); + pstring tmpret(line); + do + { + repeat = false; + auto elems(simple_iter<ppreprocessor>(this, tokenize(tmpret, m_expr_sep, false, true))); + tmpret = ""; + while (!elems.eod()) + { + auto token(elems.next_ws()); + define_t *def = get_define(token); + if (def == nullptr) + tmpret += token; + else if (!def->m_has_params) + { + tmpret += def->m_replace; + repeat = true; + } + else + { + token = elems.next(); + if (token != "(") + error("expected '(' in macro expansion of " + def->m_name); + string_list rep; + token = elems.next(); + while (token != ")") + { + pstring par(""); + int pcnt(1); + while (true) + { + if (pcnt==1 && token == ",") + { + token = elems.next(); + break; + } + if (token == "(") + pcnt++; + if (token == ")") + if (--pcnt == 0) + break; + par += token; + token = elems.next(); + } + rep.push_back(par); + } + repeat = true; + if (def->m_params.size() != rep.size()) + error(pfmt("Expected {1} parameters, got {2}")(def->m_params.size(), rep.size())); + auto r(simple_iter<ppreprocessor>(this, tokenize(def->m_replace, m_expr_sep, false, false))); + bool stringify_next = false; + while (!r.eod()) + { + token = r.next(); + if (token == "#") + stringify_next = true; + else if (token != " " && token != "\t") + { + for (std::size_t i=0; i<def->m_params.size(); i++) + if (def->m_params[i] == token) + { + if (stringify_next) + { + stringify_next = false; + token = "\"" + rep[i] + "\""; + } + else + token = rep[i]; + break; + } + if (stringify_next) + error("'#' is not followed by a macro parameter"); + tmpret += token; + tmpret += " "; // make sure this is not concatenated with next token + } + else + tmpret += token; + } + } + } + } while (repeat); + + return tmpret; + } + + static pstring catremainder(const std::vector<pstring> &elems, std::size_t start, const pstring &sep) + { + pstring ret(""); + for (std::size_t i = start; i < elems.size(); i++) + { + ret += elems[i]; + ret += sep; + } + return ret; + } + + 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; + } + + std::pair<pstring,bool> ppreprocessor::process_line(pstring line) + { + 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 {"", false}; + } + else + m_state = PROCESS; + + line = process_comments(m_line); + + pstring lt = plib::trim(plib::replace_all(line, "\t", " ")); + // FIXME ... revise and extend macro handling + if (plib::startsWith(lt, "#")) + { + string_list lti(psplit(lt, " ", true)); + if (lti[0] == "#if") + { + m_if_level++; + lt = replace_macros(lt); + //std::vector<pstring> t(psplit(replace_all(lt.substr(3), " ", ""), m_expr_sep)); + auto t(simple_iter<ppreprocessor>(this, tokenize(lt.substr(3), m_expr_sep, true, true))); + auto val = static_cast<int>(prepro_expr(t, 255)); + t.skip_ws(); + if (!t.eod()) + error("found unprocessed content at end of line"); + if (val == 0) + m_if_flag |= (1 << m_if_level); + } + else if (lti[0] == "#ifdef") + { + m_if_level++; + if (get_define(lti[1]) == nullptr) + m_if_flag |= (1 << m_if_level); + } + else if (lti[0] == "#ifndef") + { + m_if_level++; + if (get_define(lti[1]) != nullptr) + m_if_flag |= (1 << m_if_level); + } + else if (lti[0] == "#else") + { + m_if_flag ^= (1 << m_if_level); + } + else if (lti[0] == "#endif") + { + m_if_flag &= ~(1 << m_if_level); + m_if_level--; + } + else if (lti[0] == "#include") + { + if (m_if_flag == 0) + { + pstring arg(""); + for (std::size_t i=1; i<lti.size(); i++) + arg += (lti[i] + " "); + + arg = plib::trim(arg); + + if (startsWith(arg, "\"") && endsWith(arg, "\"")) + { + arg = arg.substr(1, arg.length() - 2); + /* first try local context */ + auto l(plib::util::buildpath({m_stack.back().m_local_path, arg})); + auto lstrm(m_sources.get_stream<>(l)); + if (lstrm) + { + m_stack.emplace_back(input_context(std::move(lstrm), plib::util::path(l), l)); + } + else + { + auto strm(m_sources.get_stream<>(arg)); + if (strm) + { + m_stack.emplace_back(input_context(std::move(strm), plib::util::path(arg), arg)); + } + else + error("include not found:" + arg); + } + } + else + error("include misspelled:" + arg); + pstring linemarker = pfmt("# {1} \"{2}\" 1\n")(m_stack.back().m_lineno, m_stack.back().m_name); + push_out(linemarker); + } + } + else if (lti[0] == "#pragma") + { + if (m_if_flag == 0 && lti.size() > 3 && lti[1] == "NETLIST") + { + if (lti[2] == "warning") + error("NETLIST: " + catremainder(lti, 3, " ")); + } + } + else if (lti[0] == "#define") + { + if (m_if_flag == 0) + { + if (lti.size() < 2) + error("define needs at least one argument"); + auto args(simple_iter<ppreprocessor>(this, tokenize(lt.substr(8), m_expr_sep, false, false))); + pstring n = args.next(); + if (!is_valid_token(n)) + error("define expected identifier"); + if (args.next_ws() == "(") + { + define_t def(n); + def.m_has_params = true; + auto token(args.next()); + while (true) + { + if (token == ")") + break; + def.m_params.push_back(token); + token = args.next(); + if (token != "," && token != ")") + error(pfmt("expected , or ), found <{1}>")(token)); + if (token == ",") + token = args.next(); + } + pstring r; + while (!args.eod()) + r += args.next_ws(); + def.m_replace = r; + m_defines.insert({n, def}); + } + else + { + pstring r; + while (!args.eod()) + r += args.next_ws(); + m_defines.insert({n, define_t(n, r)}); + } + } + } + else + { + if (m_if_flag == 0) + error("unknown directive"); + } + return { "", false }; + } + else + { + if (m_if_flag == 0) + return { replace_macros(lt), true }; + else + return { "", false }; + } + } + + void ppreprocessor::push_out(const pstring &s) + { + m_outbuf += decltype(m_outbuf)(s.c_str()); + if (m_debug_out) + std::cerr << s; + } + + void ppreprocessor::process_stack() + { + while (m_stack.size() > 0) + { + pstring line; + pstring linemarker = pfmt("# {1} \"{2}\"\n")(m_stack.back().m_lineno, m_stack.back().m_name); + push_out(linemarker); + bool last_skipped=false; + while (m_stack.back().m_reader.readline(line)) + { + m_stack.back().m_lineno++; + auto r(process_line(line)); + if (r.second) + { + if (last_skipped) + push_out(pfmt("# {1} \"{2}\"\n")(m_stack.back().m_lineno, m_stack.back().m_name)); + push_out(r.first + "\n"); + last_skipped = false; + } + else + last_skipped = true; + } + m_stack.pop_back(); + if (m_stack.size() > 0) + { + linemarker = pfmt("# {1} \"{2}\" 2\n")(m_stack.back().m_lineno, m_stack.back().m_name); + push_out(linemarker); + } + } + } + + + +} // namespace plib diff --git a/src/lib/netlist/plib/ppreprocessor.h b/src/lib/netlist/plib/ppreprocessor.h new file mode 100644 index 00000000000..1df9c2e5975 --- /dev/null +++ b/src/lib/netlist/plib/ppreprocessor.h @@ -0,0 +1,173 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud +/* + * ppreprocessor.h + * + */ + +#ifndef PPREPROCESSOR_H_ +#define PPREPROCESSOR_H_ + +#include "plists.h" +#include "pstream.h" +#include "pstring.h" + +#include "putil.h" // psource_t + +#include <istream> +#include <unordered_map> +#include <vector> + +namespace plib { + + class ppreprocessor : public std::istream + { + public: + + using string_list = std::vector<pstring>; + + struct define_t + { + define_t(const pstring &name, const pstring &replace) + : m_name(name), m_replace(replace), m_has_params(false) + {} + define_t(const pstring &name) + : m_name(name), m_replace(""), m_has_params(false) + {} + pstring m_name; + pstring m_replace; + bool m_has_params; + string_list m_params; + }; + + using defines_map_type = std::unordered_map<pstring, define_t>; + + explicit ppreprocessor(psource_collection_t<> &sources, defines_map_type *defines = nullptr); + + COPYASSIGN(ppreprocessor, delete) + ppreprocessor &operator=(ppreprocessor &&src) = delete; + + ppreprocessor(ppreprocessor &&s) noexcept + : std::istream(new readbuffer(this)) + , m_defines(std::move(s.m_defines)) + , m_sources(s.m_sources) + , m_expr_sep(std::move(s.m_expr_sep)) + , m_if_flag(s.m_if_flag) + , m_if_level(s.m_if_level) + , m_outbuf(std::move(s.m_outbuf)) + , m_pos(s.m_pos) + , m_state(s.m_state) + , m_comment(s.m_comment) + , m_debug_out(s.m_debug_out) + { + } + + ~ppreprocessor() override + { + delete rdbuf(); + } + + template <typename T> + ppreprocessor & process(T &&istrm) + { + m_stack.emplace_back(input_context(std::forward<T>(istrm),"","<stream>")); + process_stack(); + return *this; + } + + [[noreturn]] void error(const pstring &err); + + protected: + + class readbuffer : public std::streambuf + { + public: + readbuffer(ppreprocessor *strm) : m_strm(strm), m_buf() { setg(nullptr, nullptr, nullptr); } + readbuffer(readbuffer &&rhs) noexcept : m_strm(rhs.m_strm), m_buf() {} + COPYASSIGN(readbuffer, delete) + readbuffer &operator=(readbuffer &&src) = delete; + ~readbuffer() override = default; + + int_type underflow() override + { + if (this->gptr() == this->egptr()) + { + /* clang reports sign error - weird */ + std::size_t bytes = pstring_mem_t_size(m_strm->m_outbuf) - static_cast<std::size_t>(m_strm->m_pos); + + if (bytes > m_buf.size()) + bytes = m_buf.size(); + std::copy(m_strm->m_outbuf.c_str() + m_strm->m_pos, m_strm->m_outbuf.c_str() + m_strm->m_pos + bytes, m_buf.data()); + //printf("%ld\n", (long int)bytes); + this->setg(m_buf.data(), m_buf.data(), m_buf.data() + bytes); + + m_strm->m_pos += static_cast</*pos_type*/long>(bytes); + } + + return this->gptr() == this->egptr() + ? std::char_traits<char>::eof() + : std::char_traits<char>::to_int_type(*this->gptr()); + } + + private: + ppreprocessor *m_strm; + std::array<char_type, 1024> m_buf; + }; + define_t *get_define(const pstring &name); + pstring replace_macros(const pstring &line); + + private: + + enum state_e + { + PROCESS, + LINE_CONTINUATION + }; + + void push_out(const pstring &s); + + void process_stack(); + + string_list tokenize(const pstring &str, const string_list &sep, bool remove_ws, bool concat); + bool is_valid_token(const pstring &str); + + std::pair<pstring,bool> process_line(pstring line); + pstring process_comments(pstring line); + + defines_map_type m_defines; + psource_collection_t<> &m_sources; + string_list m_expr_sep; + + std::uint_least64_t m_if_flag; // 31 if levels + int m_if_level; + + struct input_context + { + template <typename T> + input_context(T &&istrm, const pstring &local_path, const pstring &name) + : m_reader(std::forward<T>(istrm)) + , m_lineno(0) + , m_local_path(local_path) + , m_name(name) + {} + + putf8_reader m_reader; + int m_lineno; + pstring m_local_path; + pstring m_name; + }; + + /* vector used as stack because we need to loop through stack */ + std::vector<input_context> m_stack; + pstring_t<pu8_traits> m_outbuf; + std::istream::pos_type m_pos; + state_e m_state; + pstring m_line; + bool m_comment; + bool m_debug_out; + + }; + +} // namespace plib + +#endif /* PPREPROCESSOR_H_ */ diff --git a/src/lib/netlist/plib/ptokenizer.cpp b/src/lib/netlist/plib/ptokenizer.cpp new file mode 100644 index 00000000000..fbda60de458 --- /dev/null +++ b/src/lib/netlist/plib/ptokenizer.cpp @@ -0,0 +1,301 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud +/* + * ptokenizer.cpp + * + */ + +#include "ptokenizer.h" +#include "palloc.h" +#include "putil.h" + +namespace plib { + + // ---------------------------------------------------------------------------------------- + // A simple tokenizer + // ---------------------------------------------------------------------------------------- + + pstring ptokenizer::currentline_str() + { + return m_cur_line; + } + + void ptokenizer::skipeol() + { + pstring::value_type c = getc(); + while (c) + { + if (c == 10) + { + c = getc(); + if (c != 13) + ungetc(c); + return; + } + c = getc(); + } + } + + pstring::value_type ptokenizer::getc() + { + if (m_unget != 0) + { + pstring::value_type c = m_unget; + m_unget = 0; + return c; + } + if (m_px == m_cur_line.end()) + { + ++m_source_location.back(); + if (m_strm.readline(m_cur_line)) + m_px = m_cur_line.begin(); + else + return 0; + return '\n'; + } + pstring::value_type c = *(m_px++); + return c; + } + + void ptokenizer::ungetc(pstring::value_type c) + { + m_unget = c; + } + + void ptokenizer::require_token(const token_id_t &token_num) + { + require_token(get_token(), token_num); + } + + void ptokenizer::require_token(const token_t &tok, const token_id_t &token_num) + { + if (!tok.is(token_num)) + { + pstring val(""); + for (auto &i : m_tokens) + if (i.second.id() == token_num.id()) + val = i.first; + error(pfmt("Expected token <{1}> got <{2}>")(val)(tok.str()) ); + } + } + + pstring ptokenizer::get_string() + { + token_t tok = get_token(); + if (!tok.is_type(STRING)) + { + error(pfmt("Expected a string, got <{1}>")(tok.str()) ); + } + return tok.str(); + } + + pstring ptokenizer::get_identifier() + { + token_t tok = get_token(); + if (!tok.is_type(IDENTIFIER)) + { + error(pfmt("Expected an identifier, got <{1}>")(tok.str()) ); + } + return tok.str(); + } + + pstring ptokenizer::get_identifier_or_number() + { + token_t tok = get_token(); + if (!(tok.is_type(IDENTIFIER) || tok.is_type(NUMBER))) + { + error(pfmt("Expected an identifier or number, got <{1}>")(tok.str()) ); + } + return tok.str(); + } + + // FIXME: combine into template + double ptokenizer::get_number_double() + { + token_t tok = get_token(); + if (!tok.is_type(NUMBER)) + { + error(pfmt("Expected a number, got <{1}>")(tok.str()) ); + } + bool err(false); + auto ret = plib::pstonum_ne<double>(tok.str(), err); + if (err) + error(pfmt("Expected a number, got <{1}>")(tok.str()) ); + return ret; + } + + long ptokenizer::get_number_long() + { + token_t tok = get_token(); + if (!tok.is_type(NUMBER)) + { + error(pfmt("Expected a long int, got <{1}>")(tok.str()) ); + } + bool err(false); + auto ret = plib::pstonum_ne<long>(tok.str(), err); + if (err) + error(pfmt("Expected a long int, got <{1}>")(tok.str()) ); + return ret; + } + + ptokenizer::token_t ptokenizer::get_token() + { + token_t ret = get_token_internal(); + while (true) + { + if (ret.is_type(ENDOFFILE)) + return ret; + else if (m_support_line_markers && ret.is_type(LINEMARKER)) + { + bool benter(false); + bool bexit(false); + pstring file; + unsigned lineno; + + ret = get_token_internal(); + if (!ret.is_type(NUMBER)) + error(pfmt("Expected line number after line marker but got <{1}>")(ret.str()) ); + lineno = pstonum<unsigned>(ret.str()); + ret = get_token_internal(); + if (!ret.is_type(STRING)) + error(pfmt("Expected file name after line marker but got <{1}>")(ret.str()) ); + file = ret.str(); + ret = get_token_internal(); + while (ret.is_type(NUMBER)) + { + if (ret.str() == "1") + benter = true; + if (ret.str() == "2") + bexit = false; + // FIXME: process flags; actually only 1 (file enter) and 2 (after file exit) + ret = get_token_internal(); + } + if (bexit) // pop the last location + m_source_location.pop_back(); + if (!benter) // new location! + m_source_location.pop_back(); + m_source_location.emplace_back(plib::source_location(file, lineno)); + } + else if (ret.is(m_tok_comment_start)) + { + do { + ret = get_token_internal(); + } while (ret.is_not(m_tok_comment_end)); + ret = get_token_internal(); + } + else if (ret.is(m_tok_line_comment)) + { + skipeol(); + ret = get_token_internal(); + } + else + { + return ret; + } + } + } + + ptokenizer::token_t ptokenizer::get_token_internal() + { + /* skip ws */ + pstring::value_type c = getc(); + while (m_whitespace.find(c) != pstring::npos) + { + c = getc(); + if (eof()) + { + return token_t(ENDOFFILE); + } + } + if (m_support_line_markers && c == '#') + return token_t(LINEMARKER, "#"); + else if (m_number_chars_start.find(c) != pstring::npos) + { + /* read number while we receive number or identifier chars + * treat it as an identifier when there are identifier chars in it + * + */ + token_type ret = NUMBER; + pstring tokstr = ""; + while (true) { + if (m_identifier_chars.find(c) != pstring::npos && m_number_chars.find(c) == pstring::npos) + ret = IDENTIFIER; + else if (m_number_chars.find(c) == pstring::npos) + break; + tokstr += c; + c = getc(); + } + ungetc(c); + return token_t(ret, tokstr); + } + else if (m_identifier_chars.find(c) != pstring::npos) + { + /* read identifier till non identifier char */ + pstring tokstr = ""; + while (m_identifier_chars.find(c) != pstring::npos) + { + tokstr += c; + c = getc(); + } + ungetc(c); + auto id = m_tokens.find(tokstr); + if (id != m_tokens.end()) + return token_t(id->second, tokstr); + else + return token_t(IDENTIFIER, tokstr); + } + else if (c == m_string) + { + pstring tokstr = ""; + c = getc(); + while (c != m_string) + { + tokstr += c; + c = getc(); + } + return token_t(STRING, tokstr); + } + else + { + /* read identifier till first identifier char or ws */ + pstring tokstr = ""; + while ((m_identifier_chars.find(c) == pstring::npos) && (m_whitespace.find(c) == pstring::npos)) + { + tokstr += c; + /* expensive, check for single char tokens */ + if (tokstr.length() == 1) + { + auto id = m_tokens.find(tokstr); + if (id != m_tokens.end()) + return token_t(id->second, tokstr); + } + c = getc(); + } + ungetc(c); + auto id = m_tokens.find(tokstr); + if (id != m_tokens.end()) + return token_t(id->second, tokstr); + else + return token_t(UNKNOWN, tokstr); + } + } + + void ptokenizer::error(const pstring &errs) + { + pstring s(""); + pstring trail (" from "); + pstring trail_first("In file included from "); + pstring e = plib::pfmt("{1}:{2}:0: error: {3}\n") + (m_source_location.back().file_name(), m_source_location.back().line(), errs); + m_source_location.pop_back(); + while (m_source_location.size() > 0) + { + if (m_source_location.size() == 1) + trail = trail_first; + s = trail + plib::pfmt("{1}:{2}:0\n")(m_source_location.back().file_name(), m_source_location.back().line()) + s; + m_source_location.pop_back(); + } + verror("\n" + s + e + " " + currentline_str() + "\n"); +} + +} // namespace plib diff --git a/src/lib/netlist/plib/ptokenizer.h b/src/lib/netlist/plib/ptokenizer.h new file mode 100644 index 00000000000..5a6b886a2a2 --- /dev/null +++ b/src/lib/netlist/plib/ptokenizer.h @@ -0,0 +1,169 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud +/* + * ptokenizer.h + * + */ + +#ifndef PTOKENIZER_H_ +#define PTOKENIZER_H_ + +#include "plists.h" +#include "pstream.h" +#include "pstring.h" + +#include "putil.h" // psource_t + +#include <unordered_map> +#include <vector> + +namespace plib { + + class ptokenizer + { + public: + template <typename T> + ptokenizer(T &&strm) // NOLINT(misc-forwarding-reference-overload, bugprone-forwarding-reference-overload) + : m_strm(std::forward<T>(strm)) + , m_cur_line("") + , m_px(m_cur_line.begin()) + , m_unget(0) + , m_string('"') + , m_support_line_markers(true) // FIXME + { + // add a first entry to the stack + m_source_location.emplace_back(plib::source_location("Unknown", 0)); + } + + COPYASSIGNMOVE(ptokenizer, delete) + + virtual ~ptokenizer() = default; + + enum token_type + { + IDENTIFIER, + NUMBER, + TOKEN, + STRING, + COMMENT, + LINEMARKER, + UNKNOWN, + ENDOFFILE + }; + + struct token_id_t + { + public: + + static constexpr std::size_t npos = static_cast<std::size_t>(-1); + + token_id_t() : m_id(npos) {} + explicit token_id_t(const std::size_t id) : m_id(id) {} + std::size_t id() const { return m_id; } + private: + std::size_t m_id; + }; + + struct token_t + { + explicit token_t(token_type type) + : m_type(type), m_id(), m_token("") + { + } + token_t(token_type type, const pstring &str) + : m_type(type), m_id(), m_token(str) + { + } + token_t(const token_id_t &id, const pstring &str) + : m_type(TOKEN), m_id(id), m_token(str) + { + } + + bool is(const token_id_t &tok_id) const { return m_id.id() == tok_id.id(); } + bool is_not(const token_id_t &tok_id) const { return !is(tok_id); } + + bool is_type(const token_type type) const { return m_type == type; } + + pstring str() const { return m_token; } + + private: + token_type m_type; + token_id_t m_id; + pstring m_token; + }; + + pstring currentline_str(); + + /* tokenizer stuff follows ... */ + + token_t get_token(); + pstring get_string(); + pstring get_identifier(); + pstring get_identifier_or_number(); + double get_number_double(); + long get_number_long(); + + 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(const pstring &token) + { + token_id_t ret(m_tokens.size()); + m_tokens.emplace(token, ret); + return ret; + } + + ptokenizer & identifier_chars(const pstring &s) { m_identifier_chars = s; return *this; } + ptokenizer & number_chars(const pstring &st, const pstring & rem) { m_number_chars_start = st; m_number_chars = rem; return *this; } + ptokenizer & string_char(pstring::value_type c) { m_string = c; return *this; } + ptokenizer & whitespace(const pstring & s) { m_whitespace = 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(); + void error(const pstring &errs); + + putf8_reader &stream() { return m_strm; } + protected: + virtual void verror(const pstring &msg) = 0; + + private: + void skipeol(); + + pstring::value_type getc(); + void ungetc(pstring::value_type c); + + bool eof() { return m_strm.eof(); } + + putf8_reader m_strm; + + pstring m_cur_line; + pstring::const_iterator m_px; + pstring::value_type m_unget; + + /* tokenizer stuff follows ... */ + + pstring m_identifier_chars; + pstring m_number_chars; + pstring m_number_chars_start; + std::unordered_map<pstring, token_id_t> m_tokens; + pstring m_whitespace; + pstring::value_type m_string; + + token_id_t m_tok_comment_start; + token_id_t m_tok_comment_end; + token_id_t m_tok_line_comment; + + /* source locations, vector used as stack because we need to loop through stack */ + bool m_support_line_markers; + std::vector<plib::source_location> m_source_location; + }; + +} // namespace plib + +#endif /* PTOKENIZER_H_ */ diff --git a/src/lib/netlist/plib/putil.cpp b/src/lib/netlist/plib/putil.cpp index f6eed734a3e..457e3c62ca1 100644 --- a/src/lib/netlist/plib/putil.cpp +++ b/src/lib/netlist/plib/putil.cpp @@ -19,7 +19,7 @@ namespace plib static constexpr const char PATH_SEP = '/'; #endif - pstring basename(pstring filename) + pstring basename(const pstring &filename) { auto p=find_last_of(filename, pstring(1, PATH_SEP)); if (p == pstring::npos) @@ -28,7 +28,7 @@ namespace plib return filename.substr(p+1); } - pstring path(pstring filename) + pstring path(const pstring &filename) { auto p=find_last_of(filename, pstring(1, PATH_SEP)); if (p == pstring::npos) diff --git a/src/lib/netlist/plib/putil.h b/src/lib/netlist/plib/putil.h index 9b1d8ec7f84..9a21a223ba9 100644 --- a/src/lib/netlist/plib/putil.h +++ b/src/lib/netlist/plib/putil.h @@ -8,9 +8,9 @@ #ifndef PUTIL_H_ #define PUTIL_H_ +#include "palloc.h" #include "pexception.h" #include "pstring.h" -#include "palloc.h" #include <algorithm> #include <initializer_list> @@ -33,7 +33,7 @@ namespace plib * * The c++20 draft for source locations is based on const char * strings. * It is thus only suitable for c++ source code and not for programmatic - * parsing of files. This class is a replacement dynamic use cases. + * parsing of files. This class is a replacement for dynamic use cases. * */ struct source_location @@ -43,11 +43,11 @@ namespace plib { } source_location(pstring file, unsigned line) noexcept - : m_file(file), m_func("unknown"), m_line(line), m_col(0) + : m_file(std::move(file)), m_func("unknown"), m_line(line), m_col(0) { } source_location(pstring file, pstring func, unsigned line) noexcept - : m_file(file), m_func(func), m_line(line), m_col(0) + : m_file(std::move(file)), m_func(func), m_line(line), m_col(0) { } unsigned line() const noexcept { return m_line; } @@ -55,7 +55,7 @@ namespace plib pstring file_name() const noexcept { return m_file; } pstring function_name() const noexcept { return m_func; } - source_location &operator ++() + source_location &operator ++() noexcept { ++m_line; return *this; @@ -81,8 +81,7 @@ namespace plib using stream_ptr = plib::unique_ptr<std::istream>; - psource_t() - {} + psource_t() noexcept = default; COPYASSIGNMOVE(psource_t, delete) @@ -104,11 +103,11 @@ namespace plib { public: psource_str_t(pstring name, pstring str) - : m_name(name), m_str(str) + : m_name(std::move(name)), m_str(std::move(str)) {} COPYASSIGNMOVE(psource_str_t, delete) - virtual ~psource_str_t() noexcept = default; + ~psource_str_t() noexcept override = default; typename TS::stream_ptr stream(const pstring &name) override { @@ -133,8 +132,7 @@ namespace plib using source_type = plib::unique_ptr<TS>; using list_t = std::vector<source_type>; - psource_collection_t() - {} + psource_collection_t() noexcept = default; COPYASSIGNMOVE(psource_collection_t, delete) virtual ~psource_collection_t() noexcept = default; @@ -161,7 +159,7 @@ namespace plib } template <typename S, typename F> - bool for_all(pstring name, F lambda) + bool for_all(F lambda) { for (auto &s : m_collection) { @@ -181,8 +179,8 @@ namespace plib namespace util { - pstring basename(pstring filename); - pstring path(pstring filename); + pstring basename(const pstring &filename); + pstring path(const pstring &filename); pstring buildpath(std::initializer_list<pstring> list ); pstring environment(const pstring &var, const pstring &default_val); } // namespace util @@ -365,7 +363,7 @@ namespace plib return static_cast<T>(ret); } - template<typename R, bool CLOCALE, typename T> + template<typename R, typename T> R pstonum_ne(const T &str, bool &err, std::locale loc = std::locale::classic()) noexcept { try @@ -380,6 +378,19 @@ namespace plib } } + template<typename R, typename T> + R pstonum_ne_def(const T &str, R def, std::locale loc = std::locale::classic()) noexcept + { + try + { + return pstonum<R>(str, loc); + } + catch (...) + { + return def; + } + } + //============================================================ // penum - strongly typed enumeration //============================================================ @@ -402,9 +413,9 @@ namespace plib int f = from_string_int(strings(), s); \ 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;} \ + operator E() const noexcept {return m_v;} \ + bool operator==(const ename &rhs) const noexcept {return m_v == rhs.m_v;} \ + bool operator==(const E &rhs) const noexcept {return m_v == rhs;} \ std::string name() const { \ return nthstr(static_cast<int>(m_v), strings()); \ } \ diff --git a/src/lib/netlist/plib/vector_ops.h b/src/lib/netlist/plib/vector_ops.h index bdeb24ae502..51c592968f5 100644 --- a/src/lib/netlist/plib/vector_ops.h +++ b/src/lib/netlist/plib/vector_ops.h @@ -27,7 +27,7 @@ namespace plib { template<typename VT, typename T> - void vec_set_scalar(const std::size_t n, VT &v, T && scalar) + void vec_set_scalar(const std::size_t n, VT &v, T && scalar) noexcept { const typename std::remove_reference<decltype(v[0])>::type s(std::forward<T>(scalar)); for ( std::size_t i = 0; i < n; i++ ) @@ -35,14 +35,14 @@ namespace plib } template<typename VT, typename VS> - void vec_set(const std::size_t n, VT &v, const VS & source) + void vec_set(const std::size_t n, VT &v, const VS & source) noexcept { 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 ) + T vec_mult(const std::size_t n, const V1 & v1, const V2 & v2 ) noexcept { using b8 = std::array<T, 8>; PALIGNAS_VECTOROPT() b8 value = {0}; @@ -54,7 +54,7 @@ namespace plib } template<typename T, typename VT> - T vec_mult2(const std::size_t n, const VT &v) + T vec_mult2(const std::size_t n, const VT &v) noexcept { using b8 = std::array<T, 8>; PALIGNAS_VECTOROPT() b8 value = {0}; @@ -66,7 +66,7 @@ namespace plib } template<typename T, typename VT> - T vec_sum(const std::size_t n, const VT &v) + T vec_sum(const std::size_t n, const VT &v) noexcept { if (n<8) { @@ -88,7 +88,7 @@ namespace plib } template<typename VV, typename T, typename VR> - void vec_mult_scalar(const std::size_t n, VR & result, const VV & v, T && scalar) + void vec_mult_scalar(const std::size_t n, VR & result, const VV & v, T && scalar) noexcept { const typename std::remove_reference<decltype(v[0])>::type s(std::forward<T>(scalar)); for ( std::size_t i = 0; i < n; i++ ) @@ -96,7 +96,7 @@ namespace plib } template<typename VR, typename VV, typename T> - void vec_add_mult_scalar(const std::size_t n, VR & result, const VV & v, T && scalar) + void vec_add_mult_scalar(const std::size_t n, VR & result, const VV & v, T && scalar) noexcept { const typename std::remove_reference<decltype(v[0])>::type s(std::forward<T>(scalar)); for ( std::size_t i = 0; i < n; i++ ) @@ -104,28 +104,28 @@ namespace plib } template<typename T> - void vec_add_mult_scalar_p(const std::size_t n, T * result, const T * v, T scalar) + void vec_add_mult_scalar_p(const std::size_t n, T * result, const T * v, T scalar) noexcept { 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) + void vec_add_ip(const std::size_t n, R & result, const V & v) noexcept { 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) + void vec_sub(const std::size_t n, VR & result, const V1 &v1, const V2 & v2) noexcept { 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) + void vec_scale(const std::size_t n, V & v, T &&scalar) noexcept { const typename std::remove_reference<decltype(v[0])>::type s(std::forward<T>(scalar)); for ( std::size_t i = 0; i < n; i++ ) @@ -133,7 +133,7 @@ namespace plib } template<typename T, typename V> - T vec_maxabs(const std::size_t n, const V & v) + T vec_maxabs(const std::size_t n, const V & v) noexcept { T ret = 0.0; for ( std::size_t i = 0; i < n; i++ ) |