1 // license:GPL-2.0+
2 // copyright-holders:Couriersud
3 
4 #ifndef PSOURCE_H_
5 #define PSOURCE_H_
6 
7 ///
8 /// \file putil.h
9 ///
10 
11 #include "palloc.h"
12 #include "pexception.h"
13 #include "pstream.h"
14 #include "pstring.h"
15 
16 #include <algorithm>
17 #include <initializer_list>
18 #include <sstream>
19 #include <vector>
20 
21 
22 #define PSOURCELOC() plib::source_location(__FILE__, __LINE__)
23 
24 namespace plib
25 {
26 
27 	/// \brief Source code locations.
28 	///
29 	/// The c++20 draft for source locations is based on const char * strings.
30 	/// It is thus only suitable for c++ source code and not for programmatic
31 	/// parsing of files. This class is a replacement for dynamic use cases.
32 	///
33 	struct source_location
34 	{
source_locationsource_location35 		source_location() noexcept
36 		: m_file("unknown"), m_func(m_file), m_line(0), m_col(0)
37 		{ }
38 
source_locationsource_location39 		source_location(pstring file, unsigned line) noexcept
40 		: m_file(std::move(file)), m_func("unknown"), m_line(line), m_col(0)
41 		{ }
42 
source_locationsource_location43 		source_location(pstring file, pstring func, unsigned line) noexcept
44 		: m_file(std::move(file)), m_func(std::move(func)), m_line(line), m_col(0)
45 		{ }
46 
47 		PCOPYASSIGNMOVE(source_location, default)
48 
49 		~source_location() = default;
50 
linesource_location51 		unsigned line() const noexcept { return m_line; }
columnsource_location52 		unsigned column() const noexcept { return m_col; }
file_namesource_location53 		pstring file_name() const noexcept { return m_file; }
function_namesource_location54 		pstring function_name() const noexcept { return m_func; }
55 
56 		source_location &operator ++() noexcept
57 		{
58 			++m_line;
59 			return *this;
60 		}
61 
62 	private:
63 		pstring m_file;
64 		pstring m_func;
65 		unsigned m_line;
66 		unsigned m_col;
67 	};
68 
69 	/// \brief Base source class.
70 	///
71 	/// Pure virtual class all other source implementations are based on.
72 	/// Sources provide an abstraction to read input from a variety of
73 	/// sources, e.g. files, memory, remote locations.
74 	///
75 	class psource_t
76 	{
77 	public:
78 
79 		psource_t() noexcept = default;
80 
81 		PCOPYASSIGNMOVE(psource_t, delete)
82 
83 		virtual ~psource_t() noexcept = default;
84 
85 		virtual istream_uptr stream(const pstring &name) = 0;
86 	private:
87 	};
88 
89 	/// \brief Generic string source.
90 	///
91 	/// Will return the given string when name matches.
92 	/// Is used in preprocessor code to eliminate inclusion of certain files.
93 	///
94 	class psource_str_t : public psource_t
95 	{
96 	public:
psource_str_t(pstring name,pstring str)97 		psource_str_t(pstring name, pstring str)
98 		: m_name(std::move(name)), m_str(std::move(str))
99 		{}
100 
101 		PCOPYASSIGNMOVE(psource_str_t, delete)
102 		~psource_str_t() noexcept override = default;
103 
stream(const pstring & name)104 		istream_uptr stream(const pstring &name) override
105 		{
106 			if (name == m_name)
107 				return istream_uptr(std::make_unique<std::stringstream>(putf8string(m_str)), name);
108 
109 			return istream_uptr();
110 		}
111 	private:
112 		pstring m_name;
113 		pstring m_str;
114 	};
115 
116 	/// \brief Generic sources collection.
117 	///
118 	class psource_collection_t
119 	{
120 	public:
121 		using source_ptr = std::unique_ptr<psource_t>;
122 		using list_t = std::vector<source_ptr>;
123 
124 		psource_collection_t() noexcept = default;
125 
126 		PCOPYASSIGNMOVE(psource_collection_t, delete)
127 		virtual ~psource_collection_t() noexcept = default;
128 
129 		template <typename S, typename... Args>
add_source(Args &&...args)130 		void add_source(Args&&... args)
131 		{
132 			static_assert(std::is_base_of<psource_t, S>::value, "S must inherit from plib::psource_t");
133 
134 			auto src(std::make_unique<S>(std::forward<Args>(args)...));
135 			m_collection.push_back(std::move(src));
136 		}
137 
138 		template <typename S = psource_t>
get_stream(pstring name)139 		istream_uptr get_stream(pstring name)
140 		{
141 			for (auto &s : m_collection)
142 			{
143 				auto *source(dynamic_cast<S *>(s.get()));
144 				if (source)
145 				{
146 					auto strm = source->stream(name);
147 					if (!strm.empty())
148 						return strm;
149 				}
150 			}
151 			return istream_uptr();
152 		}
153 
154 		template <typename S, typename F>
for_all(F lambda)155 		bool for_all(F lambda)
156 		{
157 			for (auto &s : m_collection)
158 			{
159 				auto *source(dynamic_cast<S *>(s.get()));
160 				if (source)
161 				{
162 					if (lambda(source))
163 						return true;
164 				}
165 			}
166 			return false;
167 		}
168 
169 	private:
170 		list_t m_collection;
171 	};
172 
173 } // namespace plib
174 
175 #endif // PSOURCE_H_
176