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