summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/netlist/plib
diff options
context:
space:
mode:
author couriersud <couriersud@gmx.org>2019-10-18 17:57:55 +0200
committer couriersud <couriersud@gmx.org>2019-10-18 17:57:55 +0200
commitb09fa00cca1a9baa0327a33d865fc970f77d4db0 (patch)
tree47dd943368aa43a0c0cf4256f88e590960c1e99f /src/lib/netlist/plib
parentad27643c07d54fc2cc3e56327fe07335e7763d52 (diff)
Netlist: code maintenance and improvements. [Couriersud]
- Added support for line markers to the preprocessor and parser. - Added support for include processing to the preprocessor. - Moved sources base type to plib to be used for preprocessor includes. This enables to include e.g. from rom memory regions. - Renamed some defines
Diffstat (limited to 'src/lib/netlist/plib')
-rw-r--r--src/lib/netlist/plib/palloc.h8
-rw-r--r--src/lib/netlist/plib/pconfig.h30
-rw-r--r--src/lib/netlist/plib/pfmtlog.cpp4
-rw-r--r--src/lib/netlist/plib/pfmtlog.h14
-rw-r--r--src/lib/netlist/plib/pomp.h10
-rw-r--r--src/lib/netlist/plib/pparser.cpp99
-rw-r--r--src/lib/netlist/plib/pparser.h67
-rw-r--r--src/lib/netlist/plib/pstrutil.h22
-rw-r--r--src/lib/netlist/plib/putil.cpp32
-rw-r--r--src/lib/netlist/plib/putil.h112
10 files changed, 336 insertions, 62 deletions
diff --git a/src/lib/netlist/plib/palloc.h b/src/lib/netlist/plib/palloc.h
index 5b7d2f59c2d..aa1aac5544d 100644
--- a/src/lib/netlist/plib/palloc.h
+++ b/src/lib/netlist/plib/palloc.h
@@ -276,7 +276,7 @@ namespace plib {
static inline void *allocate( size_t alignment, size_t size )
{
- #if (USE_ALIGNED_ALLOCATION)
+ #if (PUSE_ALIGNED_ALLOCATION)
#if defined(_WIN32) || defined(_WIN64) || defined(_MSC_VER)
return _aligned_malloc(size, alignment);
#elif defined(__APPLE__)
@@ -296,7 +296,7 @@ namespace plib {
static inline void deallocate( void *ptr )
{
- #if (USE_ALIGNED_ALLOCATION)
+ #if (PUSE_ALIGNED_ALLOCATION)
// NOLINTNEXTLINE(cppcoreguidelines-no-malloc)
free(ptr);
#else
@@ -352,7 +352,7 @@ namespace plib {
//auto t = reinterpret_cast<std::uintptr_t>(p);
//if (t & (ALIGN-1))
// printf("alignment error!");
-#if (USE_ALIGNED_HINTS)
+#if (PUSE_ALIGNED_HINTS)
return reinterpret_cast<T *>(__builtin_assume_aligned(p, ALIGN));
#else
return p;
@@ -364,7 +364,7 @@ namespace plib {
{
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)
+#if (PUSE_ALIGNED_HINTS)
return reinterpret_cast<const T *>(__builtin_assume_aligned(p, ALIGN));
#else
return p;
diff --git a/src/lib/netlist/plib/pconfig.h b/src/lib/netlist/plib/pconfig.h
index 3e20170a752..102a991e613 100644
--- a/src/lib/netlist/plib/pconfig.h
+++ b/src/lib/netlist/plib/pconfig.h
@@ -38,20 +38,20 @@
* netlists like kidniki.
*/
-#ifndef USE_OPENMP
-#define USE_OPENMP (0)
+#ifndef PUSE_OPENMP
+#define PUSE_OPENMP (0)
#endif
/*
* Set this to one if you want to use aligned storage optimizations.
*/
-#ifndef USE_ALIGNED_OPTIMIZATIONS
-#define USE_ALIGNED_OPTIMIZATIONS (0)
+#ifndef PUSE_ALIGNED_OPTIMIZATIONS
+#define PUSE_ALIGNED_OPTIMIZATIONS (0)
#endif
-#define USE_ALIGNED_ALLOCATION (USE_ALIGNED_OPTIMIZATIONS)
-#define USE_ALIGNED_HINTS (USE_ALIGNED_OPTIMIZATIONS)
+#define PUSE_ALIGNED_ALLOCATION (PUSE_ALIGNED_OPTIMIZATIONS)
+#define PUSE_ALIGNED_HINTS (PUSE_ALIGNED_OPTIMIZATIONS)
/*
* Standard alignment macros
*/
@@ -114,11 +114,19 @@ typedef __int128_t INT128;
//============================================================
#if defined(OPENMP)
-#define HAS_OPENMP ( OPENMP >= 200805 )
+#if ( OPENMP >= 200805 )
+#define PHAS_OPENMP (1)
+#else
+#define PHAS_OPENMP (0)
+#endif
#elif defined(_OPENMP)
-#define HAS_OPENMP ( _OPENMP >= 200805 )
+#if ( _OPENMP >= 200805 )
+#define PHAS_OPENMP (1)
+#else
+#define PHAS_OPENMP (0)
+#endif
#else
-#define HAS_OPENMP (0)
+#define PHAS_OPENMP (0)
#endif
@@ -126,8 +134,8 @@ typedef __int128_t INT128;
// WARNINGS
//============================================================
-#if (USE_OPENMP)
-#if (!(HAS_OPENMP))
+#if (PUSE_OPENMP)
+#if (!(PHAS_OPENMP))
#error To use openmp compile and link with "-fopenmp"
#endif
#endif
diff --git a/src/lib/netlist/plib/pfmtlog.cpp b/src/lib/netlist/plib/pfmtlog.cpp
index ca7ec88e2e3..250ead34cb3 100644
--- a/src/lib/netlist/plib/pfmtlog.cpp
+++ b/src/lib/netlist/plib/pfmtlog.cpp
@@ -112,10 +112,10 @@ pfmt::rtype pfmt::setfmt(std::stringstream &strm, char32_t cfmt_spec)
else if (pdot != pstring::npos)
{
strm << std::setprecision(pstonum<int>(fmt.substr(pdot + 1)));
- r.width = pstonum<pstring::size_type>(left(fmt,pdot));
+ r.width = pstonum<int>(left(fmt,pdot));
}
else if (fmt != "")
- r.width = pstonum<pstring::size_type>(fmt);
+ r.width = pstonum<int>(fmt);
switch (r.pend)
{
diff --git a/src/lib/netlist/plib/pfmtlog.h b/src/lib/netlist/plib/pfmtlog.h
index 531b76fafe7..7bf10173857 100644
--- a/src/lib/netlist/plib/pfmtlog.h
+++ b/src/lib/netlist/plib/pfmtlog.h
@@ -227,7 +227,7 @@ protected:
pstring::size_type p;
pstring::size_type sl;
char32_t pend;
- pstring::size_type width;
+ int width;
};
rtype setfmt(std::stringstream &strm, char32_t cfmt_spec);
@@ -248,10 +248,14 @@ protected:
strm << std::forward<T>(val);
const pstring ps(strm.str());
pstring pad("");
- if (ret.width > ps.length())
- pad = pstring(ret.width - ps.length(), ' ');
-
- m_str = m_str.substr(0, ret.p) + pad + ps + m_str.substr(ret.p + ret.sl);
+ std::size_t aw(std::abs(ret.width));
+ if (aw > ps.length())
+ pad = pstring(aw - ps.length(), ' ');
+
+ if (ret.width > 0)
+ m_str = m_str.substr(0, ret.p) + pad + ps + m_str.substr(ret.p + ret.sl);
+ else
+ m_str = m_str.substr(0, ret.p) + ps + pad + m_str.substr(ret.p + ret.sl);
}
} while (ret.ret == 1);
diff --git a/src/lib/netlist/plib/pomp.h b/src/lib/netlist/plib/pomp.h
index 400fbee9e64..79fa0f4bf9b 100644
--- a/src/lib/netlist/plib/pomp.h
+++ b/src/lib/netlist/plib/pomp.h
@@ -14,7 +14,7 @@
#include <cstdint>
-#if HAS_OPENMP
+#if PHAS_OPENMP
#include "omp.h"
#endif
@@ -26,7 +26,7 @@ void for_static(std::size_t numops, const I start, const I end, const T &what)
{
if (numops>1000)
{
- #if HAS_OPENMP && USE_OPENMP
+ #if PHAS_OPENMP && PUSE_OPENMP
#pragma omp parallel for schedule(static)
#endif
for (I i = start; i < end; i++)
@@ -40,7 +40,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)
{
-#if HAS_OPENMP && USE_OPENMP
+#if PHAS_OPENMP && PUSE_OPENMP
#pragma omp parallel for schedule(static)
#endif
for (I i = start; i < end; i++)
@@ -57,7 +57,7 @@ void for_static_np(const I start, const I end, const T &what)
inline void set_num_threads(const std::size_t threads)
{
-#if HAS_OPENMP && USE_OPENMP
+#if PHAS_OPENMP && PUSE_OPENMP
omp_set_num_threads(threads);
#else
plib::unused_var(threads);
@@ -66,7 +66,7 @@ inline void set_num_threads(const std::size_t threads)
inline std::size_t get_max_threads()
{
-#if HAS_OPENMP && USE_OPENMP
+#if PHAS_OPENMP && PUSE_OPENMP
return omp_get_max_threads();
#else
return 1;
diff --git a/src/lib/netlist/plib/pparser.cpp b/src/lib/netlist/plib/pparser.cpp
index 74d0b137829..11da93486a4 100644
--- a/src/lib/netlist/plib/pparser.cpp
+++ b/src/lib/netlist/plib/pparser.cpp
@@ -149,6 +149,23 @@ ptokenizer::token_t ptokenizer::get_token()
if (ret.is_type(ENDOFFILE))
return ret;
+ if (m_support_line_markers && ret.is_type(LINEMARKER))
+ {
+ // FIXME: do something with information gathered
+ ret = get_token_internal();
+ if (!ret.is_type(NUMBER))
+ error(pfmt("Expected line number after line marker but got <{1}>")(ret.str()) );
+ ret = get_token_internal();
+ if (!ret.is_type(STRING))
+ error(pfmt("Expected file name after line marker but got <{1}>")(ret.str()) );
+ ret = get_token_internal();
+ while (ret.is_type(NUMBER))
+ {
+ // FIXME: process flags; actually only 1 (file enter) and 2 (after file exit)
+ ret = get_token_internal();
+ }
+ }
+
if (ret.is(m_tok_comment_start))
{
do {
@@ -184,7 +201,9 @@ ptokenizer::token_t ptokenizer::get_token_internal()
return token_t(ENDOFFILE);
}
}
- if (m_number_chars_start.find(c) != pstring::npos)
+ 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
@@ -259,11 +278,11 @@ ptokenizer::token_t ptokenizer::get_token_internal()
// A simple preprocessor
// ----------------------------------------------------------------------------------------
-ppreprocessor::ppreprocessor(defines_map_type *defines)
+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_lineno(0)
, m_pos(0)
, m_state(PROCESS)
, m_comment(false)
@@ -289,7 +308,20 @@ ppreprocessor::ppreprocessor(defines_map_type *defines)
void ppreprocessor::error(const pstring &err)
{
- throw pexception("PREPRO ERROR: " + err);
+ pstring s("");
+ pstring trail (" from ");
+ pstring trail_first("In file included from ");
+ pstring e = plib::pfmt("PREPRO ERROR: {1}:{2}:0: error: {3}\n")
+ (m_stack.top().m_name, m_stack.top().m_lineno, err);
+ m_stack.pop();
+ while (m_stack.size() > 0)
+ {
+ if (m_stack.size() == 1)
+ trail = trail_first;
+ s = trail + plib::pfmt("{1}:{2}:0\n")(m_stack.top().m_name, m_stack.top().m_lineno) + s;
+ m_stack.pop();
+ }
+ throw pexception("\n" + s + e);
}
#define CHECKTOK2(p_op, p_prio) \
@@ -504,7 +536,38 @@ pstring ppreprocessor::process_line(pstring line)
}
else if (lti[0] == "#include")
{
- // ignore
+ 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.top().m_local_path, arg}));
+ auto lstrm(m_sources.get_stream<>(l));
+ if (lstrm)
+ {
+ m_stack.emplace(input_context(std::move(lstrm), plib::util::path(l), l));
+ }
+ else
+ {
+ auto strm(m_sources.get_stream<>(arg));
+ if (strm)
+ {
+ m_stack.emplace(input_context(std::move(strm), plib::util::path(arg), arg));
+ }
+ else
+ error("include not found:" + arg);
+ }
+ }
+ else
+ error("include misspelled:" + arg);
+ }
}
else if (lti[0] == "#pragma")
{
@@ -519,7 +582,7 @@ pstring ppreprocessor::process_line(pstring line)
if (m_if_flag == 0)
{
if (lti.size() < 2)
- error("PREPRO: define needs at least one argument: " + line);
+ error("define needs at least one argument: " + line);
else if (lti.size() == 2)
m_defines.insert({lti[1], define_t(lti[1], "")});
else
@@ -535,7 +598,7 @@ pstring ppreprocessor::process_line(pstring line)
else
{
if (m_if_flag == 0)
- error(pfmt("unknown directive on line {1}: {2}")(m_lineno)(replace_macros(line)));
+ error(pfmt("unknown directive on line {1}: {2}")(m_stack.top().m_lineno)(replace_macros(line)));
}
}
else
@@ -547,6 +610,28 @@ pstring ppreprocessor::process_line(pstring line)
return ret;
}
+void ppreprocessor::process_stack()
+{
+ while (m_stack.size() > 0)
+ {
+ pstring line;
+ pstring linemarker = pfmt("# {1} \"{2}\" 1\n")(m_stack.top().m_lineno, m_stack.top().m_name);
+ m_outbuf += decltype(m_outbuf)(linemarker.c_str());
+ while (m_stack.top().m_reader.readline(line))
+ {
+ m_stack.top().m_lineno++;
+ line = process_line(line);
+ m_outbuf += decltype(m_outbuf)(line.c_str()) + static_cast<char>(10);
+ }
+ m_stack.pop();
+ if (m_stack.size() > 0)
+ {
+ linemarker = pfmt("# {1} \"{2}\" 2\n")(m_stack.top().m_lineno, m_stack.top().m_name);
+ m_outbuf += decltype(m_outbuf)(linemarker.c_str());
+ }
+ }
+}
+
} // namespace plib
diff --git a/src/lib/netlist/plib/pparser.h b/src/lib/netlist/plib/pparser.h
index 5332ee2518c..ced7e500cad 100644
--- a/src/lib/netlist/plib/pparser.h
+++ b/src/lib/netlist/plib/pparser.h
@@ -12,9 +12,11 @@
#include "pstream.h"
#include "pstring.h"
+#include "putil.h" // psource_t
+
//#include <cstdint>
#include <unordered_map>
-
+#include <stack>
namespace plib {
class ptokenizer
@@ -28,6 +30,7 @@ public:
, m_px(m_cur_line.begin())
, m_unget(0)
, m_string('"')
+ , m_support_line_markers(true) // FIXME
{
}
@@ -42,6 +45,7 @@ public:
TOKEN,
STRING,
COMMENT,
+ LINEMARKER,
UNKNOWN,
ENDOFFILE
};
@@ -156,6 +160,7 @@ private:
token_id_t m_tok_comment_start;
token_id_t m_tok_comment_end;
token_id_t m_tok_line_comment;
+ bool m_support_line_markers;
};
@@ -174,26 +179,7 @@ public:
using defines_map_type = std::unordered_map<pstring, define_t>;
- explicit ppreprocessor(defines_map_type *defines = nullptr);
-
- ~ppreprocessor() override
- {
- delete rdbuf();
- }
-
- 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_outbuf += decltype(m_outbuf)(line.c_str()) + static_cast<char>(10);
- }
- return *this;
- }
+ explicit ppreprocessor(psource_collection_t<> &sources, defines_map_type *defines = nullptr);
COPYASSIGN(ppreprocessor, delete)
ppreprocessor &operator=(ppreprocessor &&src) = delete;
@@ -201,10 +187,10 @@ public:
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_lineno(s.m_lineno)
, m_outbuf(std::move(s.m_outbuf))
, m_pos(s.m_pos)
, m_state(s.m_state)
@@ -212,6 +198,19 @@ public:
{
}
+ ~ppreprocessor() override
+ {
+ delete rdbuf();
+ }
+
+ template <typename T>
+ ppreprocessor & process(T &&istrm)
+ {
+ m_stack.emplace(input_context(std::forward<T>(istrm),"","<stream>"));
+ process_stack();
+ return *this;
+ }
+
protected:
class readbuffer : public std::streambuf
@@ -242,6 +241,7 @@ protected:
? 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;
@@ -261,20 +261,41 @@ private:
LINE_CONTINUATION
};
+ void process_stack();
+
pstring process_line(pstring line);
pstring process_comments(pstring line);
defines_map_type m_defines;
+ psource_collection_t<> &m_sources;
std::vector<pstring> m_expr_sep;
std::uint_least64_t m_if_flag; // 31 if levels
int m_if_level;
- int m_lineno;
+
+ 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;
+ };
+
+ std::stack<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;
+
};
} // namespace plib
diff --git a/src/lib/netlist/plib/pstrutil.h b/src/lib/netlist/plib/pstrutil.h
index 94ecccca09e..d3e62d06af7 100644
--- a/src/lib/netlist/plib/pstrutil.h
+++ b/src/lib/netlist/plib/pstrutil.h
@@ -88,6 +88,28 @@ namespace plib
}
template<typename T>
+ typename T::size_type find_last_of(const T &str, const T &no)
+ {
+ 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 = false;
+ for (typename T::value_type const jt : no)
+ {
+ if (*it == jt)
+ {
+ f = true;
+ 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);
diff --git a/src/lib/netlist/plib/putil.cpp b/src/lib/netlist/plib/putil.cpp
index b4824d62738..f6eed734a3e 100644
--- a/src/lib/netlist/plib/putil.cpp
+++ b/src/lib/netlist/plib/putil.cpp
@@ -13,6 +13,32 @@ namespace plib
{
namespace util
{
+ #ifdef _WIN32
+ static constexpr const char PATH_SEP = '\\';
+ #else
+ static constexpr const char PATH_SEP = '/';
+ #endif
+
+ pstring basename(pstring filename)
+ {
+ auto p=find_last_of(filename, pstring(1, PATH_SEP));
+ if (p == pstring::npos)
+ return filename;
+ else
+ return filename.substr(p+1);
+ }
+
+ pstring path(pstring filename)
+ {
+ auto p=find_last_of(filename, pstring(1, PATH_SEP));
+ if (p == pstring::npos)
+ return "";
+ else if (p == 0) // root case
+ return filename.substr(0, 1);
+ else
+ return filename.substr(0, p);
+ }
+
pstring buildpath(std::initializer_list<pstring> list )
{
pstring ret = "";
@@ -21,11 +47,7 @@ namespace plib
if (ret == "")
ret = elem;
else
- #ifdef _WIN32
- ret = ret + '\\' + elem;
- #else
- ret += ('/' + elem);
- #endif
+ ret += (PATH_SEP + elem);
}
return ret;
}
diff --git a/src/lib/netlist/plib/putil.h b/src/lib/netlist/plib/putil.h
index 5ff70d941a2..227648b172b 100644
--- a/src/lib/netlist/plib/putil.h
+++ b/src/lib/netlist/plib/putil.h
@@ -10,6 +10,8 @@
#include "pexception.h"
#include "pstring.h"
+#include "palloc.h"
+
#include <algorithm>
#include <initializer_list>
#include <iostream>
@@ -24,8 +26,118 @@
namespace plib
{
+ // ----------------------------------------------------------------------------------------
+ // A Generic netlist sources implementation
+ // ----------------------------------------------------------------------------------------
+
+ class psource_t
+ {
+ public:
+
+ using stream_ptr = plib::unique_ptr<std::istream>;
+
+ psource_t()
+ {}
+
+ COPYASSIGNMOVE(psource_t, delete)
+
+ virtual ~psource_t() noexcept = default;
+
+ virtual stream_ptr stream(const pstring &name) = 0;
+ private:
+ };
+
+ /**! Generic string source
+ *
+ * Will return the given string when name matches.
+ * Is used in preprocessor code to eliminate inclusion of certain files.
+ *
+ * @tparam TS base stream class. Default is psource_t
+ */
+ template <typename TS = psource_t>
+ class psource_str_t : public TS
+ {
+ public:
+ psource_str_t(pstring name, pstring str)
+ : m_name(name), m_str(str)
+ {}
+
+ COPYASSIGNMOVE(psource_str_t, delete)
+ virtual ~psource_str_t() noexcept = default;
+
+ typename TS::stream_ptr stream(const pstring &name) override
+ {
+ if (name == m_name)
+ return plib::make_unique<std::stringstream>(m_str);
+ else
+ return typename TS::stream_ptr(nullptr);
+ }
+ private:
+ pstring m_name;
+ pstring m_str;
+ };
+
+ /**! Generic sources collection
+ *
+ * @tparam TS base stream class. Default is psource_t
+ */
+ template <typename TS = psource_t>
+ class psource_collection_t
+ {
+ public:
+ using source_type = plib::unique_ptr<TS>;
+ using list_t = std::vector<source_type>;
+
+ psource_collection_t()
+ {}
+
+ COPYASSIGNMOVE(psource_collection_t, delete)
+ virtual ~psource_collection_t() noexcept = default;
+
+ void add_source(source_type &&src)
+ {
+ m_collection.push_back(std::move(src));
+ }
+
+ template <typename S = TS>
+ typename S::stream_ptr get_stream(pstring name)
+ {
+ for (auto &s : m_collection)
+ {
+ auto source(dynamic_cast<S *>(s.get()));
+ if (source)
+ {
+ auto strm = source->stream(name);
+ if (strm)
+ return strm;
+ }
+ }
+ return typename S::stream_ptr(nullptr);
+ }
+
+ template <typename S, typename F>
+ bool for_all(pstring name, F lambda)
+ {
+ for (auto &s : m_collection)
+ {
+ auto source(dynamic_cast<S *>(s.get()));
+ if (source)
+ {
+ if (lambda(source))
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private:
+ list_t m_collection;
+ };
+
namespace util
{
+ pstring basename(pstring filename);
+ pstring path(pstring filename);
pstring buildpath(std::initializer_list<pstring> list );
pstring environment(const pstring &var, const pstring &default_val);
} // namespace util