From: Mikko Rasa Date: Thu, 1 Jun 2023 07:17:56 +0000 (+0300) Subject: Add move semantics to Variant X-Git-Url: http://git.tdb.fi/?p=libs%2Fcore.git;a=commitdiff_plain;h=HEAD;hp=062b200b08ec5998c4c02326e1e7b4e71fe4a5c6 Add move semantics to Variant --- diff --git a/.gitignore b/.gitignore index 20ad67d..17d6cb8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,16 @@ .config temp /grep -/libmspcore.a -/libmspcore.so -/libmspcore.dylib +/grep.* +/libmspcore.* /ls -/mspcore.pc +/ls.* +/mspcore.* +/mspcore-* +/mspcore_static.* /syncdir -/tests/consoletest -/tests/test -/tests/test.txt +/syncdir.* /transcode +/transcode.* /z +/z.* diff --git a/examples/z.cpp b/examples/z.cpp index d98392c..5f793c4 100644 --- a/examples/z.cpp +++ b/examples/z.cpp @@ -24,7 +24,7 @@ public: }; Z::Z(int argc, char **argv): - input_file(0) + input_file(nullptr) { string input_fn; GetOpt getopt; diff --git a/source/core/algorithm.h b/source/core/algorithm.h index 268bf7b..43bbaee 100644 --- a/source/core/algorithm.h +++ b/source/core/algorithm.h @@ -2,6 +2,7 @@ #define MSP_CORE_ALGORITHM_H_ #include +#include namespace Msp { @@ -29,6 +30,20 @@ inline typename Container::const_iterator find_if(const Container &cont, Predica return std::find_if(cont.begin(), cont.end(), pred); } +template +struct ValueMatch +{ + const T &value; + + bool operator()(const T &v) { return v==value; } +}; + +template +inline bool any_equals(Container &cont, const T &value) +{ + return std::any_of(cont.begin(), cont.end(), ValueMatch{value}); +} + template inline typename Container::iterator lower_bound(Container &cont, const T &value) { @@ -107,32 +122,32 @@ struct MemberMatch const T &value; T C::*mem_ptr; - MemberMatch(const T &v, T C::*p): value(v), mem_ptr(p) { } - bool operator()(const C &obj) { return obj.*mem_ptr==value; } }; template inline typename Container::iterator find_member(Container &cont, const T &value, T Container::value_type::*mp) { - return find_if(cont, MemberMatch(value, mp)); + return find_if(cont, MemberMatch{ value, mp }); } template inline typename Container::const_iterator find_member(const Container &cont, const T &value, T Container::value_type::*mp) { - return find_if(cont, MemberMatch(value, mp)); + return find_if(cont, MemberMatch{ value, mp }); } -template +template> struct MemberCompare { T C::*mem_ptr; + P pred; MemberCompare(T C::*p): mem_ptr(p) { } - bool operator()(const C &obj, const T &v) { return obj.*mem_ptr diff --git a/source/core/android/errorlogger.h b/source/core/android/errorlogger.h index 4512f09..77fcec7 100644 --- a/source/core/android/errorlogger.h +++ b/source/core/android/errorlogger.h @@ -9,7 +9,7 @@ namespace Android { class ErrorLogger: public Debug::ErrorReporter { public: - virtual bool report_uncaught_exception(const std::exception &) const; + bool report_uncaught_exception(const std::exception &) const override; }; } // namespace Android diff --git a/source/core/android/main.cpp b/source/core/android/main.cpp index a71d92f..d6ad415 100644 --- a/source/core/android/main.cpp +++ b/source/core/android/main.cpp @@ -1,8 +1,9 @@ #include "mainthread.h" +#include "mspcore_api.h" -extern "C" void ANativeActivity_onCreate(ANativeActivity *activity, void * /*saved_state*/, size_t /*state_size*/) +extern "C" MSPCORE_API void ANativeActivity_onCreate(ANativeActivity *activity, void * /*saved_state*/, size_t /*state_size*/) { - static Msp::Android::MainThread *thread = 0; + static Msp::Android::MainThread *thread = nullptr; if(thread) thread->attach_to_activity(activity); else diff --git a/source/core/android/mainthread.cpp b/source/core/android/mainthread.cpp index 8ce484a..6441c20 100644 --- a/source/core/android/mainthread.cpp +++ b/source/core/android/mainthread.cpp @@ -15,8 +15,7 @@ namespace Android { MainThread::MainThread(ANativeActivity *a): asset_manager(a->assetManager), - int_data_path(a->internalDataPath), - starting_up(true) + int_data_path(a->internalDataPath) { attach_to_activity(a); startup_mutex.lock(); @@ -54,7 +53,7 @@ void MainThread::resume_startup() JavaVM *MainThread::get_java_vm() const { if(!activity) - return 0; + return nullptr; return activity->vm; } @@ -69,7 +68,7 @@ void MainThread::main() /* I have no idea how dependable this is, but it seems to be the only way to get the package name aside from making a Java call through JNI */ char *appname = strdup(int_data_path[-2].c_str()); - char *argv[] = { appname, 0 }; + char *argv[] = { appname, nullptr }; Msp::Android::ErrorLogger err_logger; FS::chdir(FS::dirname(int_data_path)); Msp::Application::run(1, argv, this, &app_created); diff --git a/source/core/android/mainthread.h b/source/core/android/mainthread.h index 609300f..ab587ff 100644 --- a/source/core/android/mainthread.h +++ b/source/core/android/mainthread.h @@ -20,10 +20,10 @@ public: sigc::signal signal_input_queue_destroyed; private: - ANativeActivity *activity; - AAssetManager *asset_manager; + ANativeActivity *activity = nullptr; + AAssetManager *asset_manager = nullptr; FS::Path int_data_path; - bool starting_up; + bool starting_up = true; Mutex startup_mutex; public: @@ -41,7 +41,7 @@ public: void set_window_flags(unsigned, unsigned); private: - virtual void main(); + void main() override; static void app_created(void *); static void activity_destroyed(ANativeActivity *); diff --git a/source/core/application.cpp b/source/core/application.cpp index 2c6dc96..c214a06 100644 --- a/source/core/application.cpp +++ b/source/core/application.cpp @@ -9,33 +9,33 @@ #include #include #include "application.h" +#include "except.h" #include "getopt.h" using namespace std; namespace Msp { -Application *Application::app_ = 0; -Application::Starter *Application::starter_ = 0; -const char *Application::argv0_ = 0; -string Application::name_; -void *Application::data_ = 0; +Application *Application::_app = nullptr; +Application::Starter *Application::_starter = nullptr; +const char *Application::_argv0 = nullptr; +string Application::_name; +void *Application::_data = nullptr; -Application::Application(const string &n): - exit_code(0) +Application::Application(const string &n) { - if(app_) - throw logic_error("instance already exists"); + if(_app) + throw already_called("Application::Application"); if(!n.empty()) - name_ = n; + _name = n; else - name_ = FS::basename(argv0_); + _name = FS::basename(_argv0); } int Application::run(int argc, char **argv, void *data, void (*created_callback)(void *)) { - if(!starter_) + if(!_starter) { IO::cerr.write("Application::run called with no RegisteredApplication class!\n"); return 126; @@ -47,7 +47,7 @@ int Application::run(int argc, char **argv, void *data, void (*created_callback) { try { - app_ = starter_->create_app(argc, argv); + _app = _starter->create_app(argc, argv); } catch(const usage_error &e) { @@ -58,9 +58,9 @@ int Application::run(int argc, char **argv, void *data, void (*created_callback) if(created_callback) created_callback(data); - int result = app_->main(); - Application *a = app_; - app_ = 0; + int result = _app->main(); + Application *a = _app; + _app = nullptr; delete a; return result; } @@ -85,8 +85,8 @@ int Application::run(int argc, char **argv, void *data, void (*created_callback) } } - delete app_; - app_ = 0; + delete _app; + _app = nullptr; return 124; } @@ -94,8 +94,8 @@ int Application::run(int argc, char **argv, void *data, void (*created_callback) void Application::set_startup_info(const char *argv0, void *data) { - if(argv0_) - throw logic_error("startup info already set"); + if(_argv0) + throw already_called("Application::set_startup_info"); static FS::Path exe; @@ -114,8 +114,23 @@ void Application::set_startup_info(const char *argv0, void *data) if(exe.empty()) exe = FS::realpath(argv0); - argv0_ = exe.c_str(); - data_ = data; + _argv0 = exe.c_str(); + _data = data; +} + +void *Application::get_data() +{ + return _data; +} + +const char *Application::get_argv0() +{ + return _argv0; +} + +const std::string &Application::get_name() +{ + return _name; } int Application::main() @@ -129,7 +144,7 @@ int Application::main() void Application::catch_signal(int s) { - signal(s, &sighandler_); + signal(s, &_sighandler); } void Application::exit(int c) @@ -138,18 +153,18 @@ void Application::exit(int c) exit_code = c; } -void Application::sighandler_(int s) +void Application::_sighandler(int s) { - app_->sighandler(s); + _app->sighandler(s); } Application::Starter::Starter() { - if(starter_) - throw logic_error("Can't create more than one Starter instance"); + if(_starter) + throw already_called("Application::Starter::Starter"); - starter_ = this; + _starter = this; } } // namespace Msp diff --git a/source/core/application.h b/source/core/application.h index 93fccd8..d5a571a 100644 --- a/source/core/application.h +++ b/source/core/application.h @@ -3,6 +3,7 @@ #include #include +#include "mspcore_api.h" #include "noncopyable.h" namespace Msp { @@ -10,35 +11,33 @@ namespace Msp { /** Base class for applications. See also RegisteredApplication. */ -class Application: private NonCopyable +class MSPCORE_API Application: private NonCopyable { protected: - class Starter + class MSPCORE_API Starter { protected: Starter(); public: - virtual ~Starter() { } + virtual ~Starter() = default; virtual Application *create_app(int, char **) = 0; }; - bool done; - int exit_code; + bool done = false; + int exit_code = 0; private: - static Starter *starter_; - static Application *app_; - static const char *argv0_; - static std::string name_; - static void *data_; - - Application(const Application &); - Application &operator=(const Application &); + static Starter *_starter; + static Application *_app; + static const char *_argv0; + static std::string _name; + static void *_data; + protected: Application(const std::string & = std::string()); public: - virtual ~Application() { } + virtual ~Application() = default; /** Constructs an instance of the registered application class and runs it. If the application throws a usage_error, a help message is printed. The @@ -46,7 +45,7 @@ public: This function can only be called once. The global main() function provided by the library normally does it automatically at program startup. */ - static int run(int, char **, void * = 0, void (*)(void *) = 0); + static int run(int, char **, void * = nullptr, void (*)(void *) = nullptr); /** Sets application startup info, including argv[0] value and platform- specific data. @@ -55,9 +54,9 @@ public: Application::run(). */ static void set_startup_info(const char *, void *); - static void *get_data() { return data_; } - static const char *get_argv0() { return argv0_; } - static const std::string &get_name() { return name_; } + static void *get_data(); + static const char *get_argv0(); + static const std::string &get_name(); protected: /** Default main loop. Calls tick() repeatedly until exit() is called. A @@ -78,7 +77,7 @@ protected: private: /** Static wrapper function to call a member function of the Application instance. */ - static void sighandler_(int); + static void _sighandler(int); }; @@ -96,16 +95,16 @@ private: Application *create_app(int argc, char **argv) { return new T(argc, argv); } }; - static Starter starter_; + static Starter _starter; protected: RegisteredApplication(const std::string &n = std::string()): Application(n) - { (void)starter_; } // Force the starter into existence + { (void)_starter; } // Force the starter into existence }; template -typename RegisteredApplication::Starter RegisteredApplication::starter_; +typename RegisteredApplication::Starter RegisteredApplication::_starter; } // namespace Msp diff --git a/source/core/environ.h b/source/core/environ.h index 67fde05..7fbca16 100644 --- a/source/core/environ.h +++ b/source/core/environ.h @@ -2,12 +2,13 @@ #define ENVIRON_H_ #include +#include "mspcore_api.h" namespace Msp { -std::string getenv(const std::string &); -void setenv(const std::string &, const std::string &); -void unsetenv(const std::string &); +MSPCORE_API std::string getenv(const std::string &); +MSPCORE_API void setenv(const std::string &, const std::string &); +MSPCORE_API void unsetenv(const std::string &); } // namespace Msp diff --git a/source/core/except.h b/source/core/except.h new file mode 100644 index 0000000..1673ff4 --- /dev/null +++ b/source/core/except.h @@ -0,0 +1,38 @@ +#ifndef MSP_CORE_EXCEPT_H_ +#define MSP_CORE_EXCEPT_H_ + +#include +#include "mspcore_api.h" + +namespace Msp { + +class MSPCORE_API invalid_state: public std::logic_error +{ +public: + invalid_state(const std::string &w): logic_error(w) { } +}; + + +class MSPCORE_API already_called: public invalid_state +{ +public: + already_called(const std::string &w): invalid_state(w) { } +}; + + +class MSPCORE_API unsupported: public std::logic_error +{ +public: + unsupported(const std::string &w): logic_error(w) { } +}; + + +class MSPCORE_API internal_error: public std::logic_error +{ +public: + internal_error(const std::string &w): logic_error(w) { } +}; + +} // namespace Msp; + +#endif diff --git a/source/core/getopt.cpp b/source/core/getopt.cpp index 13e235f..cbc0afb 100644 --- a/source/core/getopt.cpp +++ b/source/core/getopt.cpp @@ -6,8 +6,7 @@ using namespace std; namespace Msp { -GetOpt::GetOpt(): - help(false) +GetOpt::GetOpt() { add_option("help", help, NO_ARG).set_help("Displays this help"); } @@ -318,9 +317,6 @@ GetOpt::OptionImpl::OptionImpl(char s, const string &l, const Store &t, ArgType shrt(s), lng(l), arg_type(a), - seen_count(0), - ext_seen_count(0), - metavar("ARG"), store(t.clone()) { } diff --git a/source/core/getopt.h b/source/core/getopt.h index 405864b..59c810c 100644 --- a/source/core/getopt.h +++ b/source/core/getopt.h @@ -6,20 +6,20 @@ #include #include #include +#include "mspcore_api.h" #include "noncopyable.h" namespace Msp { -class usage_error: public std::runtime_error +class MSPCORE_API usage_error: public std::runtime_error { private: - std::string help_; + std::string m_help; public: - usage_error(const std::string &w, const std::string &h = std::string()): std::runtime_error(w), help_(h) { } - ~usage_error() throw() { } + usage_error(const std::string &w, const std::string &h = std::string()): std::runtime_error(w), m_help(h) { } - const char *help() const throw() { return help_.c_str(); } + const char *help() const noexcept { return m_help.c_str(); } }; @@ -59,7 +59,7 @@ A built-in --help option is provided and will output a list of options, arguments and their associated help texts. An application may override this by providing its own option with the same name. */ -class GetOpt: private NonCopyable +class MSPCORE_API GetOpt: private NonCopyable { public: enum ArgType @@ -69,12 +69,12 @@ public: REQUIRED_ARG }; - class Option + class MSPCORE_API Option { protected: - Option() { } + Option() = default; public: - virtual ~Option() { } + virtual ~Option() = default; /// Sets help text for the option. virtual Option &set_help(const std::string &) = 0; @@ -89,12 +89,12 @@ public: virtual unsigned get_seen_count() const = 0; }; - class Argument + class MSPCORE_API Argument { protected: - Argument() { } + Argument() = default; public: - virtual ~Argument() { } + virtual ~Argument() = default; virtual Argument &set_help(const std::string &) = 0; }; @@ -103,9 +103,9 @@ private: class Store { protected: - Store() { } + Store() = default; public: - virtual ~Store() { } + virtual ~Store() = default; virtual Store *clone() const = 0; @@ -117,28 +117,28 @@ private: class OptionImpl: public Option { protected: - char shrt; + char shrt = 0; std::string lng; - ArgType arg_type; - unsigned seen_count; - unsigned *ext_seen_count; + ArgType arg_type = NO_ARG; + unsigned seen_count = 0; + unsigned *ext_seen_count = nullptr; std::string help; - std::string metavar; - Store *store; + std::string metavar = "ARG"; + Store *store = nullptr; public: OptionImpl(char, const std::string &, const Store &, ArgType); - virtual ~OptionImpl(); + ~OptionImpl() override; - virtual OptionImpl &set_help(const std::string &); - virtual OptionImpl &set_help(const std::string &, const std::string &); - virtual OptionImpl &bind_seen_count(unsigned &); + OptionImpl &set_help(const std::string &) override; + OptionImpl &set_help(const std::string &, const std::string &) override; + OptionImpl &bind_seen_count(unsigned &) override; char get_short() const { return shrt; } const std::string &get_long() const { return lng; } ArgType get_arg_type() const { return arg_type; } const std::string &get_help() const { return help; } const std::string &get_metavar() const { return metavar; } - virtual unsigned get_seen_count() const { return seen_count; } + unsigned get_seen_count() const override { return seen_count; } void process(); void process(const std::string &); }; @@ -147,15 +147,15 @@ private: { private: std::string name; - ArgType type; + ArgType type = REQUIRED_ARG; std::string help; - Store *store; + Store *store = nullptr; public: ArgumentImpl(const std::string &, const Store &, ArgType); - virtual ~ArgumentImpl(); + ~ArgumentImpl() override; - virtual ArgumentImpl &set_help(const std::string &); + ArgumentImpl &set_help(const std::string &) override; const std::string &get_name() const { return name; } ArgType get_type() const { return type; } const std::string &get_help() const { return help; } @@ -172,14 +172,14 @@ private: public: SimpleStore(T &d): data(d) { } - virtual SimpleStore *clone() const + SimpleStore *clone() const override { return new SimpleStore(data); } - virtual bool is_list() const { return false; } + bool is_list() const override { return false; } - virtual void store() { } + void store() override { } - virtual void store(const std::string &a) + void store(const std::string &a) override { data = lexical_cast(a); } }; @@ -192,18 +192,18 @@ private: public: ListStore(T &d): data(d) { } - virtual ListStore *clone() const + ListStore *clone() const override { return new ListStore(data); } - virtual bool is_list() const { return true; } + bool is_list() const override { return true; } - virtual void store() { } + void store() override { } - virtual void store(const std::string &a) + void store(const std::string &a) override { data.push_back(lexical_cast(a)); } }; - bool help; + bool help = false; std::vector opts; std::vector args; std::vector args_raw; diff --git a/source/core/hash.cpp b/source/core/hash.cpp deleted file mode 100644 index fe5e339..0000000 --- a/source/core/hash.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include -#include "hash.h" - -using namespace std; - -namespace Msp { - -/* -http://en.wikipedia.org/wiki/Fowler-Noll-Vo_hash_function -http://www.isthe.com/chongo/tech/comp/fnv/index.html -*/ - -UInt32 hash32(const void *data, unsigned size, unsigned bits) -{ - if(bits==0 || bits>32) - throw invalid_argument("hash32"); - - static const unsigned prime = 16777619; - static const unsigned offset = 2166136261U; - - unsigned result = offset; - for(unsigned i=0; i(data)+i))*prime; - - if(bits<32) - result = (result>>bits ^ result) & ((1<64) - throw invalid_argument("hash64"); - - static const UInt64 prime = 1099511628211ULL; - static const UInt64 offset = 14695981039346656037ULL; - - UInt64 result = offset; - for(unsigned i=0; i(data)+i))*prime; - - if(bits<64) - result = (result>>bits ^ result) & ((1ULL< +#include #include -#include "inttypes.h" namespace Msp { +template8)+(N>16)+(N>32)+(N>64)> +struct HashTraits; + +template<> +struct HashTraits<64, 6> +{ + using HashType = uint64_t; + using ResultType = uint64_t; + static constexpr HashType prime = 1099511628211ULL; + static constexpr HashType offset = 14695981039346656037ULL; + static constexpr bool folded = false; +}; + +template<> +struct HashTraits<32, 5> +{ + using HashType = uint32_t; + using ResultType = uint32_t; + static constexpr HashType prime = 16777619; + static constexpr HashType offset = 2166136261U; + static constexpr bool folded = false; +}; + +template +struct HashTraits +{ + using HashType = uint64_t; + using ResultType = uint64_t; + static constexpr bool folded = true; +}; + +template +struct HashTraits +{ + using HashType = uint32_t; + using ResultType = uint32_t; + static constexpr bool folded = true; +}; + +template +struct HashTraits +{ + using HashType = uint32_t; + using ResultType = uint16_t; + static constexpr bool folded = true; +}; + +template +struct HashTraits +{ + using HashType = uint32_t; + using ResultType = uint8_t; + static constexpr bool folded = true; +}; + /** -Computes a 32-bit Fowler-Noll-Vo (FNV-1a) hash. The number of bits can be -limited to less than 32, in which case XOR-folding is used to reduce the hash -size. +Computes a single round of a hash, adding one byte of data. N must be a native +hash size. */ -UInt32 hash32(const void *, unsigned, unsigned = 32); +template +typename HashTraits::ResultType hash_round(typename HashTraits::HashType result, uint8_t byte) +{ + constexpr typename HashTraits::HashType prime = HashTraits::prime; + return (result^byte)*prime; +} /** -Convenience function to compute a 32-bit hash of a string. +Updates a previously computed hash by adding bytes to it. N must be a native +hash size. */ -inline unsigned hash32(const std::string &s, unsigned b = 32) -{ return hash32(s.data(), s.size(), b); } +template +typename HashTraits::ResultType hash_update(typename HashTraits::HashType result, const void *data, std::size_t size) +{ + const uint8_t *ptr = static_cast(data); + for(unsigned i=0; i(result, *ptr++); + return result; +} + +template +typename HashTraits::ResultType hash_update(typename HashTraits::HashType result, const std::string &str) +{ return hash_update(result, str.data(), str.size()); } + +// For some reason this causes an ambiguity error without the enable_if. +template +typename std::enable_if::value, typename HashTraits::ResultType>::type hash_update(typename HashTraits::HashType result, const T &obj) +{ return hash_update(result, &obj, sizeof(obj)); } /** -Computes a 64-bit Fowler-Noll-Vo (FNV-1a) hash. Note that even if bits is -limited to 32 or less, this does not produce the same result as hash32. +Manually folds a hash to a smaller size. */ -UInt64 hash64(const void *, unsigned, unsigned = 64); +template +typename std::enable_if::digits, typename HashTraits::ResultType>::type hash_fold(T hash) +{ return (hash>>N ^ hash) & ((T(1)< +typename std::enable_if::digits, typename HashTraits::ResultType>::type hash_fold(T hash) +{ return hash; } /** -Convenience function to compute a 64-bit hash of a string. +Computes an N-bit Fowler-Noll-Vo (FNV-1a) hash. If N is not a native hash +size, the next larger native hash is computed and XOR-folding is applied to +the result. + +http://en.wikipedia.org/wiki/Fowler-Noll-Vo_hash_function +http://www.isthe.com/chongo/tech/comp/fnv/index.html */ -inline UInt64 hash64(const std::string &s, unsigned b = 64) -{ return hash64(s.data(), s.size(), b); } +template +typename HashTraits::ResultType hash(const void *data, std::size_t size) +{ + constexpr unsigned hash_bits = std::numeric_limits::HashType>::digits; + typename HashTraits::HashType result = hash_update(HashTraits::offset, data, size); + if(HashTraits::folded) + result = hash_fold(result); + return result; +} -inline UInt32 fold32(UInt64 hash) -{ return hash^(hash>>32); } +/** +Convenience function to compute an N-bit hash of a string. +*/ +template +typename HashTraits::ResultType hash(const std::string &str) +{ return hash(str.data(), str.size()); } -inline UInt16 fold16(UInt64 hash) -{ return hash^(hash>>16)^(hash>>32)^(hash>>48); } +/** +Convenience function to compute an N-bit hash of any object. The entire object +representation is hashed, including any padding bytes. +*/ +template +typename HashTraits::ResultType hash(const T &obj) +{ return hash(&obj, sizeof(obj)); } } // namespace Msp diff --git a/source/core/maputils.h b/source/core/maputils.h index 88f47cd..9a72d4d 100644 --- a/source/core/maputils.h +++ b/source/core/maputils.h @@ -4,6 +4,7 @@ #include #include #include +#include "mspcore_api.h" namespace Msp { @@ -39,7 +40,7 @@ static std::string stringify_key(const T &k) } // namespace Internal -class key_error: public std::runtime_error +class MSPCORE_API key_error: public std::runtime_error { public: template @@ -47,7 +48,7 @@ public: runtime_error(make_what(typeid(T), MapUtilsInternal::stringify_key(k))) { } - virtual ~key_error() throw() { } + ~key_error() throw() override = default; private: static std::string make_what(const std::type_info &, const std::string &); diff --git a/source/core/module.h b/source/core/module.h index 4a2f04c..64d761f 100644 --- a/source/core/module.h +++ b/source/core/module.h @@ -2,16 +2,17 @@ #define MSP_CORE_MODULE_H_ #include +#include "mspcore_api.h" #include "noncopyable.h" namespace Msp { -class Module: private NonCopyable +class MSPCORE_API Module: private NonCopyable { private: struct Private; - Private *priv; + Private *priv = nullptr; public: Module(const std::string &); diff --git a/source/core/mspcore_api.h b/source/core/mspcore_api.h new file mode 100644 index 0000000..eed6bcc --- /dev/null +++ b/source/core/mspcore_api.h @@ -0,0 +1,18 @@ +#ifndef MSP_CORE_API_H_ +#define MSP_CORE_API_H_ + +#if defined(_WIN32) +#if defined(MSPCORE_BUILD) +#define MSPCORE_API __declspec(dllexport) +#elif defined(MSPCORE_IMPORT) +#define MSPCORE_API __declspec(dllimport) +#else +#define MSPCORE_API +#endif +#elif defined(__GNUC__) +#define MSPCORE_API __attribute__((visibility("default"))) +#else +#define MSPCORE_API +#endif + +#endif diff --git a/source/core/mutex.h b/source/core/mutex.h index 3d3dc84..a48f58c 100644 --- a/source/core/mutex.h +++ b/source/core/mutex.h @@ -1,6 +1,7 @@ #ifndef MSP_CORE_MUTEX_H_ #define MSP_CORE_MUTEX_H_ +#include "mspcore_api.h" #include "noncopyable.h" #include "refptr.h" @@ -10,14 +11,14 @@ namespace Msp { A class for controlling mutually exclusive access to a resource. Only one thread can hold a lock on the mutex at a time. */ -class Mutex: private NonCopyable +class MSPCORE_API Mutex: private NonCopyable { friend class Semaphore; private: struct Private; - Private *priv; + Private *priv = nullptr; public: Mutex(); @@ -38,7 +39,7 @@ public: /** Locks the mutex for the lifetime of the object. */ -class MutexLock +class MSPCORE_API MutexLock { private: Mutex &mutex; @@ -67,7 +68,7 @@ public: T &operator*() const { return *data; } T *operator->() const { return data; } - void clear() { mutex = 0; data = 0; } + void clear() { mutex = nullptr; data = nullptr; } }; } diff --git a/source/core/noncopyable.h b/source/core/noncopyable.h index c948c57..78f9e66 100644 --- a/source/core/noncopyable.h +++ b/source/core/noncopyable.h @@ -1,9 +1,11 @@ #ifndef MSP_CORE_NONCOPYABLE_H_ #define MSP_CORE_NONCOPYABLE_H_ +#include "mspcore_api.h" + namespace Msp { -class NonCopyable +class MSPCORE_API NonCopyable { protected: NonCopyable() = default; diff --git a/source/core/osx/main.cpp b/source/core/osx/main.cpp index e9a6fe2..55d4a30 100644 --- a/source/core/osx/main.cpp +++ b/source/core/osx/main.cpp @@ -1,9 +1,10 @@ #include #include "application.h" +#include "mspcore_api.h" -int main(int argc, char **argv) +MSPCORE_API int main(int argc, char **argv) { - void *data = 0; + void *data = nullptr; /* Applications launched from Finder get a special argument, which would interfere with GetOpt. Remove it from argv but pass it as data so it can @@ -17,7 +18,7 @@ int main(int argc, char **argv) argv[j++] = argv[i]; } argc = j; - argv[j] = 0; + argv[j] = nullptr; return Msp::Application::run(argc, argv, data); } diff --git a/source/core/process.cpp b/source/core/process.cpp index dfbea34..4c5ed46 100644 --- a/source/core/process.cpp +++ b/source/core/process.cpp @@ -1,4 +1,5 @@ #include +#include "except.h" #include "process.h" #include "process_private.h" @@ -6,30 +7,15 @@ using namespace std; namespace Msp { -Process *Process::_self = 0; +Process *Process::_self = nullptr; Process::Process(const Private &p): priv(new Private(p)) -{ - init(); -} +{ } Process::Process(): priv(new Private) -{ - init(); -} - -void Process::init() -{ - redirect = false; - cin = 0; - cout = 0; - cerr = 0; - running = false; - finished = false; - exit_code = 0; -} +{ } Process &Process::self() { @@ -93,7 +79,7 @@ void Process::execute(const FS::Path &command, const Arguments &args) unsigned Process::get_exit_code() const { if(!finished) - throw logic_error("not finished"); + throw invalid_state("not finished"); return exit_code; } diff --git a/source/core/process.h b/source/core/process.h index 55b62cd..ed997f8 100644 --- a/source/core/process.h +++ b/source/core/process.h @@ -5,6 +5,7 @@ #include #include #include +#include "mspcore_api.h" #include "noncopyable.h" namespace Msp { @@ -22,7 +23,7 @@ the process or capture its output, use an IO::Pipe. Redirections performed on the self object take effect immediately. It is recommended to perform such redirections directly on the Console objects. */ -class Process: private NonCopyable +class MSPCORE_API Process: private NonCopyable { public: typedef std::vector Arguments; @@ -30,20 +31,19 @@ public: private: struct Private; - Private *priv; + Private *priv = nullptr; FS::Path work_dir; - bool redirect; - IO::Base *cin; - IO::Base *cout; - IO::Base *cerr; - bool running; - bool finished; - unsigned exit_code; + bool redirect = false; + IO::Base *cin = nullptr; + IO::Base *cout = nullptr; + IO::Base *cerr = nullptr; + bool running = false; + bool finished = false; + unsigned exit_code = 0; static Process *_self; Process(const Private &); - void init(); public: Process(); ~Process(); diff --git a/source/core/process_private.h b/source/core/process_private.h index f6f4f2e..fcae0f0 100644 --- a/source/core/process_private.h +++ b/source/core/process_private.h @@ -1,6 +1,7 @@ #ifndef MSP_CORE_PROCESS_PRIVATE_H_ #define MSP_CORE_PROCESS_PRIVATE_H_ +#include "process.h" #include "process_platform.h" namespace Msp { diff --git a/source/core/refptr.h b/source/core/refptr.h index a2160a5..1a164c1 100644 --- a/source/core/refptr.h +++ b/source/core/refptr.h @@ -10,10 +10,8 @@ struct RefCounts KEEP = 1U<<(sizeof(unsigned)*8-1) }; - unsigned count; - unsigned weak_count; - - RefCounts(): count(0), weak_count(0) { } + unsigned count = 0; + unsigned weak_count = 0; }; template @@ -31,14 +29,14 @@ class RefPtr template friend class WeakPtr; private: - T *data; - RefCounts *counts; + T *data = nullptr; + RefCounts *counts = nullptr; public: - RefPtr(): data(0), counts(0) { } - RefPtr(T *d): data(d), counts(data ? new RefCounts : 0) { incref(); } + RefPtr() = default; + RefPtr(T *d): data(d), counts(data ? new RefCounts : nullptr) { incref(); } private: - RefPtr(T *d, RefCounts *c): data(d), counts(d ? c : 0) { incref(); } + RefPtr(T *d, RefCounts *c): data(d), counts(d ? c : nullptr) { incref(); } public: /* Must have this or the compiler will generate a default copy-c'tor despite @@ -49,7 +47,7 @@ public: RefPtr(const RefPtr &p): data(p.data), counts(p.counts) { incref(); } template - RefPtr(const WeakPtr &p): data(p.get()), counts(data ? p.counts : 0) { incref(); } + RefPtr(const WeakPtr &p): data(p.get()), counts(data ? p.counts : nullptr) { incref(); } ~RefPtr() { decref(); } @@ -81,7 +79,7 @@ public: T *get() const { return data; } T &operator*() const { return *data; } T *operator->() const { return data; } - operator bool() const { return data!=0; } + explicit operator bool() const { return data; } unsigned refcount() const { return (data ? counts->count : 0); } @@ -102,19 +100,19 @@ class WeakPtr template friend class WeakPtr; private: - T *data; - RefCounts *counts; + T *data = nullptr; + RefCounts *counts = nullptr; public: - WeakPtr(): data(0), counts(0) { } + WeakPtr() = default; private: - WeakPtr(T *d, RefCounts *c): data(d), counts(d ? c : 0) { incref(); } + WeakPtr(T *d, RefCounts *c): data(d), counts(d ? c : nullptr) { incref(); } public: - WeakPtr(const WeakPtr &p): data(p.get()), counts(data ? p.counts : 0) { incref(); } + WeakPtr(const WeakPtr &p): data(p.get()), counts(data ? p.counts : nullptr) { incref(); } template - WeakPtr(const WeakPtr &p): data(p.get()), counts(data ? p.counts : 0) { incref(); } + WeakPtr(const WeakPtr &p): data(p.get()), counts(data ? p.counts : nullptr) { incref(); } template WeakPtr(const RefPtr &p): data(p.data), counts(p.counts) { incref(); } @@ -131,7 +129,7 @@ private: template WeakPtr &assign(const WeakPtr &); - T *get() const { return (counts && counts->count ? data : 0); } + T *get() const { return (counts && counts->count ? data : nullptr); } void incref() { if(counts) ++counts->weak_count; } void decref(); }; @@ -142,7 +140,7 @@ RefPtr &RefPtr::operator=(T *d) { decref(); data = d; - counts = (d ? new RefCounts : 0); + counts = (d ? new RefCounts : nullptr); incref(); return *this; } @@ -151,6 +149,9 @@ template template RefPtr &RefPtr::assign(const RefPtr &p) { + if(static_cast(&p)==this) + return *this; + decref(); data = p.data; counts = p.counts; @@ -162,9 +163,9 @@ template T *RefPtr::release() { T *d = data; - data = 0; + data = nullptr; decref(); - counts = 0; + counts = nullptr; return d; } @@ -176,17 +177,17 @@ void RefPtr::decref() if(!counts->count) { delete data; - data = 0; + data = nullptr; } else if(counts->count==RefCounts::KEEP) - data = 0; + data = nullptr; else return; if(!counts->weak_count) { delete counts; - counts = 0; + counts = nullptr; } } @@ -195,9 +196,12 @@ template template WeakPtr &WeakPtr::assign(const WeakPtr &p) { + if(&p==this) + return *this; + decref(); data = p.get(); - counts = (data ? p.counts : 0); + counts = (data ? p.counts : nullptr); incref(); return *this; } @@ -210,8 +214,8 @@ void WeakPtr::decref() if(!counts->weak_count && (!counts->count || counts->count==RefCounts::KEEP)) { delete counts; - data = 0; - counts = 0; + data = nullptr; + counts = nullptr; } } diff --git a/source/core/semaphore.h b/source/core/semaphore.h index 9ab25f2..f504289 100644 --- a/source/core/semaphore.h +++ b/source/core/semaphore.h @@ -2,16 +2,17 @@ #define MSP_CORE_SEMAPHORE_H_ #include +#include "mspcore_api.h" #include "noncopyable.h" namespace Msp { -class Semaphore: private NonCopyable +class MSPCORE_API Semaphore: private NonCopyable { private: struct Private; - Private *priv; + Private *priv = nullptr; public: Semaphore(unsigned); diff --git a/source/core/systemerror.cpp b/source/core/systemerror.cpp index 5424ef0..c6fd341 100644 --- a/source/core/systemerror.cpp +++ b/source/core/systemerror.cpp @@ -7,12 +7,12 @@ namespace Msp { system_error::system_error(const string &w, int c): runtime_error(w+": "+get_message(c)), - code_(c) + m_code(c) { } system_error::system_error(const string &w, const string &e): runtime_error(w+": "+e), - code_(numeric_limits::min()) + m_code(numeric_limits::min()) { } } // namespace Msp diff --git a/source/core/systemerror.h b/source/core/systemerror.h index c6b516a..cce3c5c 100644 --- a/source/core/systemerror.h +++ b/source/core/systemerror.h @@ -3,20 +3,20 @@ #include #include +#include "mspcore_api.h" namespace Msp { -class system_error: public std::runtime_error +class MSPCORE_API system_error: public std::runtime_error { private: - int code_; + int m_code; public: system_error(const std::string &, int = -1); system_error(const std::string &, const std::string &); - virtual ~system_error() throw() { } - int code() const throw() { return code_; } + int code() const noexcept { return m_code; } private: static std::string get_message(int); diff --git a/source/core/thread.cpp b/source/core/thread.cpp index 721e8cf..ad78d94 100644 --- a/source/core/thread.cpp +++ b/source/core/thread.cpp @@ -1,4 +1,4 @@ -#include +#include "except.h" #include "thread.h" #include "thread_private.h" @@ -7,43 +7,42 @@ using namespace std; namespace Msp { Thread::Thread(const string &name): - priv_(new Private), - name_(name), - state_(PENDING) + _priv(new Private), + _name(name) { } Thread::~Thread() { kill(); join(); - delete priv_; + delete _priv; } void Thread::join() { - if(state_>=JOINED) + if(_state>=JOINED) return; platform_join(); - state_ = JOINED; + _state = JOINED; } void Thread::kill() { - if(state_!=RUNNING) + if(_state!=RUNNING) return; platform_kill(); - state_ = KILLED; + _state = KILLED; } void Thread::launch() { - if(state_>=RUNNING) - throw logic_error("already launched"); + if(_state>=RUNNING) + throw already_called("Thread::launch"); platform_launch(); - state_ = RUNNING; + _state = RUNNING; } ThreadReturn THREAD_CALL Thread::Private::main_wrapper(void *arg) @@ -51,7 +50,7 @@ ThreadReturn THREAD_CALL Thread::Private::main_wrapper(void *arg) Thread *thread = reinterpret_cast(arg); thread->platform_setname(); thread->main(); - thread->state_ = FINISHED; + thread->_state = FINISHED; return 0; } diff --git a/source/core/thread.h b/source/core/thread.h index 6a17912..71acb22 100644 --- a/source/core/thread.h +++ b/source/core/thread.h @@ -2,6 +2,7 @@ #define MSP_CORE_THREAD_H_ #include +#include "mspcore_api.h" #include "noncopyable.h" namespace Msp { @@ -13,7 +14,7 @@ automatically started upon creation - you must manually call launch() instead. This is to allow initializing variables of the derived class before the thread is started. */ -class Thread: private NonCopyable +class MSPCORE_API Thread: private NonCopyable { private: struct Private; @@ -27,19 +28,19 @@ private: JOINED }; - Private *priv_; - std::string name_; - State state_; + Private *_priv = nullptr; + std::string _name; + State _state = PENDING; protected: Thread(const std::string & = std::string()); public: virtual ~Thread(); - const std::string &get_name() const { return name_; } + const std::string &get_name() const { return _name; } /** Indicates whether the thread has finished running. */ - bool is_finished() { return state_>=FINISHED; } + bool is_finished() { return _state>=FINISHED; } /** Waits for the thread to exit. Calling this from the thread will cause a deadlock. */ diff --git a/source/core/thread_private.h b/source/core/thread_private.h index 3c3b341..f133d60 100644 --- a/source/core/thread_private.h +++ b/source/core/thread_private.h @@ -8,9 +8,7 @@ namespace Msp { struct Thread::Private { - ThreadHandle handle; - - Private(): handle(0) { } + ThreadHandle handle = 0; static ThreadReturn THREAD_CALL main_wrapper(void *); }; diff --git a/source/core/typeregistry.h b/source/core/typeregistry.h index dd5dc01..193fe07 100644 --- a/source/core/typeregistry.h +++ b/source/core/typeregistry.h @@ -40,7 +40,7 @@ private: RegisteredType(const std::string &kw): TypeBase(kw) { } - virtual void invoke(T arg) const { action(this->keyword, arg); } + void invoke(T arg) const override { action(this->keyword, arg); } }; std::map types; diff --git a/source/core/unix/main.cpp b/source/core/unix/main.cpp index 434dba1..010459f 100644 --- a/source/core/unix/main.cpp +++ b/source/core/unix/main.cpp @@ -1,6 +1,7 @@ #include "application.h" +#include "mspcore_api.h" -int main(int argc, char **argv) +MSPCORE_API int main(int argc, char **argv) { - return Msp::Application::run(argc, argv, 0); + return Msp::Application::run(argc, argv, nullptr); } diff --git a/source/core/unix/mutex.cpp b/source/core/unix/mutex.cpp index 15e5c9a..a23add5 100644 --- a/source/core/unix/mutex.cpp +++ b/source/core/unix/mutex.cpp @@ -9,7 +9,7 @@ namespace Msp { Mutex::Mutex(): priv(new Private) { - pthread_mutex_init(&priv->mutex, 0); + pthread_mutex_init(&priv->mutex, nullptr); } Mutex::~Mutex() diff --git a/source/core/unix/process.cpp b/source/core/unix/process.cpp index 99be2e1..ee0a36d 100644 --- a/source/core/unix/process.cpp +++ b/source/core/unix/process.cpp @@ -4,6 +4,7 @@ #include #include #include +#include "except.h" #include "process.h" #include "process_private.h" @@ -12,7 +13,9 @@ using namespace std; namespace Msp { Process::~Process() -{ } +{ + delete priv; +} void Process::platform_get_self_info(Private &priv) { @@ -35,7 +38,7 @@ void Process::execute(const string &command, bool path_search, const Arguments & argv[0] = command.c_str(); for(unsigned i=0; iinfo.pid, &status, (block ? 0 : WNOHANG)); diff --git a/source/core/unix/semaphore.cpp b/source/core/unix/semaphore.cpp index 8149258..f19bdab 100644 --- a/source/core/unix/semaphore.cpp +++ b/source/core/unix/semaphore.cpp @@ -14,17 +14,16 @@ struct Semaphore::Private { Mutex mutex; pthread_cond_t cond; - unsigned limit; - unsigned count; + unsigned limit = 1; + unsigned count = 0; }; Semaphore::Semaphore(unsigned limit): priv(new Private) { - pthread_cond_init(&priv->cond, 0); + pthread_cond_init(&priv->cond, nullptr); priv->limit = limit; - priv->count = 0; } Semaphore::~Semaphore() diff --git a/source/core/unix/thread.cpp b/source/core/unix/thread.cpp index 119d55f..4223193 100644 --- a/source/core/unix/thread.cpp +++ b/source/core/unix/thread.cpp @@ -7,24 +7,24 @@ namespace Msp { void Thread::platform_join() { - pthread_join(priv_->handle, 0); + pthread_join(_priv->handle, nullptr); } void Thread::platform_kill() { - pthread_kill(priv_->handle, SIGKILL); + pthread_kill(_priv->handle, SIGKILL); } void Thread::platform_launch() { - pthread_create(&priv_->handle, 0, &Private::main_wrapper, this); + pthread_create(&_priv->handle, nullptr, &Private::main_wrapper, this); } void Thread::platform_setname() { #if defined(__GLIBC__) && (__GLIBC__>2 || (__GLIBC__==2 && __GLIBC_MINOR__>=12)) - if(!name_.empty()) - pthread_setname_np(priv_->handle, name_.c_str()); + if(!_name.empty()) + pthread_setname_np(_priv->handle, _name.c_str()); #endif } diff --git a/source/core/variant.h b/source/core/variant.h index 5109dbc..5cb1b93 100644 --- a/source/core/variant.h +++ b/source/core/variant.h @@ -5,119 +5,217 @@ #include #include #include "meta.h" +#include "mspcore_api.h" namespace Msp { -class type_mismatch: public std::runtime_error +class MSPCORE_API type_mismatch: public std::runtime_error { public: type_mismatch(const std::type_info &, const std::type_info &); - ~type_mismatch() throw() { } }; -class Variant +class MSPCORE_API Variant { -private: - struct StoreBase - { - virtual ~StoreBase() { } +public: + static constexpr unsigned INTERNAL_SIZE = 2*sizeof(void *); - virtual const std::type_info &type_id() const = 0; - virtual StoreBase *clone() const = 0; - virtual bool type_equals(const StoreBase &) const = 0; - virtual bool value_equals(const StoreBase &) const = 0; + struct Functions + { + const std::type_info &(*get_type)(); + bool (*compare)(const char *, const char *); + void (*clone)(char *, const char *); + void (*move)(char *, char *); + void (*destroy)(char *); }; +private: template - struct Store: public StoreBase - { - T data; + using EnableNotVariant = typename std::enable_if::type>::type, Variant>::value>::type; - Store(const T &d): data(d) { } + const Functions *funcs = nullptr; + alignas(void *) char storage[INTERNAL_SIZE]; - virtual const std::type_info &type_id() const { return typeid(T); } - virtual StoreBase *clone() const { return new Store(data); } - virtual bool type_equals(const StoreBase &s) const { return dynamic_cast *>(&s); } - virtual bool value_equals(const StoreBase &s) const { return value_equals_(s); } +public: + Variant() = default; + template> + Variant(T &&v) { assign(std::forward(v)); } + Variant(const Variant &v) { copy_from(v); } + Variant(Variant &&v) { move_from(std::move(v)); } + ~Variant() { clear(); } - template - typename std::enable_if::value, bool>::type value_equals_(const StoreBase &s) const - { const Store *t = dynamic_cast *>(&s); return (t && t->data==data); } + template> + Variant &operator=(T &&v) { assign(std::forward(v)); return *this; } - template - typename std::enable_if::value, bool>::type value_equals_(const StoreBase &) const - { return false; } - }; + Variant &operator=(const Variant &v) { if(&v!=this) copy_from(v); return *this; } + Variant &operator=(Variant &&v) { if(&v!=this) move_from(std::move(v)); return *this; } - StoreBase *store; + void clear(); + +private: + template + void assign(T &&); + + void copy_from(const Variant &); + void move_from(Variant &&); + + template + T &get(); public: - Variant(): store(0) { } template - Variant(const T &v): store(new Store::type>(v)) { } - Variant(const Variant &v): store(v.store ? v.store->clone() : 0) { } - ~Variant() { delete store; } + T &value() { return get(); } template - Variant &operator=(const T &v) - { - delete store; - store = new Store::type>(v); - return *this; - } + const T &value() const { return const_cast(this)->get(); } - Variant &operator=(const Variant &v) - { - delete store; - store = (v.store ? v.store->clone() : 0); - return *this; - } + template + bool has_type() const { return type_equals(funcs, get_functions::type>()); } + + bool has_same_type(const Variant &v) const { return type_equals(funcs, v.funcs); } + + template + DEPRECATED bool check_type() const { return has_type(); } + + DEPRECATED bool check_same_type(const Variant &v) const { return has_same_type(v); } + + bool operator==(const Variant &v) const { return (has_same_type(v) && funcs->compare(storage, v.storage)); } + bool operator!=(const Variant &v) const { return !(operator==(v)); } + + template + operator T() const { return value(); } private: + static bool type_equals(const Functions *, const Functions *); + template - Store::type> *get_typed_store() const - { - typedef typename std::remove_cv::type NCT; - Store *s = dynamic_cast *>(store); - if(!s) - throw type_mismatch(typeid(T), (store ? store->type_id() : typeid(void))); - return s; - } + static constexpr bool is_small() { return (sizeof(T)<=INTERNAL_SIZE && alignof(T)<=alignof(void *)); } + + template + using EnableSmall = typename std::enable_if(), U>::type; + + template + using EnableLarge = typename std::enable_if(), U>::type; -public: template - T &value() - { - return get_typed_store()->data; - } + static const Functions *get_functions(); template - const T &value() const - { - return get_typed_store()->data; - } + static const std::type_info &get_type() { return typeid(T); } template - bool check_type() const - { - return dynamic_cast::type> *>(store)!=0; - } + static EnableSmall create(char *s, T &&v) + { new(s) typename std::remove_reference::type(std::forward(v)); } - bool check_same_type(const Variant &v) const - { return store && v.store && store->type_equals(*v.store); } + template + static EnableLarge create(char *s, T &&v) + { using V = typename std::remove_reference::type; *reinterpret_cast(s) = new V(std::forward(v)); } + + template + static typename std::enable_if::value, bool>::type compare(const char *, const char *) + { return false; } + + template + static typename std::enable_if::value, EnableSmall>::type compare(const char *s1, const char *s2) + { return *reinterpret_cast(s1)==*reinterpret_cast(s2); } + + template + static typename std::enable_if::value, EnableLarge>::type compare(const char *s1, const char *s2) + { return **reinterpret_cast(s1)==**reinterpret_cast(s2); } + + template + static EnableSmall clone(char *s, const char *v) + { new(s) T(*reinterpret_cast(v)); } + + template + static EnableLarge clone(char *s, const char *v) + { *reinterpret_cast(s) = new T(**reinterpret_cast(v)); } + + template + static EnableSmall move(char *s, char *v) + { new(s) T(std::move(*reinterpret_cast(v))); } - bool operator==(const Variant &v) const - { return store && v.store && store->value_equals(*v.store); } + template + static EnableLarge move(char *s, char *v) + { T *&p = *reinterpret_cast(v); *reinterpret_cast(s) = p; p = nullptr; } - bool operator!=(const Variant &v) const - { return !(operator==(v)); } + template + static EnableSmall destroy(char *s) + { reinterpret_cast(s)->~T(); } template - operator T() const - { return value(); } + static EnableLarge destroy(char *s) + { delete *reinterpret_cast(s); } }; + +inline void Variant::clear() +{ + if(funcs) + funcs->destroy(storage); + funcs = nullptr; +} + +template +inline void Variant::assign(T &&v) +{ + clear(); + funcs = get_functions::type>::type>(); + create(storage, std::forward(v)); +} + +inline void Variant::copy_from(const Variant &v) +{ + clear(); + if((funcs = v.funcs)) + funcs->clone(storage, v.storage); +} + +inline void Variant::move_from(Variant &&v) +{ + clear(); + if((funcs = v.funcs)) + funcs->move(storage, v.storage); + v.clear(); +} + +template +inline T &Variant::get() +{ + if(!has_type()) + throw type_mismatch(typeid(T), (funcs ? funcs->get_type() : typeid(void))); + + if(sizeof(T)<=INTERNAL_SIZE) + return *reinterpret_cast(storage); + else + return **reinterpret_cast(storage); +} + +inline bool Variant::type_equals(const Functions *funcs1, const Functions *funcs2) +{ + if(!funcs1 || !funcs2) + return false; + else if(funcs1==funcs2) + return true; + else + return funcs1->get_type()==funcs2->get_type(); +} + +template +inline const Variant::Functions *Variant::get_functions() +{ + static Functions funcs = + { + &get_type, + &compare, + &clone, + &move, + &destroy + }; + return &funcs; +} + } // namespace Msp #endif diff --git a/source/core/windows/environ.cpp b/source/core/windows/environ.cpp index ff5c2b0..7abf7e5 100644 --- a/source/core/windows/environ.cpp +++ b/source/core/windows/environ.cpp @@ -3,7 +3,7 @@ #include "mutex.h" #ifdef __GNUC__ -extern "C" errno_t getenv_s(size_t *, char *, size_t, const char *); +extern "C" __declspec(dllimport) errno_t getenv_s(size_t *, char *, size_t, const char *); #endif using namespace std; diff --git a/source/core/windows/main.cpp b/source/core/windows/main.cpp index 11df925..df17020 100644 --- a/source/core/windows/main.cpp +++ b/source/core/windows/main.cpp @@ -1,12 +1,14 @@ -#include +#include "winapi.h" +#include #include #include #include "application.h" +#include "mspcore_api.h" using namespace std; using namespace Msp; -int main(int argc, char **argv) +MSPCORE_API int main(int argc, char **argv) { return Msp::Application::run(argc, argv); } diff --git a/source/core/windows/module_platform.h b/source/core/windows/module_platform.h index 81dfd0f..eb0b633 100644 --- a/source/core/windows/module_platform.h +++ b/source/core/windows/module_platform.h @@ -1,7 +1,7 @@ #ifndef MSP_CORE_MODULE_PLATFORM_H_ #define MSP_CORE_MODULE_PLATFORM_H_ -#include +#include "winapi.h" namespace Msp { diff --git a/source/core/windows/mutex.cpp b/source/core/windows/mutex.cpp index e51fda4..6d39635 100644 --- a/source/core/windows/mutex.cpp +++ b/source/core/windows/mutex.cpp @@ -1,4 +1,4 @@ -#include +#include "winapi.h" #include "mutex.h" #include "mutex_private.h" diff --git a/source/core/windows/mutex_platform.h b/source/core/windows/mutex_platform.h index fae5e85..1d5c1c0 100644 --- a/source/core/windows/mutex_platform.h +++ b/source/core/windows/mutex_platform.h @@ -1,7 +1,7 @@ #ifndef MSP_CORE_MUTEX_PLATFORM_H_ #define MSP_CORE_MUTEX_PLATFORM_H_ -#include +#include "winapi.h" namespace Msp { diff --git a/source/core/windows/process.cpp b/source/core/windows/process.cpp index 8293650..0eae33b 100644 --- a/source/core/windows/process.cpp +++ b/source/core/windows/process.cpp @@ -1,7 +1,8 @@ -#include +#include "winapi.h" #include #include #include +#include "except.h" #include "process.h" #include "process_private.h" @@ -43,12 +44,13 @@ Process::~Process() { CloseHandle(priv->info.hProcess); CloseHandle(priv->info.hThread); + delete priv; } void Process::platform_get_self_info(Private &priv) { priv.info.hProcess = GetCurrentProcess(); - priv.info.hThread = 0; + priv.info.hThread = nullptr; priv.info.dwProcessId = GetCurrentProcessId(); priv.info.dwThreadId = 0; } @@ -61,12 +63,12 @@ void Process::execute(const string &command, bool path_search, const Arguments & STARTUPINFO startup; startup.cb = sizeof(STARTUPINFO); - startup.lpReserved = 0; - startup.lpDesktop = 0; - startup.lpTitle = 0; + startup.lpReserved = nullptr; + startup.lpDesktop = nullptr; + startup.lpTitle = nullptr; startup.dwFlags = 0; startup.cbReserved2 = 0; - startup.lpReserved2 = 0; + startup.lpReserved2 = nullptr; if(redirect) { startup.dwFlags |= STARTF_USESTDHANDLES; @@ -78,9 +80,9 @@ void Process::execute(const string &command, bool path_search, const Arguments & HANDLE cerr_handle = (cerr ? *cerr->get_handle(IO::M_WRITE) : GetStdHandle(STD_ERROR_HANDLE)); DuplicateHandle(self_handle, cerr_handle, self_handle, &startup.hStdError, 0, true, DUPLICATE_SAME_ACCESS); } - const char *cmdptr = (path_search ? 0 : command.c_str()); - const char *wd = (work_dir.empty() ? 0 : work_dir.c_str()); - if(!CreateProcess(cmdptr, const_cast(cmdline.c_str()), 0, 0, true, 0, 0, wd, &startup, &priv->info)) + const char *cmdptr = (path_search ? nullptr : command.c_str()); + const char *wd = (work_dir.empty() ? nullptr : work_dir.c_str()); + if(!CreateProcess(cmdptr, const_cast(cmdline.c_str()), nullptr, nullptr, true, 0, nullptr, wd, &startup, &priv->info)) throw system_error("CreateProcess"); if(redirect) @@ -99,7 +101,7 @@ void Process::execute(const string &command, bool path_search, const Arguments & bool Process::wait(bool block) { if(!running) - throw logic_error("not running"); + throw invalid_state("not running"); DWORD ret = WaitForSingleObject(priv->info.hProcess, (block ? INFINITE : 0)); if(ret==WAIT_FAILED) @@ -135,8 +137,8 @@ void Process::interrupt() Process::Private::Private() { - info.hProcess = 0; - info.hThread = 0; + info.hProcess = nullptr; + info.hThread = nullptr; info.dwProcessId = 0; info.dwThreadId = 0; } diff --git a/source/core/windows/process_platform.h b/source/core/windows/process_platform.h index 4cb793a..d55678e 100644 --- a/source/core/windows/process_platform.h +++ b/source/core/windows/process_platform.h @@ -1,7 +1,7 @@ #ifndef MSP_CORE_PROCESS_PLATFORM_H_ #define MSP_CORE_PROCESS_PLATFORM_H_ -#include +#include "winapi.h" namespace Msp { diff --git a/source/core/windows/semaphore.cpp b/source/core/windows/semaphore.cpp index c81f815..e45e4b9 100644 --- a/source/core/windows/semaphore.cpp +++ b/source/core/windows/semaphore.cpp @@ -1,4 +1,4 @@ -#include +#include "winapi.h" #include #include #include "semaphore.h" diff --git a/source/core/windows/systemerror.cpp b/source/core/windows/systemerror.cpp index 98eb9ed..754c90b 100644 --- a/source/core/windows/systemerror.cpp +++ b/source/core/windows/systemerror.cpp @@ -1,4 +1,4 @@ -#include +#include "winapi.h" #include #include "systemerror.h" @@ -11,7 +11,7 @@ string system_error::get_message(int c) c = GetLastError(); char msg[1024]; - if(FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, 0, c, 0, msg, sizeof(msg), 0)) + if(FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, c, 0, msg, sizeof(msg), nullptr)) return msg; else return lexical_cast(c, Fmt().hex()); diff --git a/source/core/windows/thread.cpp b/source/core/windows/thread.cpp index ab02c4d..3231896 100644 --- a/source/core/windows/thread.cpp +++ b/source/core/windows/thread.cpp @@ -1,4 +1,4 @@ -#include +#include "winapi.h" #include "thread.h" #include "thread_private.h" @@ -6,18 +6,18 @@ namespace Msp { void Thread::platform_join() { - WaitForSingleObject(priv_->handle, INFINITE); + WaitForSingleObject(_priv->handle, INFINITE); } void Thread::platform_kill() { - TerminateThread(priv_->handle, 0); + TerminateThread(_priv->handle, 0); } void Thread::platform_launch() { DWORD dummy; // Win9x needs the lpTthreadId parameter - priv_->handle = CreateThread(0, 0, &Private::main_wrapper, this, 0, &dummy); + _priv->handle = CreateThread(nullptr, 0, &Private::main_wrapper, this, 0, &dummy); } void Thread::platform_setname() diff --git a/source/core/windows/thread_platform.h b/source/core/windows/thread_platform.h index 50b1a5e..d88bd8b 100644 --- a/source/core/windows/thread_platform.h +++ b/source/core/windows/thread_platform.h @@ -1,7 +1,7 @@ #ifndef MSP_CORE_THREAD_PLATFORM_H_ #define MSP_CORE_THREAD_PLATFORM_H_ -#include +#include "winapi.h" namespace Msp { diff --git a/source/core/windows/winapi.h b/source/core/windows/winapi.h new file mode 100644 index 0000000..dca0880 --- /dev/null +++ b/source/core/windows/winapi.h @@ -0,0 +1,12 @@ +#ifndef MSP_CORE_WINAPI_H_ +#define MSP_CORE_WINAPI_H_ + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#ifndef NOMINMAX +#define NOMINMAX +#endif +#include + +#endif diff --git a/source/debug/backtrace.h b/source/debug/backtrace.h index 3f32ade..b8e06af 100644 --- a/source/debug/backtrace.h +++ b/source/debug/backtrace.h @@ -4,16 +4,17 @@ #include #include #include +#include namespace Msp { namespace Debug { -class Backtrace +class MSPCORE_API Backtrace { public: struct StackFrame { - void *address; + void *address = nullptr; std::string file; std::string symbol; }; @@ -27,8 +28,8 @@ public: static Backtrace create(); }; -std::ostream &operator<<(std::ostream &, const Backtrace &); -std::ostream &operator<<(std::ostream &, const Backtrace::StackFrame &); +MSPCORE_API std::ostream &operator<<(std::ostream &, const Backtrace &); +MSPCORE_API std::ostream &operator<<(std::ostream &, const Backtrace::StackFrame &); } // namespace Debug } // namespace Msp diff --git a/source/debug/debugapi.cpp b/source/debug/debugapi.cpp new file mode 100644 index 0000000..8fafdd9 --- /dev/null +++ b/source/debug/debugapi.cpp @@ -0,0 +1,59 @@ +#ifndef _WIN32 +#include +#endif +#include +#include +#include +#include +#include "debugapi.h" + +using namespace std; + +namespace Msp { +namespace Debug { + +DebuggerType check_debugger(bool force_recheck) +{ + static DebuggerType debugger = NONE; + static bool checked = false; + + if(!checked || force_recheck) + { + checked = true; + +#ifndef _WIN32 + unsigned tracer_pid = 0; + IO::BufferedFile status("/proc/self/status"); + string line; + while(status.getline(line)) + if(!line.compare(0, 10, "TracerPid:")) + { + tracer_pid = lexical_cast(strip(line.substr(10))); + break; + } + + if(tracer_pid) + { + FS::Path tracer_cmd = FS::readlink(format("/proc/%d/exe", tracer_pid)); + if(FS::basename(tracer_cmd)=="gdb") + debugger = GDB; + else + debugger = UNKNOWN; + } +#endif + } + + return debugger; +} + +void debug_break() +{ +#ifdef _WIN32 + __debugbreak(); +#else + raise(SIGTRAP); +#endif +} + +} // namespace Debug +} // namespace Msp diff --git a/source/debug/debugapi.h b/source/debug/debugapi.h new file mode 100644 index 0000000..0f1a501 --- /dev/null +++ b/source/debug/debugapi.h @@ -0,0 +1,22 @@ +#ifndef MSP_DEBUG_DEBUGAPI_H_ +#define MSP_DEBUG_DEBUGAPI_H_ + +#include + +namespace Msp { +namespace Debug { + +enum DebuggerType +{ + NONE, + GDB, + UNKNOWN, +}; + +MSPCORE_API DebuggerType check_debugger(bool = false); +MSPCORE_API void debug_break(); + +} // namespace Debug +} // namespace Msp + +#endif diff --git a/source/debug/demangle.cpp b/source/debug/demangle.cpp index e41eb9a..3ed3171 100644 --- a/source/debug/demangle.cpp +++ b/source/debug/demangle.cpp @@ -13,7 +13,7 @@ string demangle(const string &sym) { #ifdef __GNUC__ int status; - char *dm = abi::__cxa_demangle(sym.c_str(), 0, 0, &status); + char *dm = abi::__cxa_demangle(sym.c_str(), nullptr, nullptr, &status); string result; if(status==0) diff --git a/source/debug/demangle.h b/source/debug/demangle.h index 213a348..2233435 100644 --- a/source/debug/demangle.h +++ b/source/debug/demangle.h @@ -2,11 +2,12 @@ #define MSP_DEBUG_DEMANGLE_H_ #include +#include namespace Msp { namespace Debug { -std::string demangle(const std::string &); +MSPCORE_API std::string demangle(const std::string &); } // namespace Debug } // namespace Msp diff --git a/source/debug/errorreporter.cpp b/source/debug/errorreporter.cpp index d4d51bc..6591c03 100644 --- a/source/debug/errorreporter.cpp +++ b/source/debug/errorreporter.cpp @@ -3,17 +3,22 @@ namespace Msp { namespace Debug { -ErrorReporter *ErrorReporter::current = 0; +ErrorReporter *ErrorReporter::_current = nullptr; ErrorReporter::ErrorReporter(): - prev(current) + _prev(_current) { - current = this; + _current = this; } ErrorReporter::~ErrorReporter() { - current = prev; + _current = _prev; +} + +const ErrorReporter *ErrorReporter::get_current() +{ + return _current; } } // namespace Debug diff --git a/source/debug/errorreporter.h b/source/debug/errorreporter.h index 98806dd..b702b7c 100644 --- a/source/debug/errorreporter.h +++ b/source/debug/errorreporter.h @@ -2,24 +2,25 @@ #define MSP_DEBUG_ERRORREPORTER_H_ #include +#include #include namespace Msp { namespace Debug { -class ErrorReporter: private NonCopyable +class MSPCORE_API ErrorReporter: private NonCopyable { private: - ErrorReporter *prev; + ErrorReporter *_prev = nullptr; - static ErrorReporter *current; + static ErrorReporter *_current; protected: ErrorReporter(); public: virtual ~ErrorReporter(); - static const ErrorReporter *get_current() { return current; } + static const ErrorReporter *get_current(); virtual bool report_uncaught_exception(const std::exception &) const = 0; }; diff --git a/source/debug/exceptiontrace.cpp b/source/debug/exceptiontrace.cpp index 8ffc9c8..7a681c3 100644 --- a/source/debug/exceptiontrace.cpp +++ b/source/debug/exceptiontrace.cpp @@ -20,7 +20,7 @@ struct HookThrow HookThrow::HookThrow() { - void *handle = dlopen(0, RTLD_LAZY); + void *handle = dlopen(nullptr, RTLD_LAZY); orig_cxa_throw = reinterpret_cast(dlvsym(handle, "__cxa_throw", "CXXABI_1.3")); dlclose(handle); } diff --git a/source/debug/exceptiontrace.h b/source/debug/exceptiontrace.h index 52664b6..0786c78 100644 --- a/source/debug/exceptiontrace.h +++ b/source/debug/exceptiontrace.h @@ -1,13 +1,15 @@ #ifndef MSP_DEBUG_EXCEPTIONTRACE_H_ #define MSP_DEBUG_EXCEPTIONTRACE_H_ +#include + namespace Msp { namespace Debug { class Backtrace; -void enable_exception_trace(bool); -const Backtrace &get_exception_trace(); +MSPCORE_API void enable_exception_trace(bool); +MSPCORE_API const Backtrace &get_exception_trace(); } // namespace Debug } // namespace Msp diff --git a/source/debug/profiler.cpp b/source/debug/profiler.cpp index c82558b..65cc71c 100644 --- a/source/debug/profiler.cpp +++ b/source/debug/profiler.cpp @@ -7,11 +7,6 @@ using namespace std; namespace Msp { namespace Debug { -Profiler::Profiler(): - period(0), - inner(0) -{ } - void Profiler::set_period(unsigned p) { if(p==period) @@ -96,13 +91,5 @@ const Profiler::ScopeInfo &Profiler::get_scope(const string &sn) const return get_item(scopes, sn); } - -Profiler::ScopeInfo::ScopeInfo(): - calls(0), - calls_per_sec(0), - hist_pos(0), - hist_full(false) -{ } - } // namespace Debug } // namespace Msp diff --git a/source/debug/profiler.h b/source/debug/profiler.h index 521ce95..7d98dc7 100644 --- a/source/debug/profiler.h +++ b/source/debug/profiler.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -25,39 +26,35 @@ profiled. Note: This is not thread-safe. To profile multiple threads, create a separate Profiler for each thread. */ -class Profiler: private NonCopyable +class MSPCORE_API Profiler: private NonCopyable { public: - struct CallInfo + struct MSPCORE_API CallInfo { Msp::Time::TimeStamp entry_time; Msp::Time::TimeDelta duration; }; - struct ScopeInfo + struct MSPCORE_API ScopeInfo { Time::TimeStamp first_call; - unsigned calls; + unsigned calls = 0; Time::TimeDelta total_time; Time::TimeDelta self_time; Time::TimeDelta avg_time; - float calls_per_sec; + float calls_per_sec = 0; std::vector history; - unsigned hist_pos; - bool hist_full; + unsigned hist_pos = 0; + bool hist_full = false; std::map called_from; - - ScopeInfo(); }; private: - unsigned period; + unsigned period = 0; std::map scopes; - ProfilingScope *inner; + ProfilingScope *inner = nullptr; public: - Profiler(); - /** Sets the averaging period for timing data, measured in calls. Previous average timings are cleared. */ void set_period(unsigned p); diff --git a/source/debug/profilingscope.h b/source/debug/profilingscope.h index 4e4294e..7b8bcf3 100644 --- a/source/debug/profilingscope.h +++ b/source/debug/profilingscope.h @@ -1,6 +1,7 @@ #ifndef MSP_DEBUG_PROFILINGSCOPE_H_ #define MSP_DEBUG_PROFILINGSCOPE_H_ +#include #include #include #include "profiler.h" @@ -13,18 +14,16 @@ RAII timing class to accompany Profiler. Timing starts when an object is created and ends when it goes out of scope. If there was another object in an outer scope, it is notified of the time used in inner scopes. */ -class ProfilingScope: private NonCopyable +class MSPCORE_API ProfilingScope: private NonCopyable { private: Profiler &profiler; std::string name; - ProfilingScope *parent; + ProfilingScope *parent = nullptr; Time::TimeStamp entry_time; Time::TimeDelta time_spent; Time::TimeDelta child_time; - ProfilingScope(const ProfilingScope &); - ProfilingScope &operator=(const ProfilingScope &); public: ProfilingScope(Profiler &p, const std::string &n); ~ProfilingScope(); diff --git a/source/fs/android/stat_owner.cpp b/source/fs/android/stat_owner.cpp index 45fba30..48823e9 100644 --- a/source/fs/android/stat_owner.cpp +++ b/source/fs/android/stat_owner.cpp @@ -9,17 +9,27 @@ namespace FS { void Stat::Private::fill_owner_info(Stat::OwnerInfo &result) { - struct passwd *owner; - if((owner = getpwuid(owner_id))) - result.owner = owner->pw_name; + if(owner_id!=INVALID_UID) + { + struct passwd *owner; + if((owner = getpwuid(owner_id))) + result.owner = owner->pw_name; + else + result.owner = format("%d", owner_id); + } else - result.owner = format("%d", owner_id); + result.owner = "None"; - struct group *group; - if((group = getgrgid(group_id))) - result.group = group->gr_name; + if(group_id!=INVALID_GID) + { + struct group *group; + if((group = getgrgid(group_id))) + result.group = group->gr_name; + else + result.group = format("%d", group_id); + } else - result.group = format("%d", group_id); + result.group = "None"; } } // namespace FS diff --git a/source/fs/dir.cpp b/source/fs/dir.cpp index 066d88b..0f617e5 100644 --- a/source/fs/dir.cpp +++ b/source/fs/dir.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include "dir.h" #include "path.h" @@ -109,7 +110,7 @@ Path get_sys_conf_dir() { const char *argv0 = Application::get_argv0(); if(!argv0) - throw logic_error("no startup command"); + throw invalid_state("no startup command"); Path dir = get_bin_dir(argv0); @@ -128,7 +129,7 @@ Path get_sys_data_dir() { const char *argv0 = Application::get_argv0(); if(!argv0) - throw logic_error("no startup command"); + throw invalid_state("no startup command"); Path dir = get_bin_dir(argv0); @@ -144,7 +145,7 @@ Path get_sys_lib_dir() { const char *argv0 = Application::get_argv0(); if(!argv0) - throw logic_error("no startup command"); + throw invalid_state("no startup command"); Path dir = get_bin_dir(argv0); diff --git a/source/fs/dir.h b/source/fs/dir.h index c0a1c74..960be2e 100644 --- a/source/fs/dir.h +++ b/source/fs/dir.h @@ -4,63 +4,64 @@ #include #include #include +#include #include "path.h" namespace Msp { namespace FS { -class not_a_directory: public std::runtime_error +class MSPCORE_API not_a_directory: public std::runtime_error { public: not_a_directory(const Path &); - virtual ~not_a_directory() throw() { } + ~not_a_directory() throw() override = default; }; /// Creates a directory -void mkdir(const Path &path, int mode); +MSPCORE_API void mkdir(const Path &path, int mode); /// Creates a directory and any required parent directories -void mkpath(const Path &path, int mode); +MSPCORE_API void mkpath(const Path &path, int mode); /// Removes a directory, which must be empty -void rmdir(const Path &path); +MSPCORE_API void rmdir(const Path &path); /// Removes a directory and anything it contains -void rmpath(const Path &path); +MSPCORE_API void rmpath(const Path &path); /// Lists the contents of a directory -std::vector list_files(const Path &path); +MSPCORE_API std::vector list_files(const Path &path); /// Lists the contents of a directory, filtered with a regex -std::vector list_filtered(const Path &path, const std::string &filter); +MSPCORE_API std::vector list_filtered(const Path &path, const std::string &filter); /// Returns the current working directory -Path getcwd(); +MSPCORE_API Path getcwd(); /// Changes the current working directory -void chdir(const Path &); +MSPCORE_API void chdir(const Path &); /// Returns the user's home directory -Path get_home_dir(); +MSPCORE_API Path get_home_dir(); /// Returns a directory suitable for storing user-specific data. -Path get_user_data_dir(); +MSPCORE_API Path get_user_data_dir(); /// Returns a directory containing system-wide configuration. -Path get_sys_conf_dir(); +MSPCORE_API Path get_sys_conf_dir(); /// Returns a directory containing immutable system-wide data. -Path get_sys_data_dir(); +MSPCORE_API Path get_sys_data_dir(); /// Returns a directory containing system-wide architecture-specific files. -Path get_sys_lib_dir(); +MSPCORE_API Path get_sys_lib_dir(); /** Looks for a file in a list of paths. Returns the absolute path to the first existing location, or an empty Path if the file is not found at all. */ -Path path_lookup(const std::string &, const std::vector &); +MSPCORE_API Path path_lookup(const std::string &, const std::vector &); /** Looks for a file using the PATH environment variable. */ -Path path_lookup(const std::string &); +MSPCORE_API Path path_lookup(const std::string &); } // namespace FS } // namespace Msp diff --git a/source/fs/filemonitor.cpp b/source/fs/filemonitor.cpp index 5ff5b78..5ff6392 100644 --- a/source/fs/filemonitor.cpp +++ b/source/fs/filemonitor.cpp @@ -1,4 +1,5 @@ #include +#include #include "filemonitor.h" #include "filemonitor_platform.h" @@ -8,8 +9,7 @@ namespace Msp { namespace FS { FileMonitor::FileMonitor(): - priv(new Private(*this)), - event_disp(0) + priv(new Private(*this)) { } FileMonitor::~FileMonitor() @@ -20,7 +20,7 @@ FileMonitor::~FileMonitor() void FileMonitor::use_event_dispatcher(IO::EventDispatcher &ed) { if(event_disp) - throw logic_error("event_disp!=0"); + throw already_called("FileMonitor::use_event_dispatcher"); event_disp = &ed; platform_use_event_dispatcher(); @@ -30,7 +30,6 @@ void FileMonitor::add_file(const FS::Path &path) { MonitoredFile file; file.path = path; - file.modified = false; prepare_file(file); files.push_back(file); } diff --git a/source/fs/filemonitor.h b/source/fs/filemonitor.h index e96aff6..3ce5d79 100644 --- a/source/fs/filemonitor.h +++ b/source/fs/filemonitor.h @@ -1,15 +1,15 @@ #ifndef FILEMONITOR_H_ #define FILEMONITOR_H_ +#include #include #include #include -#include namespace Msp { namespace FS { -class FileMonitor: NonCopyable +class MSPCORE_API FileMonitor: NonCopyable { private: struct Private; @@ -17,16 +17,16 @@ private: struct MonitoredFile { FS::Path path; - bool modified; - int tag; + bool modified = false; + int tag = -1; }; public: sigc::signal signal_file_modified; private: - Private *priv; - IO::EventDispatcher *event_disp; + Private *priv = nullptr; + IO::EventDispatcher *event_disp = nullptr; std::vector files; public: diff --git a/source/fs/osx/dir_location.cpp b/source/fs/osx/dir_location.cpp index b58b971..13aa3d2 100644 --- a/source/fs/osx/dir_location.cpp +++ b/source/fs/osx/dir_location.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "dir.h" using namespace std; @@ -28,7 +29,7 @@ Path get_user_data_dir() { const string &appname = Application::get_name(); if(appname.empty()) - throw logic_error("no application name"); + throw invalid_state("no application name"); char buf[1024]; unsigned len = get_application_support_dir(buf, sizeof(buf)); diff --git a/source/fs/path.cpp b/source/fs/path.cpp index a5a5a10..1181b92 100644 --- a/source/fs/path.cpp +++ b/source/fs/path.cpp @@ -17,20 +17,7 @@ inline bool is_windows_drive(const string &p) namespace Msp { namespace FS { -Path::Path() -{ } - Path::Path(const string &p) -{ - init(p); -} - -Path::Path(const char *p) -{ - init(p); -} - -void Path::init(const string &p) { if(p.empty()) return; @@ -146,11 +133,21 @@ void Path::add_component(const string &comp) path += DIRSEP; path += comp; } - else if(separators.empty()) + else if(start==0) + { + /* Removing the last component of a relative path results in the + current directory */ path = "."; + } + else if(start==1) + { + /* Removing the last component of an absolute path results in the + root directory */ + path.erase(start, string::npos); + } else { - // Otherwise, erase the last component + // Otherwise, erase the last component and its separator path.erase(separators.back(), string::npos); separators.pop_back(); } diff --git a/source/fs/path.h b/source/fs/path.h index e0b593c..1b15047 100644 --- a/source/fs/path.h +++ b/source/fs/path.h @@ -4,6 +4,7 @@ #include #include #include +#include namespace Msp { namespace FS { @@ -28,13 +29,13 @@ A path can also be treated as an array of components, supporting indexing, iteration and slicing. In this context the root directory is treated as a component of its own. */ -class Path +class MSPCORE_API Path { private: typedef std::vector PositionArray; public: - class Iterator + class MSPCORE_API Iterator { public: typedef PositionArray::difference_type difference_type; @@ -70,13 +71,10 @@ private: PositionArray separators; public: - Path(); + Path() = default; Path(const std::string &); - Path(const char *); -private: - void init(const std::string &); + Path(const char *p): Path(std::string(p)) { } -public: /// Returns the path as a string. const std::string &str() const { return path; } diff --git a/source/fs/redirectedpath.h b/source/fs/redirectedpath.h index 50a3609..95888f7 100644 --- a/source/fs/redirectedpath.h +++ b/source/fs/redirectedpath.h @@ -1,6 +1,7 @@ #ifndef MSP_FS_REDIRECTEDPATH_H_ #define MSP_FS_REDIRECTEDPATH_H_ +#include #include "path.h" namespace Msp { @@ -12,7 +13,7 @@ goes out of scope, it is renamed to the original path. If destruction happens due to an exception, it is unlinked instead. The primary use for this is to atomically overwrite a file with a new version. */ -class RedirectedPath: public Path +class MSPCORE_API RedirectedPath: public Path { private: Path original; diff --git a/source/fs/stat.cpp b/source/fs/stat.cpp index 2269ae1..e296ead 100644 --- a/source/fs/stat.cpp +++ b/source/fs/stat.cpp @@ -7,20 +7,6 @@ using namespace std; namespace Msp { namespace FS { -Stat::Private::Private(): - owner_id(0), - group_id(0) -{ } - - -Stat::Stat(): - exists(false), - type(UNKNOWN), - size(0), - alloc_size(0), - priv(0) -{ } - Stat::Stat(const Stat &other): exists(other.exists), type(other.type), @@ -28,11 +14,14 @@ Stat::Stat(const Stat &other): alloc_size(other.alloc_size), mtime(other.mtime), owner_info(other.owner_info), - priv(other.priv ? new Private(*other.priv) : 0) + priv(other.priv ? new Private(*other.priv) : nullptr) { } Stat &Stat::operator=(const Stat &other) { + if(&other==this) + return *this; + exists = other.exists; type = other.type; size = other.size; @@ -40,7 +29,7 @@ Stat &Stat::operator=(const Stat &other) mtime = other.mtime; owner_info = other.owner_info; delete priv; - priv = (other.priv ? new Private(*other.priv) : 0); + priv = (other.priv ? new Private(*other.priv) : nullptr); return *this; } diff --git a/source/fs/stat.h b/source/fs/stat.h index 3f056a5..fd6a2f7 100644 --- a/source/fs/stat.h +++ b/source/fs/stat.h @@ -1,8 +1,9 @@ #ifndef MSP_FS_STAT_H_ #define MSP_FS_STAT_H_ +#include #include -#include +#include #include #include "path.h" @@ -17,12 +18,12 @@ enum FileType SYMLINK }; -typedef UInt64 FileSize; +typedef uint64_t FileSize; /** Holds file information. */ -class Stat +class MSPCORE_API Stat { private: struct Private; @@ -33,16 +34,16 @@ private: std::string group; }; - bool exists; - FileType type; - FileSize size; - FileSize alloc_size; + bool exists = false; + FileType type = UNKNOWN; + FileSize size = 0; + FileSize alloc_size = 0; Time::TimeStamp mtime; mutable OwnerInfo owner_info; - Private *priv; + Private *priv = nullptr; public: - Stat(); + Stat() = default; Stat(const Stat &); Stat &operator=(const Stat &); ~Stat(); @@ -73,7 +74,7 @@ inline Stat lstat(const Path &path) { return Stat::lstat(path); } /// Tests for existence of a file -bool exists(const Path &path); +MSPCORE_API bool exists(const Path &path); /// Tests whether a path refers to an existing regular file inline bool is_reg(const Path &path) diff --git a/source/fs/stat_private.h b/source/fs/stat_private.h index 7b20638..23019a5 100644 --- a/source/fs/stat_private.h +++ b/source/fs/stat_private.h @@ -1,6 +1,7 @@ #ifndef MSP_FS_STAT_PRIVATE_H_ #define MSP_FS_STAT_PRIVATE_H_ +#include "stat.h" #include "stat_platform.h" namespace Msp { @@ -8,10 +9,10 @@ namespace FS { struct Stat::Private { - UserID owner_id; - GroupID group_id; + UserID owner_id = INVALID_UID; + GroupID group_id = INVALID_GID; - Private(); + Private() = default; Private(const Private &); ~Private(); diff --git a/source/fs/unix/dir_location.cpp b/source/fs/unix/dir_location.cpp index 7382587..68d82a2 100644 --- a/source/fs/unix/dir_location.cpp +++ b/source/fs/unix/dir_location.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "dir.h" using namespace std; @@ -19,7 +20,7 @@ Path get_user_data_dir() { const string &appname = Application::get_name(); if(appname.empty()) - throw logic_error("no application name"); + throw invalid_state("no application name"); return get_home_dir()/("."+appname); } diff --git a/source/fs/unix/filemonitor_platform.h b/source/fs/unix/filemonitor_platform.h index ed900bf..a6e67a6 100644 --- a/source/fs/unix/filemonitor_platform.h +++ b/source/fs/unix/filemonitor_platform.h @@ -1,6 +1,10 @@ #ifndef MSP_FS_FILEMONITOR_PLATFORM_H_ #define MSP_FS_FILEMONITOR_PLATFORM_H_ +#include +#include +#include "filemonitor.h" + namespace Msp { namespace FS { @@ -16,16 +20,16 @@ public: int add_watch(const FS::Path &, int); void remove_watch(int); - virtual void set_block(bool) { } - virtual void set_inherit(bool) { } + void set_block(bool) override { } + void set_inherit(bool) override { } protected: - virtual std::size_t do_write(const char *, std::size_t); - virtual std::size_t do_read(char *, std::size_t); + std::size_t do_write(const char *, std::size_t) override; + std::size_t do_read(char *, std::size_t) override; public: - virtual const IO::Handle &get_handle(IO::Mode) { return fd; } - virtual const IO::Handle &get_event_handle() { return fd; } + const IO::Handle &get_handle(IO::Mode) override { return fd; } + const IO::Handle &get_event_handle() override { return fd; } }; diff --git a/source/fs/unix/stat_owner.cpp b/source/fs/unix/stat_owner.cpp index 1a33d74..9c643d9 100644 --- a/source/fs/unix/stat_owner.cpp +++ b/source/fs/unix/stat_owner.cpp @@ -11,19 +11,29 @@ void Stat::Private::fill_owner_info(Stat::OwnerInfo &result) { char buf[1024]; - struct passwd pw; - struct passwd *owner; - if(!getpwuid_r(owner_id, &pw, buf, sizeof(buf), &owner) && owner) - result.owner = owner->pw_name; + if(owner_id!=INVALID_UID) + { + struct passwd pw; + struct passwd *owner; + if(!getpwuid_r(owner_id, &pw, buf, sizeof(buf), &owner) && owner) + result.owner = owner->pw_name; + else + result.owner = format("%d", owner_id); + } else - result.owner = format("%d", owner_id); + result.owner = "None"; - struct group gr; - struct group *group; - if(!getgrgid_r(group_id, &gr, buf, sizeof(buf), &group) && group) - result.group = group->gr_name; + if(group_id!=INVALID_GID) + { + struct group gr; + struct group *group; + if(!getgrgid_r(group_id, &gr, buf, sizeof(buf), &group) && group) + result.group = group->gr_name; + else + result.group = format("%d", group_id); + } else - result.group = format("%d", group_id); + result.group = "None"; } } // namespace FS diff --git a/source/fs/unix/stat_platform.h b/source/fs/unix/stat_platform.h index cc3f095..d888fed 100644 --- a/source/fs/unix/stat_platform.h +++ b/source/fs/unix/stat_platform.h @@ -9,6 +9,9 @@ namespace FS { typedef uid_t UserID; typedef gid_t GroupID; +const UserID INVALID_UID = -1; +const GroupID INVALID_GID = -1; + } // namespace FS } // namespace Msp diff --git a/source/fs/utils.h b/source/fs/utils.h index e518d35..9c4bb5c 100644 --- a/source/fs/utils.h +++ b/source/fs/utils.h @@ -1,50 +1,51 @@ #ifndef MSP_FS_UTILS_H_ #define MSP_FS_UTILS_H_ +#include #include "path.h" namespace Msp { namespace FS { /// Extracts the last component of the path. -std::string basename(const Path &); +MSPCORE_API std::string basename(const Path &); /// Removes the last component from the path. -Path dirname(const Path &); +MSPCORE_API Path dirname(const Path &); /** Returns the base part of a filename. This includes everything up to the last dot, but not the dot itself. */ -std::string basepart(const std::string &); +MSPCORE_API std::string basepart(const std::string &); /** Returns the extension part of a filename. This includes the last dot and everything after it. */ -std::string extpart(const std::string &); +MSPCORE_API std::string extpart(const std::string &); /// Fixes the case of a path to match files / directories on the filesystem. -Path fix_case(const Path &path); +MSPCORE_API Path fix_case(const Path &path); /// Reads the contents of a symbolic link -Path readlink(const Path &path); +MSPCORE_API Path readlink(const Path &path); /// Resolves all symlinks from a path. Will always return an absolute path. -Path realpath(const Path &path); +MSPCORE_API Path realpath(const Path &path); /// Removes a file -void unlink(const Path &path); +MSPCORE_API void unlink(const Path &path); /// Renames a file. Existing file, if any, is overwritten. -void rename(const Path &from, const Path &to); +MSPCORE_API void rename(const Path &from, const Path &to); /** Makes a path relative to some base path. That is, base/result==path. Both paths must be either absolute or relative. */ -Path relative(const Path &path, const Path &base); +MSPCORE_API Path relative(const Path &path, const Path &base); /// Returns the longest prefix shared by both paths. -Path common_ancestor(const Path &, const Path &); +MSPCORE_API Path common_ancestor(const Path &, const Path &); /** Determines how many levels a path is below another. Returns -1 if path is not a descendant of parent. Both paths must be either absolute or relative. */ -int descendant_depth(const Path &path, const Path &parent); +MSPCORE_API int descendant_depth(const Path &path, const Path &parent); } // namespace FS } // namespace Msp diff --git a/source/fs/windows/dir.cpp b/source/fs/windows/dir.cpp index c6f6b9b..2ba2f1e 100644 --- a/source/fs/windows/dir.cpp +++ b/source/fs/windows/dir.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -28,7 +28,7 @@ vector list_filtered(const Path &path, const string &filter) vector result; WIN32_FIND_DATA entry; string pattern = path.str()+"\\*"; - HANDLE search_handle = FindFirstFileEx(pattern.c_str(), FindExInfoBasic, &entry, FindExSearchNameMatch, 0, 0); + HANDLE search_handle = FindFirstFileEx(pattern.c_str(), FindExInfoBasic, &entry, FindExSearchNameMatch, nullptr, 0); if(search_handle==INVALID_HANDLE_VALUE) { DWORD err = GetLastError(); diff --git a/source/fs/windows/dir_location.cpp b/source/fs/windows/dir_location.cpp index 4c3b866..85c5c2f 100644 --- a/source/fs/windows/dir_location.cpp +++ b/source/fs/windows/dir_location.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "dir.h" using namespace std; @@ -10,7 +11,7 @@ namespace FS { Path get_home_dir() { char home[MAX_PATH]; - if(SHGetFolderPath(0, CSIDL_PERSONAL, 0, 0, home)==S_OK) + if(SHGetFolderPath(nullptr, CSIDL_PERSONAL, nullptr, 0, home)==S_OK) return home; return "."; } @@ -19,10 +20,10 @@ Path get_user_data_dir() { const string &appname = Application::get_name(); if(appname.empty()) - throw logic_error("no application name"); + throw invalid_state("no application name"); char datadir[MAX_PATH]; - if(SHGetFolderPath(0, CSIDL_LOCAL_APPDATA, 0, 0, datadir)==S_OK) + if(SHGetFolderPath(nullptr, CSIDL_LOCAL_APPDATA, nullptr, 0, datadir)==S_OK) return Path(datadir)/appname; return "."; } diff --git a/source/fs/windows/filemonitor.cpp b/source/fs/windows/filemonitor.cpp index 3ed65b1..63336e3 100644 --- a/source/fs/windows/filemonitor.cpp +++ b/source/fs/windows/filemonitor.cpp @@ -1,3 +1,4 @@ +#include #include "filemonitor.h" #include "filemonitor_platform.h" @@ -21,7 +22,7 @@ void FileMonitor::tick() FileMonitor::Private::Private(FileMonitor &) { - throw logic_error("not implemented"); + throw unsupported("FileMonitor"); } } // namespace FS diff --git a/source/fs/windows/filemonitor_platform.h b/source/fs/windows/filemonitor_platform.h index 392ec4b..60bb86c 100644 --- a/source/fs/windows/filemonitor_platform.h +++ b/source/fs/windows/filemonitor_platform.h @@ -1,6 +1,8 @@ #ifndef MSP_FS_FILEMONITOR_PLATFORM_H_ #define MSP_FS_FILEMONITOR_PLATFORM_H_ +#include "filemonitor.h" + namespace Msp { namespace FS { diff --git a/source/fs/windows/stat.cpp b/source/fs/windows/stat.cpp index ac9e0c9..ee79476 100644 --- a/source/fs/windows/stat.cpp +++ b/source/fs/windows/stat.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -13,7 +13,7 @@ namespace { PSID copy_sid(PSID sid) { if(!sid || !IsValidSid(sid)) - return 0; + return nullptr; DWORD len = GetLengthSid(sid); PSID copy = reinterpret_cast(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len)); if(!CopySid(len, copy, sid)) @@ -32,7 +32,7 @@ string get_account_name(PSID sid) char domain[1024]; DWORD dlen = sizeof(domain); SID_NAME_USE use; - if(!LookupAccountSid(0, sid, name, &nlen, domain, &dlen, &use)) + if(!LookupAccountSid(nullptr, sid, name, &nlen, domain, &dlen, &use)) throw Msp::system_error("LookupAccountSid"); return Msp::format("%s/%s", name, domain); } @@ -50,20 +50,20 @@ Stat::Private::Private(const Private &other): Stat::Private::~Private() { - if(owner_id) + if(owner_id!=INVALID_UID) HeapFree(GetProcessHeap(), 0, owner_id); - if(group_id) + if(group_id!=INVALID_GID) HeapFree(GetProcessHeap(), 0, group_id); } void Stat::Private::fill_owner_info(Stat::OwnerInfo &result) { - if(owner_id) + if(owner_id!=INVALID_UID) result.owner = get_account_name(owner_id); else result.owner = "None"; - if(group_id) + if(group_id!=INVALID_GID) result.group = get_account_name(group_id); else result.group = "None"; @@ -73,7 +73,7 @@ void Stat::Private::fill_owner_info(Stat::OwnerInfo &result) Stat Stat::stat(const Path &path) { HANDLE handle; - handle = CreateFile(path.str().c_str(), READ_CONTROL, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS, 0); + handle = CreateFile(path.str().c_str(), READ_CONTROL, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS, nullptr); if(handle==INVALID_HANDLE_VALUE) { DWORD err = GetLastError(); @@ -102,10 +102,10 @@ Stat Stat::stat(const Path &path) result.mtime = Time::TimeStamp(Time::filetime_to_rawtime(info.ftLastWriteTime)); PSECURITY_DESCRIPTOR sec_desc; - PSID owner = 0; - PSID group = 0; + PSID owner = nullptr; + PSID group = nullptr; const SECURITY_INFORMATION sec_info = OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION; - DWORD err = GetSecurityInfo(handle, SE_FILE_OBJECT, sec_info, &owner, &group, 0, 0, &sec_desc); + DWORD err = GetSecurityInfo(handle, SE_FILE_OBJECT, sec_info, &owner, &group, nullptr, nullptr, &sec_desc); if(err) { CloseHandle(handle); diff --git a/source/fs/windows/stat_platform.h b/source/fs/windows/stat_platform.h index 4e8cfbc..89961c6 100644 --- a/source/fs/windows/stat_platform.h +++ b/source/fs/windows/stat_platform.h @@ -1,7 +1,7 @@ #ifndef MSP_FS_STAT_PLATFORM_H_ #define MSP_FS_STAT_PLATFORM_H_ -#include +#include namespace Msp { namespace FS { @@ -9,6 +9,9 @@ namespace FS { typedef PSID UserID; typedef PSID GroupID; +const UserID INVALID_UID = nullptr; +const GroupID INVALID_GID = nullptr; + } // namespace FS } // namespace Msp diff --git a/source/fs/windows/utils.cpp b/source/fs/windows/utils.cpp index ca9e7aa..a1c2513 100644 --- a/source/fs/windows/utils.cpp +++ b/source/fs/windows/utils.cpp @@ -1,4 +1,5 @@ -#include +#include +#include #include #include "dir.h" #include "utils.h" @@ -11,7 +12,7 @@ namespace FS { Path readlink(const Path &link) { (void)link; - throw logic_error("no symbolic links on win32"); + throw unsupported("readlink"); } Path realpath(const Path &path) diff --git a/source/io/android/asset.cpp b/source/io/android/asset.cpp index 1b97eae..3e03034 100644 --- a/source/io/android/asset.cpp +++ b/source/io/android/asset.cpp @@ -34,8 +34,9 @@ Asset::~Asset() delete priv; } -unsigned Asset::do_read(char *buf, unsigned size) +size_t Asset::do_read(char *buf, size_t size) { + // The function actually returns an int, despite taking size_t int ret = AAsset_read(priv->asset, buf, size); if(ret<0) throw runtime_error("Asset::do_read"); diff --git a/source/io/asset.cpp b/source/io/asset.cpp index 526133e..d605ff4 100644 --- a/source/io/asset.cpp +++ b/source/io/asset.cpp @@ -1,3 +1,4 @@ +#include #include "asset.h" using namespace std; @@ -7,22 +8,22 @@ namespace IO { void Asset::set_block(bool) { - throw logic_error("Asset::set_block"); + throw unsupported("Asset::set_block"); } void Asset::set_inherit(bool) { - throw logic_error("Asset::set_inherit"); + throw unsupported("Asset::set_inherit"); } -unsigned Asset::do_write(const char *, unsigned) +size_t Asset::do_write(const char *, size_t) { throw invalid_access(M_WRITE); } const Handle &Asset::get_handle(Mode) { - throw logic_error("Asset::get_handle"); + throw unsupported("Asset::get_handle"); } } // namespace IO diff --git a/source/io/asset.h b/source/io/asset.h index c5b98cb..41cf10d 100644 --- a/source/io/asset.h +++ b/source/io/asset.h @@ -1,6 +1,7 @@ #ifndef MSP_IO_ASSET_H_ #define MSP_IO_ASSET_H_ +#include #include "seekable.h" namespace Msp { @@ -11,29 +12,29 @@ Opens a file from the application's assets. On Android, this means the assets contained within the APK. On other platfoms, assets are located in the directory indicated by FS::get_sys_data_dir(). Assets are always read-only. */ -class Asset: public Seekable +class MSPCORE_API Asset: public Seekable { private: struct Private; - Private *priv; + Private *priv = nullptr; public: Asset(const std::string &); ~Asset(); - virtual void set_block(bool); - virtual void set_inherit(bool); + void set_block(bool) override; + void set_inherit(bool) override; private: - virtual unsigned do_write(const char *, unsigned); - virtual unsigned do_read(char *, unsigned); + std::size_t do_write(const char *, std::size_t) override; + std::size_t do_read(char *, std::size_t) override; public: - virtual const Handle &get_handle(Mode); + const Handle &get_handle(Mode) override; - virtual SeekOffset seek(SeekOffset, SeekType); - virtual SeekOffset tell() const; + SeekOffset seek(SeekOffset, SeekType) override; + SeekOffset tell() const override; }; } // namespace IO diff --git a/source/io/base.cpp b/source/io/base.cpp index 9c2b40a..b8c13d2 100644 --- a/source/io/base.cpp +++ b/source/io/base.cpp @@ -6,10 +6,7 @@ using namespace std; namespace Msp { namespace IO { -Base::Base(): - mode(M_READ), - eof_flag(false), - mutex(0) +Base::Base() { } Base::~Base() diff --git a/source/io/base.h b/source/io/base.h index 7bd5bd9..92c860d 100644 --- a/source/io/base.h +++ b/source/io/base.h @@ -3,6 +3,7 @@ #include #include +#include #include #include #include "handle.h" @@ -15,7 +16,7 @@ namespace IO { /** Common interface for all I/O objects. */ -class Base: private NonCopyable +class MSPCORE_API Base: private NonCopyable { public: /** RAII synchronization primitive. Prevents concurrent access to the @@ -42,9 +43,9 @@ public: sigc::signal signal_deleted; protected: - Mode mode; - bool eof_flag; - Mutex *mutex; + Mode mode = M_READ; + bool eof_flag = false; + Mutex *mutex = nullptr; Base(); public: diff --git a/source/io/buffered.cpp b/source/io/buffered.cpp index 77a5f45..9f001fb 100644 --- a/source/io/buffered.cpp +++ b/source/io/buffered.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include "buffered.h" #include "handle.h" @@ -13,8 +13,7 @@ Buffered::Buffered(Base &b, unsigned s): buf_size(s), buf(new char[buf_size]), begin(buf), - end(buf), - cur_op(M_NONE) + end(buf) { mode = below.get_mode(); below.signal_flush_required.connect(sigc::mem_fun(this, &Buffered::flush)); @@ -34,12 +33,12 @@ Buffered::~Buffered() void Buffered::set_block(bool) { - throw logic_error("Buffered::set_block"); + throw unsupported("Buffered::set_block"); } void Buffered::set_inherit(bool) { - throw logic_error("Buffered::set_block"); + throw unsupported("Buffered::set_block"); } void Buffered::flush() @@ -180,7 +179,7 @@ int Buffered::get() const Handle &Buffered::get_handle(Mode) { - throw logic_error("Buffered::get_handle"); + throw unsupported("Buffered::get_handle"); } void Buffered::set_op(Mode op) diff --git a/source/io/buffered.h b/source/io/buffered.h index eeae3e4..c05fc25 100644 --- a/source/io/buffered.h +++ b/source/io/buffered.h @@ -2,40 +2,41 @@ #define MSP_IO_BUFFERED_H_ #include +#include #include "base.h" namespace Msp { namespace IO { -class Buffered: public Base, public sigc::trackable +class MSPCORE_API Buffered: public Base, public sigc::trackable { private: Base &below; - std::size_t buf_size; - char *buf; - char *begin; - char *end; - Mode cur_op; + std::size_t buf_size = 0; + char *buf = nullptr; + char *begin = nullptr; + char *end = nullptr; + Mode cur_op = M_NONE; public: Buffered(Base &, unsigned = 8192); ~Buffered(); - virtual void set_block(bool); - virtual void set_inherit(bool); + void set_block(bool) override; + void set_inherit(bool) override; void flush(); protected: - virtual std::size_t do_write(const char *, std::size_t); - virtual std::size_t do_read(char *, std::size_t); + std::size_t do_write(const char *, std::size_t) override; + std::size_t do_read(char *, std::size_t) override; public: - virtual std::size_t put(char); + std::size_t put(char) override; - bool getline(std::string &); - int get(); + bool getline(std::string &) override; + int get() override; - virtual const Handle &get_handle(Mode); + const Handle &get_handle(Mode) override; private: void set_op(Mode); diff --git a/source/io/console.cpp b/source/io/console.cpp index abb872d..0ac05c6 100644 --- a/source/io/console.cpp +++ b/source/io/console.cpp @@ -68,9 +68,5 @@ Console &Console::instance(Stream s) throw invalid_argument("Console::instance"); } -Console &cin = Console::instance(Console::CIN); -Console &cout = Console::instance(Console::COUT); -Console &cerr = Console::instance(Console::CERR); - } // namespace IO } // namespace Msp diff --git a/source/io/console.h b/source/io/console.h index 1200086..fe777cc 100644 --- a/source/io/console.h +++ b/source/io/console.h @@ -1,6 +1,7 @@ #ifndef MSP_IO_CONSOLE_H_ #define MSP_IO_CONSOLE_H_ +#include #include "eventobject.h" #include "handle.h" @@ -12,7 +13,7 @@ Provides access to standard input, output and error streams. This class can't be instantiated directly - use one of the cin, cout and cerr references instead. */ -class Console: public EventObject +class MSPCORE_API Console: public EventObject { public: enum Stream @@ -31,8 +32,8 @@ private: public: ~Console(); - virtual void set_block(bool); - virtual void set_inherit(bool); + void set_block(bool) override; + void set_inherit(bool) override; /** If local echo is enabled, characters will appear on the console as they are typed. Can only be used on an input Console. */ @@ -54,19 +55,20 @@ public: void redirect(Base &); protected: - virtual std::size_t do_write(const char *, std::size_t); - virtual std::size_t do_read(char *, std::size_t); + std::size_t do_write(const char *, std::size_t) override; + std::size_t do_read(char *, std::size_t) override; public: - virtual const Handle &get_handle(Mode); - virtual const Handle &get_event_handle() { return handle; } + const Handle &get_handle(Mode) override; + const Handle &get_event_handle() override { return handle; } static Console &instance(Stream); }; -extern Console &cin; -extern Console &cout; -extern Console &cerr; +// TODO make these inline instead of static when upgrading to C++17. +static Console &cin = Console::instance(Console::CIN); +static Console &cout = Console::instance(Console::COUT); +static Console &cerr = Console::instance(Console::CERR); } // namespace IO } // namespace Msp diff --git a/source/io/eventdispatcher.cpp b/source/io/eventdispatcher.cpp index 9c233ee..035a7f2 100644 --- a/source/io/eventdispatcher.cpp +++ b/source/io/eventdispatcher.cpp @@ -69,11 +69,6 @@ void EventDispatcher::dispatch() } -EventDispatcher::Slot::Slot(EventDispatcher &d, EventObject &o): - disp(d), - obj(o) -{ } - void EventDispatcher::Slot::connect_signals() const { obj.signal_events_changed.connect(sigc::mem_fun(this, &Slot::events_changed)); diff --git a/source/io/eventdispatcher.h b/source/io/eventdispatcher.h index f95f477..25341bf 100644 --- a/source/io/eventdispatcher.h +++ b/source/io/eventdispatcher.h @@ -3,6 +3,7 @@ #include #include +#include #include #include #include "poll.h" @@ -14,7 +15,7 @@ namespace IO { Put your I/O objects inside one of these to get signaled when something happens on some of them. */ -class EventDispatcher +class MSPCORE_API EventDispatcher { private: struct Slot: public sigc::trackable @@ -22,7 +23,7 @@ private: EventDispatcher &disp; EventObject &obj; - Slot(EventDispatcher &, EventObject &); + Slot(EventDispatcher &d, EventObject &o): disp(d), obj(o) { } void connect_signals() const; void events_changed(PollEvent) const; diff --git a/source/io/eventobject.cpp b/source/io/eventobject.cpp index 462e8bb..7d5ab5b 100644 --- a/source/io/eventobject.cpp +++ b/source/io/eventobject.cpp @@ -3,8 +3,7 @@ namespace Msp { namespace IO { -EventObject::EventObject(): - events(P_NONE) +EventObject::EventObject() { } EventObject::~EventObject() @@ -12,8 +11,8 @@ EventObject::~EventObject() void EventObject::set_events(PollEvent e) { - events = e; - signal_events_changed.emit(events); + _events = e; + signal_events_changed.emit(_events); } void EventObject::event(PollEvent ev) diff --git a/source/io/eventobject.h b/source/io/eventobject.h index 88a71c7..75cfb73 100644 --- a/source/io/eventobject.h +++ b/source/io/eventobject.h @@ -1,6 +1,7 @@ #ifndef MSP_IO_EVENTOBJECT_H_ #define MSP_IO_EVENTOBJECT_H_ +#include #include "base.h" namespace Msp { @@ -13,7 +14,7 @@ Interface class for objects that can provide event-based I/O. These objects can be fed to the various poll functions in poll.h, or added to an EventDispatcher to generate event signals. */ -class EventObject: public Base +class MSPCORE_API EventObject: public Base { public: /** Emitted when there is data available for reading. If all data is not @@ -25,17 +26,17 @@ public: sigc::signal signal_events_changed; private: - PollEvent events; + PollEvent _events = P_NONE; protected: EventObject(); - virtual ~EventObject(); + ~EventObject() override; void set_events(PollEvent); public: /** Returns a mask of the currently interesting events. Used by EventDispatcher. */ - PollEvent get_events() const { return events; } + PollEvent get_events() const { return _events; } /** Returns a handle for polling. */ virtual const Handle &get_event_handle() = 0; diff --git a/source/io/eventreader.h b/source/io/eventreader.h index 3c01f09..11091ab 100644 --- a/source/io/eventreader.h +++ b/source/io/eventreader.h @@ -25,17 +25,17 @@ private: struct Private; Handle &handle; - Private *priv; + Private *priv = nullptr; public: - EventReader(Handle &, unsigned); + EventReader(Handle &, std::size_t); ~EventReader(); const Handle &get_event(); void start(); void wait(); - unsigned read(char *, unsigned); + unsigned read(char *, std::size_t); }; } // namespace IO diff --git a/source/io/file.cpp b/source/io/file.cpp index 5ead278..7d6e1f9 100644 --- a/source/io/file.cpp +++ b/source/io/file.cpp @@ -1,3 +1,4 @@ +#include #include "file.h" #include "handle_private.h" @@ -104,7 +105,7 @@ void BufferedFile::set_block(bool b) void BufferedFile::set_inherit(bool) { - throw logic_error("BufferedFile::set_inherit"); + throw unsupported("BufferedFile::set_inherit"); } size_t BufferedFile::do_write(const char *buf, size_t size) @@ -146,7 +147,7 @@ int BufferedFile::get() const Handle &BufferedFile::get_handle(Mode) { - throw logic_error("BufferedFile::get_handle"); + throw unsupported("BufferedFile::get_handle"); } SeekOffset BufferedFile::seek(SeekOffset offset, SeekType type) diff --git a/source/io/file.h b/source/io/file.h index aeac6c8..2af56ae 100644 --- a/source/io/file.h +++ b/source/io/file.h @@ -3,26 +3,24 @@ #include #include +#include #include "buffered.h" -#include "filtered.h" #include "handle.h" #include "seekable.h" namespace Msp { namespace IO { -class file_not_found: public std::runtime_error +class MSPCORE_API file_not_found: public std::runtime_error { public: file_not_found(const std::string &fn): std::runtime_error(fn) { } - ~file_not_found() throw() { } }; -class file_already_exists: public std::runtime_error +class MSPCORE_API file_already_exists: public std::runtime_error { public: file_already_exists(const std::string &fn): std::runtime_error(fn) { } - ~file_already_exists() throw() { } }; @@ -31,7 +29,7 @@ A class for reading and writing files. Non-blocking mode is not supported on Win32. */ -class File: public Seekable +class MSPCORE_API File: public Seekable { public: enum CreateMode @@ -55,22 +53,22 @@ public: private: void platform_init(const std::string &, CreateMode); public: - virtual ~File(); + ~File() override; - virtual void set_block(bool); - virtual void set_inherit(bool); + void set_block(bool) override; + void set_inherit(bool) override; protected: - virtual std::size_t do_write(const char *, std::size_t); - virtual std::size_t do_read(char *, std::size_t); + std::size_t do_write(const char *, std::size_t) override; + std::size_t do_read(char *, std::size_t) override; public: - virtual void sync(); + void sync(); - virtual SeekOffset seek(SeekOffset, SeekType); - virtual SeekOffset tell() const; + SeekOffset seek(SeekOffset, SeekType) override; + SeekOffset tell() const override; - virtual const Handle &get_handle(Mode); + const Handle &get_handle(Mode) override; }; inline File::CreateMode operator|(File::CreateMode m, File::CreateMode n) @@ -83,7 +81,7 @@ inline File::CreateMode operator~(File::CreateMode m) { return File::CreateMode(~static_cast(m)); } -class BufferedFile: public Seekable +class MSPCORE_API BufferedFile: public Seekable { private: File file; @@ -93,22 +91,22 @@ private: public: BufferedFile(const std::string &, Mode = M_READ, File::CreateMode = File::C_OVERWRITE); - virtual void set_block(bool); - virtual void set_inherit(bool); + void set_block(bool) override; + void set_inherit(bool) override; protected: - virtual std::size_t do_write(const char *, std::size_t); - virtual std::size_t do_read(char *, std::size_t); + std::size_t do_write(const char *, std::size_t) override; + std::size_t do_read(char *, std::size_t) override; public: - virtual std::size_t put(char); + std::size_t put(char) override; - virtual bool getline(std::string &); - virtual int get(); + bool getline(std::string &) override; + int get() override; - virtual const Handle &get_handle(Mode); + const Handle &get_handle(Mode) override; - virtual SeekOffset seek(SeekOffset, SeekType); - virtual SeekOffset tell() const { return position; } + SeekOffset seek(SeekOffset, SeekType) override; + SeekOffset tell() const override { return position; } }; } // namespace IO diff --git a/source/io/filtered.h b/source/io/filtered.h deleted file mode 100644 index 2092743..0000000 --- a/source/io/filtered.h +++ /dev/null @@ -1,94 +0,0 @@ -#ifndef MSP_IO_FILTERED_H_ -#define MSP_IO_FILTERED_H_ - -namespace Msp { -namespace IO { - -/** -This class is broken by design. Do not use. It exposes base class methods in -an unsafe and misleading way. In particular, a Filtered causes -seeks to behave incorrectly. -*/ -template -class Filtered: public B -{ -private: - struct Activator - { - Filtered &f; - - Activator(Filtered &f_): f(f_) { f.active = true; } - ~Activator() { f.active = false; } - }; - - F filter; - bool active; - -public: - Filtered(): filter(*this), active(false) { } - ~Filtered() { active = true; } - - template - Filtered(A0 a0): B(a0), filter(*this), active(false) { } - - template - Filtered(A0 a0, A1 a1): B(a0, a1), filter(*this), active(false) { } - -protected: - virtual unsigned do_write(const char *b, unsigned s) - { - if(!active) - { - Activator a(*this); - return filter.write(b, s); - } - else - return B::do_write(b, s); - } - - virtual unsigned do_read(char *b, unsigned s) - { - if(!active) - { - Activator a(*this); - return filter.read(b, s); - } - else - return B::do_read(b, s); - } - -public: - virtual unsigned put(char c) - { - if(active) - return B::put(c); - - Activator a(*this); - return filter.put(c); - } - - virtual bool getline(std::string &l) - { - if(active) - return B::getline(l); - - Activator a(*this); - return filter.getline(l); - } - - virtual int get() - { - if(active) - return B::get(); - - Activator a(*this); - return filter.get(); - } - - F &get_filter() { return filter; } -}; - -} // namespace IO -} // namespace Msp - -#endif diff --git a/source/io/generic/asset.cpp b/source/io/generic/asset.cpp index 7971f1b..b5cad9a 100644 --- a/source/io/generic/asset.cpp +++ b/source/io/generic/asset.cpp @@ -28,7 +28,7 @@ Asset::~Asset() delete priv; } -unsigned Asset::do_read(char *buf, unsigned size) +size_t Asset::do_read(char *buf, size_t size) { return priv->file->read(buf, size); } diff --git a/source/io/handle.cpp b/source/io/handle.cpp index 693f93f..53b5a7e 100644 --- a/source/io/handle.cpp +++ b/source/io/handle.cpp @@ -25,9 +25,9 @@ Handle::~Handle() delete priv; } -Handle::operator const void *() const +Handle::operator bool() const { - return priv->handle!=INVALID_HANDLE_VALUE ? this : 0; + return priv->handle!=INVALID_HANDLE_VALUE; } diff --git a/source/io/handle.h b/source/io/handle.h index be2097e..06c2034 100644 --- a/source/io/handle.h +++ b/source/io/handle.h @@ -2,17 +2,18 @@ #define MSP_IO_HANDLE_H_ #include +#include namespace Msp { namespace IO { -class Handle +class MSPCORE_API Handle { public: struct Private; private: - Private *priv; + Private *priv = nullptr; public: Handle(); @@ -23,10 +24,7 @@ public: Private &operator*() { return *priv; } const Private &operator*() const { return *priv; } - /** This is effectively a boolean conversion, but avoids accidental - conversion to OS native handles. Unix-based systems use int and win32 uses - void *; const void * is not implicitly convertible to either. */ - operator const void *() const; + explicit operator bool() const; }; diff --git a/source/io/memory.cpp b/source/io/memory.cpp index 616150f..0539fdb 100644 --- a/source/io/memory.cpp +++ b/source/io/memory.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "handle.h" #include "memory.h" @@ -8,43 +9,34 @@ using namespace std; namespace Msp { namespace IO { -Memory::Memory(char *d, size_t s, Mode m) -{ - init(d, d+s, m); -} +Memory::Memory(char *d, std::size_t s, Mode m): + Memory(d, d+s, m) +{ } -Memory::Memory(char *b, char *e, Mode m) +Memory::Memory(char *b, char *e, Mode m): + begin(b), + end(e), + pos(begin) { - init(b, e, m); + mode = m; } -Memory::Memory(const char *cd, size_t s) -{ - char *d = const_cast(cd); - init(d, d+s, M_READ); -} +Memory::Memory(const char *d, std::size_t s): + Memory(const_cast(d), const_cast(d+s), M_READ) +{ } -Memory::Memory(const char *b, const char *e) -{ - init(const_cast(b), const_cast(e), M_READ); -} - -void Memory::init(char *b, char *e, Mode m) -{ - begin = b; - end = e; - pos = begin; - mode = m; -} +Memory::Memory(const char *b, const char *e): + Memory(const_cast(b), const_cast(e), M_READ) +{ } void Memory::set_block(bool) { - throw logic_error("Memory::set_block"); + throw unsupported("Memory::set_block"); } void Memory::set_inherit(bool) { - throw logic_error("Memory::set_inherit"); + throw unsupported("Memory::set_inherit"); } size_t Memory::do_write(const char *buf, size_t size) @@ -115,7 +107,7 @@ int Memory::get() const Handle &Memory::get_handle(Mode) { - throw logic_error("Memory::get_handle"); + throw unsupported("Memory::get_handle"); } SeekOffset Memory::seek(SeekOffset off, SeekType type) diff --git a/source/io/memory.h b/source/io/memory.h index 5b9961c..e009cfd 100644 --- a/source/io/memory.h +++ b/source/io/memory.h @@ -1,42 +1,40 @@ #ifndef MSP_IO_MEMORY_H_ #define MSP_IO_MEMORY_H_ +#include #include "seekable.h" namespace Msp { namespace IO { -class Memory: public Seekable +class MSPCORE_API Memory: public Seekable { private: - char *begin; - char *end; - char *pos; + char *begin = nullptr; + char *end = nullptr; + char *pos = nullptr; public: - Memory(char *, std::size_t, Mode = M_RDWR); + Memory(char *d, std::size_t s, Mode m = M_RDWR); Memory(char *, char *, Mode = M_RDWR); - Memory(const char *, std::size_t); - Memory(const char *, const char *); -private: - void init(char *, char *, Mode); + Memory(const char *d, std::size_t s); + Memory(const char *b, const char *e); -public: - virtual void set_block(bool); - virtual void set_inherit(bool); + void set_block(bool) override; + void set_inherit(bool) override; private: - virtual std::size_t do_write(const char *, std::size_t); - virtual std::size_t do_read(char *, std::size_t); + std::size_t do_write(const char *, std::size_t) override; + std::size_t do_read(char *, std::size_t) override; public: - virtual std::size_t put(char); - virtual bool getline(std::string &); - virtual int get(); + std::size_t put(char) override; + bool getline(std::string &) override; + int get() override; - virtual const Handle &get_handle(Mode); + const Handle &get_handle(Mode) override; - virtual SeekOffset seek(SeekOffset, SeekType); - virtual SeekOffset tell() const { return pos-begin; } + SeekOffset seek(SeekOffset, SeekType) override; + SeekOffset tell() const override { return pos-begin; } }; } // namespace IO diff --git a/source/io/mode.h b/source/io/mode.h index 0f7bb4f..6230a65 100644 --- a/source/io/mode.h +++ b/source/io/mode.h @@ -2,6 +2,7 @@ #define MSP_IO_MODE_H_ #include +#include namespace Msp { namespace IO { @@ -30,11 +31,10 @@ inline void adjust_mode(Mode &m, Mode f, bool b) { m = b ? (m|f) : (m&~f); } -class invalid_access: public std::logic_error +class MSPCORE_API invalid_access: public std::logic_error { public: invalid_access(Mode); - ~invalid_access() throw() { } }; } // namespace IO diff --git a/source/io/pipe.cpp b/source/io/pipe.cpp index 01bf20a..f6bc335 100644 --- a/source/io/pipe.cpp +++ b/source/io/pipe.cpp @@ -43,15 +43,19 @@ void Pipe::set_mode(Mode m) void Pipe::set_block(bool b) { adjust_mode(mode, M_NONBLOCK, !b); - sys_set_blocking(read_handle, b); - sys_set_blocking(write_handle, b); + if(read_handle) + sys_set_blocking(read_handle, b); + if(write_handle) + sys_set_blocking(write_handle, b); } void Pipe::set_inherit(bool i) { adjust_mode(mode, M_INHERIT, i); - sys_set_inherit(read_handle, i); - sys_set_inherit(write_handle, i); + if(read_handle) + sys_set_inherit(read_handle, i); + if(write_handle) + sys_set_inherit(write_handle, i); } size_t Pipe::do_write(const char *buf, size_t size) diff --git a/source/io/pipe.h b/source/io/pipe.h index 5fc0b3d..c62aa36 100644 --- a/source/io/pipe.h +++ b/source/io/pipe.h @@ -1,6 +1,7 @@ #ifndef MSP_IO_PIPE_H_ #define MSP_IO_PIPE_H_ +#include #include "eventobject.h" #include "eventreader.h" #include "handle.h" @@ -8,7 +9,7 @@ namespace Msp { namespace IO { -class Pipe: public EventObject +class MSPCORE_API Pipe: public EventObject { private: Handle read_handle; @@ -23,16 +24,16 @@ public: ~Pipe(); void set_mode(Mode); - virtual void set_block(bool); - virtual void set_inherit(bool); + void set_block(bool) override; + void set_inherit(bool) override; protected: - virtual std::size_t do_write(const char *, std::size_t); - virtual std::size_t do_read(char *, std::size_t); + std::size_t do_write(const char *, std::size_t) override; + std::size_t do_read(char *, std::size_t) override; public: - virtual const Handle &get_handle(Mode); - virtual const Handle &get_event_handle() { return reader.get_event(); } + const Handle &get_handle(Mode) override; + const Handle &get_event_handle() override { return reader.get_event(); } }; } // namespace IO diff --git a/source/io/poll.cpp b/source/io/poll.cpp index 4ca2f3d..7aa41e1 100644 --- a/source/io/poll.cpp +++ b/source/io/poll.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include "eventobject.h" #include "poll.h" @@ -10,9 +10,7 @@ namespace Msp { namespace IO { Poller::Poller(): - priv(new Private), - events_changed(false), - objs_changed(false) + priv(new Private) { } Poller::~Poller() @@ -46,10 +44,10 @@ void Poller::set_object(EventObject &obj, PollEvent ev) #ifdef _WIN32 if(objects.size()>=MAXIMUM_WAIT_OBJECTS) - throw logic_error("Maximum number of wait objects reached"); + throw invalid_state("too many objects"); #endif - objects.push_back(PolledObject(&obj, ev)); + objects.push_back({ &obj, ev }); objs_changed = true; } @@ -93,7 +91,7 @@ PollEvent poll(EventObject &obj, PollEvent pe) PollEvent poll(EventObject &obj, PollEvent pe, const Time::TimeDelta &timeout) { if(timeout(timeout/Time::msec)); } diff --git a/source/io/poll.h b/source/io/poll.h index 0fb1ebc..53e3808 100644 --- a/source/io/poll.h +++ b/source/io/poll.h @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -31,24 +32,22 @@ inline PollEvent operator~(PollEvent e) { return PollEvent(~static_cast(e)); } -class Poller: private NonCopyable +class MSPCORE_API Poller: private NonCopyable { public: struct PolledObject { EventObject *object; PollEvent events; - - PolledObject(EventObject *o, PollEvent e): object(o), events(e) { } }; private: struct Private; std::vector objects; - Private *priv; - bool events_changed; - bool objs_changed; + Private *priv = nullptr; + bool events_changed = false; + bool objs_changed = false; std::vector poll_result; public: @@ -66,8 +65,8 @@ public: const std::vector &get_result() const { return poll_result; } }; -PollEvent poll(EventObject &, PollEvent); -PollEvent poll(EventObject &, PollEvent, const Time::TimeDelta &); +MSPCORE_API PollEvent poll(EventObject &, PollEvent); +MSPCORE_API PollEvent poll(EventObject &, PollEvent, const Time::TimeDelta &); } // namespace IO } // namespace Msp diff --git a/source/io/seekable.h b/source/io/seekable.h index f0170b4..e549d24 100644 --- a/source/io/seekable.h +++ b/source/io/seekable.h @@ -1,8 +1,9 @@ #ifndef MSP_IO_SEEKABLE_H_ #define MSP_IO_SEEKABLE_H_ +#include #include -#include +#include #include "base.h" namespace Msp { @@ -10,7 +11,7 @@ namespace IO { class Handle; -typedef Int64 SeekOffset; +typedef std::int64_t SeekOffset; enum SeekType { @@ -20,18 +21,18 @@ enum SeekType }; -class bad_seek: public std::runtime_error +class MSPCORE_API bad_seek: public std::runtime_error { public: bad_seek(SeekOffset, SeekType); - virtual ~bad_seek() throw() { } + ~bad_seek() throw() override = default; }; -class Seekable: public Base +class MSPCORE_API Seekable: public Base { protected: - Seekable() { } + Seekable() = default; public: /** Changes the read/write offset. Returns the new offset. */ diff --git a/source/io/serial.cpp b/source/io/serial.cpp index 09a9768..b256b11 100644 --- a/source/io/serial.cpp +++ b/source/io/serial.cpp @@ -106,7 +106,7 @@ void Serial::set_parameters(const string ¶ms) state.apply_to(handle); } -unsigned Serial::do_write(const char *buf, unsigned size) +size_t Serial::do_write(const char *buf, size_t size) { if(size==0) return 0; @@ -114,12 +114,12 @@ unsigned Serial::do_write(const char *buf, unsigned size) return sys_write(handle, buf, size); } -unsigned Serial::do_read(char *buf, unsigned size) +size_t Serial::do_read(char *buf, size_t size) { if(size==0) return 0; - unsigned ret = reader.read(buf, size); + size_t ret = reader.read(buf, size); if(ret==0) set_eof(); diff --git a/source/io/serial.h b/source/io/serial.h index dbc7a77..b83f1e5 100644 --- a/source/io/serial.h +++ b/source/io/serial.h @@ -1,6 +1,7 @@ #ifndef MSP_IO_SERIAL_H_ #define MSP_IO_SERIAL_H_ +#include #include "eventobject.h" #include "eventreader.h" #include "handle.h" @@ -8,7 +9,7 @@ namespace Msp { namespace IO { -class Serial: public EventObject +class MSPCORE_API Serial: public EventObject { public: enum Parity @@ -29,14 +30,14 @@ public: private: void platform_init(const std::string &); public: - virtual ~Serial(); + ~Serial() override; private: void close(); public: - virtual void set_block(bool); - virtual void set_inherit(bool); + void set_block(bool) override; + void set_inherit(bool) override; void set_baud_rate(unsigned); void set_data_bits(unsigned); @@ -45,12 +46,12 @@ public: void set_parameters(const std::string &); private: - virtual unsigned do_write(const char *, unsigned); - virtual unsigned do_read(char *, unsigned); + std::size_t do_write(const char *, std::size_t) override; + std::size_t do_read(char *, std::size_t) override; public: - virtual const Handle &get_handle(Mode); - virtual const Handle &get_event_handle() { return reader.get_event(); } + const Handle &get_handle(Mode) override; + const Handle &get_event_handle() override { return reader.get_event(); } }; } // namespace IO diff --git a/source/io/slice.cpp b/source/io/slice.cpp index 4007a5e..9ca5966 100644 --- a/source/io/slice.cpp +++ b/source/io/slice.cpp @@ -1,4 +1,4 @@ -#include +#include #include "slice.h" using namespace std; @@ -9,12 +9,10 @@ namespace IO { Slice::Slice(Seekable &b, SeekOffset s, SeekOffset l): below(b), start_offset(s), - length(l), - position(0), - sync_position(true) + length(l) { if(s<0 || l<0) - throw invalid_argument("Slice"); + throw invalid_argument("Slice::Slice"); Base::Synchronize sync(below); mode = below.get_mode()&M_RDWR; @@ -23,12 +21,12 @@ Slice::Slice(Seekable &b, SeekOffset s, SeekOffset l): void Slice::set_block(bool) { - throw logic_error("Slice::set_block"); + throw unsupported("Slice::set_block"); } void Slice::set_inherit(bool) { - throw logic_error("Slice::set_inherit"); + throw unsupported("Slice::set_inherit"); } void Slice::flush() @@ -110,7 +108,7 @@ int Slice::get() const Handle &Slice::get_handle(Mode) { - throw logic_error("Slice::get_handle"); + throw unsupported("Slice::get_handle"); } SeekOffset Slice::seek(SeekOffset off, SeekType type) diff --git a/source/io/slice.h b/source/io/slice.h index 8ca4327..272fa2c 100644 --- a/source/io/slice.h +++ b/source/io/slice.h @@ -1,6 +1,7 @@ #ifndef MSP_IO_SLICE_H_ #define MSP_IO_SLICE_H_ +#include #include "seekable.h" namespace Msp { @@ -16,37 +17,37 @@ its range. If the offset of the underlying object is changed, the Slice will restore it before the next access. This enables multiple Slices to be created on top of the same object. */ -class Slice: public Seekable, public sigc::trackable +class MSPCORE_API Slice: public Seekable, public sigc::trackable { private: Seekable &below; - SeekOffset start_offset; - SeekOffset length; - SeekOffset position; - bool sync_position; + SeekOffset start_offset = 0; + SeekOffset length = 0; + SeekOffset position = 0; + bool sync_position = true; public: Slice(Seekable &, SeekOffset, SeekOffset); - virtual void set_block(bool); - virtual void set_inherit(bool); + void set_block(bool) override; + void set_inherit(bool) override; private: void flush(); unsigned prepare_op(unsigned, Mode); protected: - virtual std::size_t do_write(const char *, std::size_t); - virtual std::size_t do_read(char *, std::size_t); + std::size_t do_write(const char *, std::size_t) override; + std::size_t do_read(char *, std::size_t) override; public: - virtual std::size_t put(char); - virtual int get(); + std::size_t put(char) override; + int get() override; - virtual const Handle &get_handle(Mode); + const Handle &get_handle(Mode) override; - virtual SeekOffset seek(SeekOffset, SeekType); - virtual SeekOffset tell() const { return position; } + SeekOffset seek(SeekOffset, SeekType) override; + SeekOffset tell() const override { return position; } }; } // namespace IO diff --git a/source/io/unix/eventreader.cpp b/source/io/unix/eventreader.cpp index fcbc892..b87a347 100644 --- a/source/io/unix/eventreader.cpp +++ b/source/io/unix/eventreader.cpp @@ -3,9 +3,8 @@ namespace Msp { namespace IO { -EventReader::EventReader(Handle &h, unsigned): - handle(h), - priv(0) +EventReader::EventReader(Handle &h, size_t): + handle(h) { } EventReader::~EventReader() @@ -22,7 +21,7 @@ void EventReader::start() void EventReader::wait() { } -unsigned EventReader::read(char *buf, unsigned len) +unsigned EventReader::read(char *buf, size_t len) { return sys_read(handle, buf, len); } diff --git a/source/io/unix/handle_platform.h b/source/io/unix/handle_platform.h index b241669..4254687 100644 --- a/source/io/unix/handle_platform.h +++ b/source/io/unix/handle_platform.h @@ -6,7 +6,7 @@ namespace IO { typedef int PlatformHandle; -#define INVALID_HANDLE_VALUE -1 +const PlatformHandle INVALID_HANDLE_VALUE = -1; } // namespace IO } // namespace Msp diff --git a/source/io/unix/poll.cpp b/source/io/unix/poll.cpp index 28d3aeb..e3db10e 100644 --- a/source/io/unix/poll.cpp +++ b/source/io/unix/poll.cpp @@ -91,7 +91,7 @@ void Poller::platform_poll(int timeout) for(unsigned i=0; (i0); ++i) if(priv->pfd[i].revents) { - poll_result.push_back(PolledObject(objects[i].object, poll_event_from_sys(priv->pfd[i].revents))); + poll_result.push_back({ objects[i].object, poll_event_from_sys(priv->pfd[i].revents) }); --ret; } } diff --git a/source/io/unix/poll_platform.h b/source/io/unix/poll_platform.h index bfd83da..0166b98 100644 --- a/source/io/unix/poll_platform.h +++ b/source/io/unix/poll_platform.h @@ -3,6 +3,7 @@ #include #include +#include "poll.h" namespace Msp { namespace IO { diff --git a/source/io/unix/seekable.cpp b/source/io/unix/seekable.cpp index a402742..63af4b9 100644 --- a/source/io/unix/seekable.cpp +++ b/source/io/unix/seekable.cpp @@ -21,7 +21,7 @@ int sys_seek_type(SeekType st) else if(st==S_END) return SEEK_END; - throw invalid_argument("sys_seek_type"); + throw invalid_argument("IO::sys_seek"); } } diff --git a/source/io/unix/serial.cpp b/source/io/unix/serial.cpp index 70286b7..728f3d8 100644 --- a/source/io/unix/serial.cpp +++ b/source/io/unix/serial.cpp @@ -80,14 +80,14 @@ void Serial::DeviceState::set_baud_rate(unsigned baud) case 3000000: speed = 0010015; break; case 3500000: speed = 0010016; break; case 4000000: speed = 0010017; break; - default: throw invalid_argument("set_baud_rate"); + default: throw invalid_argument("Serial::set_baud_rate"); } int ret = cfsetospeed(&state, speed); if(ret==0) ret = cfsetispeed(&state, speed); if(ret<0) - throw invalid_argument("set_baud_rate"); + throw invalid_argument("Serial::set_baud_rate"); } void Serial::DeviceState::set_data_bits(unsigned bits) @@ -99,7 +99,7 @@ void Serial::DeviceState::set_data_bits(unsigned bits) case 6: flag = CS6; break; case 7: flag = CS7; break; case 8: flag = CS8; break; - default: throw invalid_argument("set_data_bits"); + default: throw invalid_argument("Serial::set_data_bits"); } state.c_cflag = (state.c_cflag&~CSIZE)|flag; @@ -113,7 +113,7 @@ void Serial::DeviceState::set_parity(Serial::Parity par) case Serial::NONE: flag = 0; break; case Serial::EVEN: flag = PARENB; break; case Serial::ODD: flag = PARENB|PARODD; break; - default: throw invalid_argument("set_parity"); + default: throw invalid_argument("Serial::set_parity"); } state.c_cflag = (state.c_cflag&~(PARENB|PARODD))|flag; @@ -126,7 +126,7 @@ void Serial::DeviceState::set_stop_bits(unsigned bits) { case 1: flag = 0; break; case 2: flag = CSTOPB; break; - default: throw invalid_argument("set_stop_bits"); + default: throw invalid_argument("Serial::set_stop_bits"); } state.c_cflag = (state.c_cflag&~CSTOPB)|flag; diff --git a/source/io/utils.cpp b/source/io/utils.cpp index eee51cc..2b80cc7 100644 --- a/source/io/utils.cpp +++ b/source/io/utils.cpp @@ -4,9 +4,9 @@ namespace Msp { namespace IO { -unsigned read_all(Base &obj, char *buf, unsigned size) +size_t read_all(Base &obj, char *buf, size_t size) { - unsigned pos = 0; + size_t pos = 0; while(pos +#include + namespace Msp { namespace IO { @@ -12,7 +15,7 @@ data is read, regardless of the blocking mode of the object. Note: If the data is not immediately available and the object is in non-blocking mode, this function effectively becomes a busyloop until it can get more data. */ -unsigned read_all(Base &, char *, unsigned); +MSPCORE_API std::size_t read_all(Base &, char *, std::size_t); } // namespace IO } // namespace Msp diff --git a/source/io/windows/console.cpp b/source/io/windows/console.cpp index a331133..4f78487 100644 --- a/source/io/windows/console.cpp +++ b/source/io/windows/console.cpp @@ -1,3 +1,4 @@ +#include #include #include "console.h" #include "handle_private.h" @@ -13,7 +14,7 @@ DWORD stream_to_sys(Msp::IO::Console::Stream stream) case Msp::IO::Console::CIN: return STD_INPUT_HANDLE; case Msp::IO::Console::COUT: return STD_OUTPUT_HANDLE; case Msp::IO::Console::CERR: return STD_ERROR_HANDLE; - default: throw invalid_argument("stream_to_sys"); + default: throw Msp::internal_error("stream_to_sys"); } } diff --git a/source/io/windows/eventreader.cpp b/source/io/windows/eventreader.cpp index 82d9e8c..8f208c2 100644 --- a/source/io/windows/eventreader.cpp +++ b/source/io/windows/eventreader.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include "eventreader.h" @@ -13,28 +13,25 @@ struct EventReader::Private { OVERLAPPED overlapped; Handle event; - unsigned buf_size; - char *buffer; - unsigned buf_avail; - char *buf_next; - bool pending; - bool eof; + size_t buf_size = 0; + char *buffer = nullptr; + size_t buf_avail = 0; + char *buf_next = nullptr; + bool pending = false; + bool eof = false; }; -EventReader::EventReader(Handle &h, unsigned size): +EventReader::EventReader(Handle &h, size_t size): handle(h), priv(new Private) { memset(&priv->overlapped, 0, sizeof(OVERLAPPED)); - *priv->event = CreateEvent(0, true, false, 0); + *priv->event = CreateEvent(nullptr, true, false, nullptr); priv->overlapped.hEvent = *priv->event; priv->buf_size = size; priv->buffer = new char[priv->buf_size]; - priv->buf_avail = 0; priv->buf_next = priv->buffer; - priv->pending = false; - priv->eof = false; } EventReader::~EventReader() @@ -95,7 +92,7 @@ void EventReader::wait() } } -unsigned EventReader::read(char *buf, unsigned len) +unsigned EventReader::read(char *buf, size_t len) { if(!priv->buf_avail) { diff --git a/source/io/windows/file.cpp b/source/io/windows/file.cpp index 3cbdc4a..a388ade 100644 --- a/source/io/windows/file.cpp +++ b/source/io/windows/file.cpp @@ -35,10 +35,10 @@ void File::platform_init(const string &fn, CreateMode cm) SECURITY_ATTRIBUTES sec_attr; sec_attr.nLength = sizeof(SECURITY_ATTRIBUTES); - sec_attr.lpSecurityDescriptor = 0; + sec_attr.lpSecurityDescriptor = nullptr; sec_attr.bInheritHandle = !!(mode&M_INHERIT); - *handle = CreateFile(fn.c_str(), flags, share_flags, 0, create_flags, FILE_ATTRIBUTE_NORMAL, &sec_attr); + *handle = CreateFile(fn.c_str(), flags, share_flags, &sec_attr, create_flags, FILE_ATTRIBUTE_NORMAL, nullptr); if(!handle) { int err = GetLastError(); diff --git a/source/io/windows/handle.cpp b/source/io/windows/handle.cpp index 1cdf8ce..e72282a 100644 --- a/source/io/windows/handle.cpp +++ b/source/io/windows/handle.cpp @@ -20,10 +20,10 @@ void sys_set_inherit(Handle &, bool) size_t sys_read(Handle &handle, char *buf, size_t size) { if(size>numeric_limits::max()) - throw invalid_argument("read"); + throw invalid_argument("IO::sys_read"); DWORD ret; - if(ReadFile(*handle, buf, size, &ret, 0)==0) + if(ReadFile(*handle, buf, size, &ret, nullptr)==0) throw system_error("ReadFile"); return ret; @@ -32,10 +32,10 @@ size_t sys_read(Handle &handle, char *buf, size_t size) size_t sys_write(Handle &handle, const char *buf, size_t size) { if(size>numeric_limits::max()) - throw invalid_argument("write"); + throw invalid_argument("IO::sys_write"); DWORD ret; - if(WriteFile(*handle, buf, size, &ret, 0)==0) + if(WriteFile(*handle, buf, size, &ret, nullptr)==0) throw system_error("WriteFile"); return ret; diff --git a/source/io/windows/handle_platform.h b/source/io/windows/handle_platform.h index f12e5f7..776e8f3 100644 --- a/source/io/windows/handle_platform.h +++ b/source/io/windows/handle_platform.h @@ -1,7 +1,7 @@ #ifndef MSP_IO_HANDLE_PLATFORM_H_ #define MSP_IO_HANDLE_PLATFORM_H_ -#include +#include namespace Msp { namespace IO { diff --git a/source/io/windows/pipe.cpp b/source/io/windows/pipe.cpp index 02d7f33..70d256c 100644 --- a/source/io/windows/pipe.cpp +++ b/source/io/windows/pipe.cpp @@ -11,11 +11,11 @@ namespace IO { void Pipe::platform_init() { string name = format("\\\\.\\pipe\\%u.%p", GetCurrentProcessId(), this); - *read_handle = CreateNamedPipe(name.c_str(), PIPE_ACCESS_INBOUND|FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE, 1, 1024, 1024, 0, 0); + *read_handle = CreateNamedPipe(name.c_str(), PIPE_ACCESS_INBOUND|FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE, 1, 1024, 1024, 0, nullptr); if(!read_handle) throw system_error("CreateNamedPipe"); - *write_handle = CreateFile(name.c_str(), GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); + *write_handle = CreateFile(name.c_str(), GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, nullptr); if(!write_handle) { unsigned err = GetLastError(); diff --git a/source/io/windows/poll.cpp b/source/io/windows/poll.cpp index 0d644cd..cbd92fd 100644 --- a/source/io/windows/poll.cpp +++ b/source/io/windows/poll.cpp @@ -1,3 +1,4 @@ +#include #include #include "eventobject.h" #include "handle.h" diff --git a/source/io/windows/poll_platform.h b/source/io/windows/poll_platform.h index ccf92c3..62a000f 100644 --- a/source/io/windows/poll_platform.h +++ b/source/io/windows/poll_platform.h @@ -1,8 +1,9 @@ #ifndef MSP_IO_POLL_PLATFORM_H_ #define MSP_IO_POLL_PLATFORM_H_ -#include +#include #include +#include "poll.h" namespace Msp { namespace IO { diff --git a/source/io/windows/seekable.cpp b/source/io/windows/seekable.cpp index 73c5cc5..3756cf1 100644 --- a/source/io/windows/seekable.cpp +++ b/source/io/windows/seekable.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include "handle.h" #include "handle_private.h" @@ -19,7 +19,7 @@ int sys_seek_type(SeekType st) else if(st==S_END) return FILE_END; - throw invalid_argument("sys_seek_type"); + throw invalid_argument("IO::sys_seek"); } } diff --git a/source/io/windows/serial.cpp b/source/io/windows/serial.cpp index 84a3175..d041c87 100644 --- a/source/io/windows/serial.cpp +++ b/source/io/windows/serial.cpp @@ -13,7 +13,7 @@ void Serial::platform_init(const string &port) { string name = "\\\\.\\"+port; - *handle = CreateFile(name.c_str(), GENERIC_READ|GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, 0); + *handle = CreateFile(name.c_str(), GENERIC_READ|GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, nullptr); if(!handle) throw system_error(format("CreateFile(%s)", port)); mode = M_READ|M_WRITE; @@ -56,7 +56,7 @@ void Serial::DeviceState::set_parity(Serial::Parity par) case Serial::NONE: state.Parity = NOPARITY; break; case Serial::EVEN: state.Parity = EVENPARITY; break; case Serial::ODD: state.Parity = ODDPARITY; break; - default: throw invalid_argument("set_parity"); + default: throw invalid_argument("Serial::set_parity"); } } @@ -66,7 +66,7 @@ void Serial::DeviceState::set_stop_bits(unsigned bits) { case 1: state.StopBits = ONESTOPBIT; break; case 2: state.StopBits = TWOSTOPBITS; break; - default: throw invalid_argument("set_stop_bits"); + default: throw invalid_argument("Serial::set_stop_bits"); } } diff --git a/source/io/windows/serial_platform.h b/source/io/windows/serial_platform.h index dd7dd50..3173736 100644 --- a/source/io/windows/serial_platform.h +++ b/source/io/windows/serial_platform.h @@ -1,7 +1,7 @@ #ifndef MSP_IO_SERIAL_PLATFORM_H_ #define MSP_IO_SERIAL_PLATFORM_H_ -#include +#include namespace Msp { namespace IO { diff --git a/source/io/zlibcompressed.cpp b/source/io/zlibcompressed.cpp index 2220bcc..8896f14 100644 --- a/source/io/zlibcompressed.cpp +++ b/source/io/zlibcompressed.cpp @@ -1,6 +1,7 @@ #ifdef WITH_ZLIB #include #endif +#include #include "zlibcompressed.h" using namespace std; @@ -14,7 +15,7 @@ zlib_error::zlib_error(const string &w, int c): #else runtime_error(w), #endif - code_(c) + m_code(c) { } @@ -30,23 +31,13 @@ struct ZlibCompressed::Private ZlibCompressed::Private::Private() { #ifdef WITH_ZLIB - stream.zalloc = 0; - stream.zfree = 0; - stream.opaque = 0; + stream.zalloc = nullptr; + stream.zfree = nullptr; + stream.opaque = nullptr; #endif } -ZlibCompressed::ZlibCompressed(Base &b, unsigned level): - below(b) -{ - mode = below.get_mode()&M_RDWR; - if(mode!=M_READ && mode!=M_WRITE) - throw invalid_access(mode); - - init(level); -} - ZlibCompressed::ZlibCompressed(Base &b, Mode m, unsigned level): below(b) { @@ -54,16 +45,7 @@ ZlibCompressed::ZlibCompressed(Base &b, Mode m, unsigned level): if(mode!=M_READ && mode!=M_WRITE) throw invalid_access(m); - init(level); -} - -void ZlibCompressed::init(unsigned level) -{ #ifdef WITH_ZLIB - buffer_size = 1024; - in_buffer = 0; - out_buffer = 0; - stream_end = false; priv = new Private; if(mode==M_WRITE) @@ -92,7 +74,7 @@ void ZlibCompressed::init(unsigned level) (void)buffer_size; (void)stream_end; (void)level; - throw zlib_error("unsupported", -1); + throw unsupported("ZlibCompressed"); #endif } @@ -115,12 +97,12 @@ ZlibCompressed::~ZlibCompressed() void ZlibCompressed::set_block(bool) { - throw logic_error("ZlibCompressed::set_block"); + throw unsupported("ZlibCompressed::set_block"); } void ZlibCompressed::set_inherit(bool) { - throw logic_error("ZlibCompressed::set_inherit"); + throw unsupported("ZlibCompressed::set_inherit"); } void ZlibCompressed::flush() @@ -280,7 +262,7 @@ size_t ZlibCompressed::do_read(char *data, size_t size) const Handle &ZlibCompressed::get_handle(Mode) { - throw logic_error("ZlibCompressed::get_handle"); + throw unsupported("ZlibCompressed::get_handle"); } } // namespace IO diff --git a/source/io/zlibcompressed.h b/source/io/zlibcompressed.h index e4ae6e0..1dc1569 100644 --- a/source/io/zlibcompressed.h +++ b/source/io/zlibcompressed.h @@ -4,21 +4,21 @@ #include #include #include +#include #include "base.h" namespace Msp { namespace IO { -class zlib_error: public std::runtime_error +class MSPCORE_API zlib_error: public std::runtime_error { private: - int code_; + int m_code; public: zlib_error(const std::string &, int); - ~zlib_error() throw() { } - int code() const throw() { return code_; } + int code() const noexcept { return m_code; } }; /** @@ -28,41 +28,37 @@ operates on top of another I/O object. To ensure proper termination of the compressed data stream, the ZlibCompressed object must be destroyed before the underlying object is closed. */ -class ZlibCompressed: public Base, public sigc::trackable +class MSPCORE_API ZlibCompressed: public Base, public sigc::trackable { private: struct Private; Base &below; - std::size_t buffer_size; - unsigned char *in_buffer; - unsigned char *out_buffer; - bool stream_end; - Private *priv; + std::size_t buffer_size = 1024; + unsigned char *in_buffer = nullptr; + unsigned char *out_buffer = nullptr; + bool stream_end = false; + Private *priv = nullptr; public: /** Creates a zlib de/compression object. The underlying object must be open for reading or writing, not both. The level parameter determines compression quality, ranging from 1 (fastest) to 9 (best compression). */ - ZlibCompressed(Base &, unsigned level = 9); + ZlibCompressed(Base &b, unsigned level = 9): ZlibCompressed(b, b.get_mode()&M_RDWR, level) { } /** Creates a zlib de/compression object. Mode must be either read or write, and compatible with the underlying object. */ ZlibCompressed(Base &, Mode, unsigned level = 9); -private: - void init(unsigned); - -public: - virtual ~ZlibCompressed(); + ~ZlibCompressed() override; - virtual void set_block(bool); - virtual void set_inherit(bool); + void set_block(bool) override; + void set_inherit(bool) override; void flush(); protected: - virtual std::size_t do_write(const char *, std::size_t); + std::size_t do_write(const char *, std::size_t) override; private: /** Compresses data and writes it to the underlying object. Returns true if @@ -72,9 +68,9 @@ private: bool compress_data(int flush_mode); public: - virtual std::size_t do_read(char *, std::size_t); + std::size_t do_read(char *, std::size_t) override; - virtual const Handle &get_handle(Mode); + const Handle &get_handle(Mode) override; }; } // namespace IO diff --git a/source/stringcodec/ascii.h b/source/stringcodec/ascii.h index 6980494..755edeb 100644 --- a/source/stringcodec/ascii.h +++ b/source/stringcodec/ascii.h @@ -1,35 +1,36 @@ #ifndef MSP_STRINGCODEC_ASCII_H_ #define MSP_STRINGCODEC_ASCII_H_ +#include #include "codec.h" namespace Msp { namespace StringCodec { -class Ascii: public StandardCodec +class MSPCORE_API Ascii: public StandardCodec { public: - class Encoder: public Codec::Encoder + class MSPCORE_API Encoder: public Codec::Encoder { public: Encoder(ErrorMode em = DEFAULT): Codec::Encoder(em) { } - virtual void encode_char(unichar, std::string &); + void encode_char(unichar, std::string &) override; private: - virtual void transliterate(unichar, std::string &); + void transliterate(unichar, std::string &) override; }; - class Decoder: public Codec::Decoder + class MSPCORE_API Decoder: public Codec::Decoder { public: Decoder(ErrorMode em = DEFAULT): Codec::Decoder(em) { } - virtual unichar decode_char(const std::string &, std::string::const_iterator &); + unichar decode_char(const std::string &, std::string::const_iterator &) override; }; Ascii(ErrorMode em = DEFAULT): StandardCodec(em) { } - virtual const char *get_name() const { return "ASCII"; } + const char *get_name() const override { return "ASCII"; } }; } // namespace StringCodec diff --git a/source/stringcodec/codec.cpp b/source/stringcodec/codec.cpp index abec134..ff2bd63 100644 --- a/source/stringcodec/codec.cpp +++ b/source/stringcodec/codec.cpp @@ -86,7 +86,7 @@ Codec *create_codec(const string &n) else if(em_str=="trans" || em_str=="transliterate") em = TRANSLITERATE; else - throw invalid_argument("invalid error mode"); + throw invalid_argument("StringCodec::create_codec"); } if(name=="ascii") return new Ascii(em); @@ -101,7 +101,7 @@ Codec *create_codec(const string &n) if(name=="utf16be") return new Utf16(em, Utf16::BIG); if(name=="utf16le") return new Utf16(em, Utf16::LITTLE); if(name=="windows1252" || name=="cp1252") return new Windows1252(em); - throw invalid_argument("unknown string codec"); + throw invalid_argument("StringCodec::create_codec"); } Codec *detect_codec(const string &str) diff --git a/source/stringcodec/codec.h b/source/stringcodec/codec.h index 1b89347..f53bae5 100644 --- a/source/stringcodec/codec.h +++ b/source/stringcodec/codec.h @@ -2,6 +2,7 @@ #define MSP_STRINGCODEC_CODEC_H_ #include +#include #include "except.h" #include "ustring.h" @@ -25,7 +26,7 @@ Unicode strings are represented as ustrings. An std::string is considered to be an encoded sequence of bytes. A codec is able to determine if an encoded string could be decoded with it. */ -class Codec +class MSPCORE_API Codec { public: /** @@ -36,14 +37,14 @@ public: may find it useful or necessary to implement some other functions too (particularly sync and reset for stateful codecs). */ - class Encoder + class MSPCORE_API Encoder { protected: - ErrorMode err_mode; + ErrorMode err_mode = THROW_ON_ERROR; Encoder(ErrorMode em): err_mode(em==DEFAULT ? THROW_ON_ERROR : em) { } public: - virtual ~Encoder() { } + virtual ~Encoder() = default; /** Encodes a single unicode character. If the character can't be represented in this encoding, error() should be called. */ @@ -87,14 +88,14 @@ public: Each codec class should contain an Decoder class derived from this. */ - class Decoder + class MSPCORE_API Decoder { protected: - ErrorMode err_mode; + ErrorMode err_mode = THROW_ON_ERROR; Decoder(ErrorMode em): err_mode(em==DEFAULT ? THROW_ON_ERROR : em) { } public: - virtual ~Decoder() { } + virtual ~Decoder() = default; /** Decodes a single character from a string. The iterator is advanced to the next character. For stateful codecs, -1 may be returned if a @@ -131,9 +132,9 @@ public: }; protected: - Codec() { } + Codec() = default; public: - virtual ~Codec() { } + virtual ~Codec() = default; /** Returns the name of the encoding handled by this codec. */ virtual const char *get_name() const = 0; @@ -162,7 +163,7 @@ template class StandardCodec: public Codec { private: - ErrorMode err_mode; + ErrorMode err_mode = THROW_ON_ERROR; protected: StandardCodec(ErrorMode em): err_mode(em==DEFAULT ? THROW_ON_ERROR : em) { } @@ -171,10 +172,10 @@ protected: { return (em==DEFAULT ? err_mode : em); } public: - virtual Encoder *create_encoder(ErrorMode em = DEFAULT) const + Encoder *create_encoder(ErrorMode em = DEFAULT) const override { return new typename C::Encoder(get_error_mode(em)); } - virtual Decoder *create_decoder(ErrorMode em = DEFAULT) const + Decoder *create_decoder(ErrorMode em = DEFAULT) const override { return new typename C::Decoder(get_error_mode(em)); } }; @@ -204,11 +205,11 @@ std::string transcode(const std::string &s) /** Creates a codec for an encoding by name. The caller is responsible for deleting the codec when it's no longer needed. */ -Codec *create_codec(const std::string &); +MSPCORE_API Codec *create_codec(const std::string &); /** Automatically detects the encoding of a string and creates a codec for it. The codec must be deleted when it's no longer needed. */ -Codec *detect_codec(const std::string &); +MSPCORE_API Codec *detect_codec(const std::string &); } // namespace StringCodec } // namespace Msp diff --git a/source/stringcodec/codecutils.h b/source/stringcodec/codecutils.h index 395949e..cf9eb2d 100644 --- a/source/stringcodec/codecutils.h +++ b/source/stringcodec/codecutils.h @@ -1,10 +1,12 @@ #ifndef MSP_STRINGCODEC_CODECUTILS_H_ #define MSP_STRINGCODEC_CODECUTILS_H_ +#include + namespace Msp { namespace StringCodec { -int transform_mapping_or_direct(const int *mapping, unsigned map_size, int ch, bool reverse); +MSPCORE_API int transform_mapping_or_direct(const int *mapping, unsigned map_size, int ch, bool reverse); } // namespace StringCodec } // namespace Msp diff --git a/source/stringcodec/except.h b/source/stringcodec/except.h index 6e25666..fc377e0 100644 --- a/source/stringcodec/except.h +++ b/source/stringcodec/except.h @@ -2,6 +2,7 @@ #define MSP_STRINGCODEC_EXCEPT_H_ #include +#include #include "ustring.h" namespace Msp { @@ -10,33 +11,30 @@ namespace StringCodec { /** Base class for codec errors. */ -class codec_error: public std::runtime_error +class MSPCORE_API codec_error: public std::runtime_error { public: codec_error(const std::string &w): std::runtime_error(w) { } - virtual ~codec_error() throw() { } }; /** Thrown when a codec can't encode the requested character. */ -class invalid_character: public codec_error +class MSPCORE_API invalid_character: public codec_error { public: invalid_character(unichar, const std::string &); - virtual ~invalid_character() throw() { } }; /** Thrown when a codec encounters a byte sequence it can't decode. */ -class invalid_sequence: public codec_error +class MSPCORE_API invalid_sequence: public codec_error { public: invalid_sequence(const std::string::const_iterator &, const std::string::const_iterator &, const std::string &); - virtual ~invalid_sequence() throw() { } private: std::string format_sequence(const std::string::const_iterator &, const std::string::const_iterator &); diff --git a/source/stringcodec/iso2022jp.cpp b/source/stringcodec/iso2022jp.cpp index 296c1ef..93c50f4 100644 --- a/source/stringcodec/iso2022jp.cpp +++ b/source/stringcodec/iso2022jp.cpp @@ -1,3 +1,4 @@ +#include #include "ascii.h" #include "iso2022jp.h" #include "jisx0201.h" @@ -80,7 +81,6 @@ void Iso2022Jp::Encoder::transliterate(unichar, string &buf) Iso2022Jp::Decoder::Decoder(ErrorMode em): Codec::Decoder(em), - mode(ASCII), dec(new Ascii::Decoder) { } @@ -123,7 +123,7 @@ unichar Iso2022Jp::Decoder::decode_char(const string &str, string::const_iterato else if(dec) return dec->decode_char(str, i); else - throw logic_error("no sub-decoder"); + throw internal_error("no sub-decoder"); if(result>=0) return result; diff --git a/source/stringcodec/iso2022jp.h b/source/stringcodec/iso2022jp.h index aa5c78b..0bb1ad3 100644 --- a/source/stringcodec/iso2022jp.h +++ b/source/stringcodec/iso2022jp.h @@ -1,12 +1,13 @@ #ifndef MSP_STRINGCODEC_ISO2022JP_H_ #define MSP_STRINGCODEC_ISO2022JP_H_ +#include #include "codec.h" namespace Msp { namespace StringCodec { -class Iso2022Jp: public StandardCodec +class MSPCORE_API Iso2022Jp: public StandardCodec { public: enum Mode @@ -16,40 +17,40 @@ public: JISX0208 }; - class Encoder: public Codec::Encoder + class MSPCORE_API Encoder: public Codec::Encoder { private: - Mode mode; + Mode mode = ASCII; public: - Encoder(ErrorMode em = DEFAULT): Codec::Encoder(em), mode(ASCII) { } + Encoder(ErrorMode em = DEFAULT): Codec::Encoder(em) { } - virtual void encode_char(unichar, std::string &); - virtual void sync(std::string &); - virtual void reset(); + void encode_char(unichar, std::string &) override; + void sync(std::string &) override; + void reset() override; private: void switch_mode(Mode, std::string &); - virtual void transliterate(unichar, std::string &); + void transliterate(unichar, std::string &) override; }; - class Decoder: public Codec::Decoder + class MSPCORE_API Decoder: public Codec::Decoder { private: - Mode mode; - Codec::Decoder *dec; + Mode mode = ASCII; + Codec::Decoder *dec = nullptr; public: Decoder(ErrorMode = DEFAULT); - virtual unichar decode_char(const std::string &, std::string::const_iterator &); - virtual void reset(); + unichar decode_char(const std::string &, std::string::const_iterator &) override; + void reset() override; private: void switch_mode(Mode); }; Iso2022Jp(ErrorMode em = DEFAULT): StandardCodec(em) { } - virtual const char *get_name() const { return "ISO-2022-JP"; } + const char *get_name() const override { return "ISO-2022-JP"; } }; } // namespace StringCodec diff --git a/source/stringcodec/iso646fi.h b/source/stringcodec/iso646fi.h index 2266c2c..3f1bb70 100644 --- a/source/stringcodec/iso646fi.h +++ b/source/stringcodec/iso646fi.h @@ -1,35 +1,36 @@ #ifndef MSP_STRINGCODEC_ISO646FI_H_ #define MSP_STRINGCODEC_ISO646FI_H_ +#include #include "codec.h" namespace Msp { namespace StringCodec { -class Iso646Fi: public StandardCodec +class MSPCORE_API Iso646Fi: public StandardCodec { public: - class Encoder: public Codec::Encoder + class MSPCORE_API Encoder: public Codec::Encoder { public: Encoder(ErrorMode em = DEFAULT): Codec::Encoder(em) { } - virtual void encode_char(unichar, std::string &); + void encode_char(unichar, std::string &) override; private: - virtual void transliterate(unichar, std::string &); + void transliterate(unichar, std::string &) override; }; - class Decoder: public Codec::Decoder + class MSPCORE_API Decoder: public Codec::Decoder { public: Decoder(ErrorMode em = DEFAULT): Codec::Decoder(em) { } - virtual unichar decode_char(const std::string &, std::string::const_iterator &); + unichar decode_char(const std::string &, std::string::const_iterator &) override; }; Iso646Fi(ErrorMode em = DEFAULT): StandardCodec(em) { } - virtual const char *get_name() const { return "ISO-646-FI"; } + const char *get_name() const override { return "ISO-646-FI"; } }; } // namespace StringCodec diff --git a/source/stringcodec/iso88591.h b/source/stringcodec/iso88591.h index 2b5a624..a6003ce 100644 --- a/source/stringcodec/iso88591.h +++ b/source/stringcodec/iso88591.h @@ -1,35 +1,36 @@ #ifndef MSP_STRINGCODEC_ISO88591_H_ #define MSP_STRINGCODEC_ISO88591_H_ +#include #include "codec.h" namespace Msp { namespace StringCodec { -class Iso88591: public StandardCodec +class MSPCORE_API Iso88591: public StandardCodec { public: - class Encoder: public Codec::Encoder + class MSPCORE_API Encoder: public Codec::Encoder { public: Encoder(ErrorMode em = DEFAULT): Codec::Encoder(em) { } - virtual void encode_char(unichar, std::string &); + void encode_char(unichar, std::string &) override; private: - virtual void transliterate(unichar, std::string &); + void transliterate(unichar, std::string &) override; }; - class Decoder: public Codec::Decoder + class MSPCORE_API Decoder: public Codec::Decoder { public: Decoder(ErrorMode em = DEFAULT): Codec::Decoder(em) { } - virtual unichar decode_char(const std::string &, std::string::const_iterator &); + unichar decode_char(const std::string &, std::string::const_iterator &) override; }; Iso88591(ErrorMode em = DEFAULT): StandardCodec(em) { } - virtual const char *get_name() const { return "ISO-8859-1"; } + const char *get_name() const override { return "ISO-8859-1"; } }; } // namespace StringCodec diff --git a/source/stringcodec/iso885915.h b/source/stringcodec/iso885915.h index ffb3c9a..2e81245 100644 --- a/source/stringcodec/iso885915.h +++ b/source/stringcodec/iso885915.h @@ -1,35 +1,36 @@ #ifndef MSP_STRINGCODEC_ISO885915_H_ #define MSP_STRINGCODEC_ISO885915_H_ +#include #include "codec.h" namespace Msp { namespace StringCodec { -class Iso885915: public StandardCodec +class MSPCORE_API Iso885915: public StandardCodec { public: - class Encoder: public Codec::Encoder + class MSPCORE_API Encoder: public Codec::Encoder { public: Encoder(ErrorMode em = DEFAULT): Codec::Encoder(em) { } - virtual void encode_char(unichar, std::string &); + void encode_char(unichar, std::string &) override; private: - virtual void transliterate(unichar, std::string &); + void transliterate(unichar, std::string &) override; }; - class Decoder: public Codec::Decoder + class MSPCORE_API Decoder: public Codec::Decoder { public: Decoder(ErrorMode em = DEFAULT): Codec::Decoder(em) { } - virtual unichar decode_char(const std::string &, std::string::const_iterator &); + unichar decode_char(const std::string &, std::string::const_iterator &) override; }; Iso885915(ErrorMode em = DEFAULT): StandardCodec(em) { } - virtual const char *get_name() const { return "ISO-8859-15"; } + const char *get_name() const override { return "ISO-8859-15"; } }; } // namespace StringCodec diff --git a/source/stringcodec/jisx0201.h b/source/stringcodec/jisx0201.h index 1e7c8ef..3194c78 100644 --- a/source/stringcodec/jisx0201.h +++ b/source/stringcodec/jisx0201.h @@ -1,35 +1,36 @@ #ifndef MSP_STRINGCODEC_JISX201_H_ #define MSP_STRINGCODEC_JISX201_H_ +#include #include "codec.h" namespace Msp { namespace StringCodec { -class JisX0201: public StandardCodec +class MSPCORE_API JisX0201: public StandardCodec { public: - class Encoder: public Codec::Encoder + class MSPCORE_API Encoder: public Codec::Encoder { public: Encoder(ErrorMode em = DEFAULT): Codec::Encoder(em) { } - virtual void encode_char(unichar, std::string &); + void encode_char(unichar, std::string &) override; private: - virtual void transliterate(unichar, std::string &); + void transliterate(unichar, std::string &) override; }; - class Decoder: public Codec::Decoder + class MSPCORE_API Decoder: public Codec::Decoder { public: Decoder(ErrorMode em = DEFAULT): Codec::Decoder(em) { } - virtual unichar decode_char(const std::string &, std::string::const_iterator &); + unichar decode_char(const std::string &, std::string::const_iterator &) override; }; JisX0201(ErrorMode em = DEFAULT): StandardCodec(em) { } - virtual const char *get_name() const { return "JIS X 0201"; } + const char *get_name() const override { return "JIS X 0201"; } }; } // namespace StringCodec diff --git a/source/stringcodec/jisx0208.cpp b/source/stringcodec/jisx0208.cpp index c097824..df28a37 100644 --- a/source/stringcodec/jisx0208.cpp +++ b/source/stringcodec/jisx0208.cpp @@ -9,12 +9,12 @@ namespace StringCodec { void JisX0208::Encoder::encode_char(unichar ucs, string &buf) { - unsigned short jis = ucs_to_jisx0208(ucs); + Kuten jis = ucs_to_jisx0208(ucs); if(jis) { char jbuf[2]; - jbuf[0] = jis>>8; - jbuf[1] = jis; + jbuf[0] = jis.ku+0x20; + jbuf[1] = jis.ten+0x20; buf.append(jbuf, 2); } else @@ -79,8 +79,8 @@ Kuten ucs_to_jisx0208(unichar c) Kuten result; if(ucs_to_jisx0208_table[i].ucs==static_cast(c)) { - result.ku = (ucs_to_jisx0208_table[i].jis>>8)+1; - result.ten = ucs_to_jisx0208_table[i].jis+1; + result.ku = (ucs_to_jisx0208_table[i].jis>>8); + result.ten = ucs_to_jisx0208_table[i].jis; } return result; diff --git a/source/stringcodec/jisx0208.h b/source/stringcodec/jisx0208.h index 293d277..0f29432 100644 --- a/source/stringcodec/jisx0208.h +++ b/source/stringcodec/jisx0208.h @@ -1,6 +1,7 @@ #ifndef MSP_STRINGCODEC_JISX0208_H_ #define MSP_STRINGCODEC_JISX0208_H_ +#include #include "codec.h" namespace Msp { @@ -11,45 +12,43 @@ Codec for the JIS X 0208 encoding. This is not particularly useful as a stand-alone codec, due to lack of a linefeed character among other things, but is included as part of some other encodings. */ -class JisX0208: public StandardCodec +class MSPCORE_API JisX0208: public StandardCodec { public: - class Encoder: public Codec::Encoder + class MSPCORE_API Encoder: public Codec::Encoder { public: Encoder(ErrorMode em = DEFAULT): Codec::Encoder(em) { } - virtual void encode_char(unichar, std::string &); + void encode_char(unichar, std::string &) override; private: - virtual void transliterate(unichar, std::string &); + void transliterate(unichar, std::string &) override; }; - class Decoder: public Codec::Decoder + class MSPCORE_API Decoder: public Codec::Decoder { public: Decoder(ErrorMode em = DEFAULT): Codec::Decoder(em) { } - virtual unichar decode_char(const std::string &, std::string::const_iterator &); + unichar decode_char(const std::string &, std::string::const_iterator &) override; }; JisX0208(ErrorMode em = DEFAULT): StandardCodec(em) { } - virtual const char *get_name() const { return "JIS X 0208"; } + const char *get_name() const override { return "JIS X 0208"; } }; struct Kuten { - unsigned short ku; - unsigned short ten; + unsigned short ku = 0; + unsigned short ten = 0; - Kuten(): ku(0), ten(0) { } - - operator bool() { return ku!=0 && ten!=0; } + explicit operator bool() { return ku!=0 && ten!=0; } }; -unichar jisx0208_to_ucs(Kuten); -Kuten ucs_to_jisx0208(unichar); +MSPCORE_API unichar jisx0208_to_ucs(Kuten); +MSPCORE_API Kuten ucs_to_jisx0208(unichar); } // namespace StringCodec } // namespace Msp diff --git a/source/stringcodec/utf16.cpp b/source/stringcodec/utf16.cpp index 13d49ad..f8ae093 100644 --- a/source/stringcodec/utf16.cpp +++ b/source/stringcodec/utf16.cpp @@ -7,8 +7,7 @@ namespace StringCodec { Utf16::Encoder::Encoder(ErrorMode em, Endian en): Codec::Encoder(em), - endian(en==AUTO ? BIG : en), - emit_bom(true) + endian(en==AUTO ? BIG : en) { } void Utf16::Encoder::encode_char(unichar ch, string &buf) diff --git a/source/stringcodec/utf16.h b/source/stringcodec/utf16.h index 7fecf1e..a588b12 100644 --- a/source/stringcodec/utf16.h +++ b/source/stringcodec/utf16.h @@ -1,6 +1,7 @@ #ifndef MSP_STRINGCODEC_UTF16_H_ #define MSP_STRINGCODEC_UTF16_H_ +#include #include "codec.h" namespace Msp { @@ -11,7 +12,7 @@ The UTF-16 codec, as specified in the Unicode standard. Both little and big endian are supported, as well as autodetection with the BOM. In the absence of a BOM, big endian is assumed. */ -class Utf16: public StandardCodec +class MSPCORE_API Utf16: public StandardCodec { public: enum Endian @@ -21,35 +22,35 @@ public: LITTLE }; - class Encoder: public Codec::Encoder + class MSPCORE_API Encoder: public Codec::Encoder { private: - Endian endian; - bool emit_bom; + Endian endian = BIG; + bool emit_bom = true; public: Encoder(ErrorMode em = DEFAULT, Endian en = BIG); - virtual void encode_char(unichar, std::string &); + void encode_char(unichar, std::string &) override; private: - virtual void transliterate(unichar, std::string &); + void transliterate(unichar, std::string &) override; }; - class Decoder: public Codec::Decoder + class MSPCORE_API Decoder: public Codec::Decoder { private: - Endian endian; + Endian endian = AUTO; public: Decoder(ErrorMode em = DEFAULT, Endian en = AUTO); - virtual unichar decode_char(const std::string &, std::string::const_iterator &); + unichar decode_char(const std::string &, std::string::const_iterator &) override; private: unichar decode_unit(const std::string &, const std::string::const_iterator &, std::string::const_iterator &); }; private: - Endian endian; + Endian endian = AUTO; public: Utf16(ErrorMode em = DEFAULT, Endian en = AUTO): @@ -57,13 +58,13 @@ public: endian(en) { } - virtual const char *get_name() const + const char *get_name() const override { return endian==BIG ? "UTF-16-BE" : endian==LITTLE ? "UTF-16-LE" : "UTF-16"; } - virtual Encoder *create_encoder(ErrorMode em = DEFAULT) const + Encoder *create_encoder(ErrorMode em = DEFAULT) const override { return new Encoder(get_error_mode(em), endian); } - virtual Decoder *create_decoder(ErrorMode em = DEFAULT) const + Decoder *create_decoder(ErrorMode em = DEFAULT) const override { return new Decoder(get_error_mode(em), endian); } }; diff --git a/source/stringcodec/utf8.h b/source/stringcodec/utf8.h index 94c627e..c3f4a59 100644 --- a/source/stringcodec/utf8.h +++ b/source/stringcodec/utf8.h @@ -1,35 +1,36 @@ #ifndef MSP_STRINGCODEC_UTF8_H_ #define MSP_STRINGCODEC_UTF8_H_ +#include #include "codec.h" namespace Msp { namespace StringCodec { -class Utf8: public StandardCodec +class MSPCORE_API Utf8: public StandardCodec { public: - class Encoder: public Codec::Encoder + class MSPCORE_API Encoder: public Codec::Encoder { public: Encoder(ErrorMode em = DEFAULT): Codec::Encoder(em) { } - virtual void encode_char(unichar, std::string &); + void encode_char(unichar, std::string &) override; private: - virtual void transliterate(unichar, std::string &); + void transliterate(unichar, std::string &) override; }; - class Decoder: public Codec::Decoder + class MSPCORE_API Decoder: public Codec::Decoder { public: Decoder(ErrorMode em = DEFAULT): Codec::Decoder(em) { } - virtual unichar decode_char(const std::string &, std::string::const_iterator &); + unichar decode_char(const std::string &, std::string::const_iterator &) override; }; Utf8(ErrorMode em = DEFAULT): StandardCodec(em) { } - virtual const char *get_name() const { return "UTF-8"; } + const char *get_name() const override { return "UTF-8"; } }; } // namespace StringCodec diff --git a/source/stringcodec/windows1252.h b/source/stringcodec/windows1252.h index c5d140f..b89fdae 100644 --- a/source/stringcodec/windows1252.h +++ b/source/stringcodec/windows1252.h @@ -1,35 +1,36 @@ #ifndef MSP_STRINGCODEC_WINDOWS1252_H_ #define MSP_STRINGCODEC_WINDOWS1252_H_ +#include #include "codec.h" namespace Msp { namespace StringCodec { -class Windows1252: public StandardCodec +class MSPCORE_API Windows1252: public StandardCodec { public: - class Encoder: public Codec::Encoder + class MSPCORE_API Encoder: public Codec::Encoder { public: Encoder(ErrorMode em = DEFAULT): Codec::Encoder(em) { } - virtual void encode_char(unichar, std::string &); + void encode_char(unichar, std::string &) override; private: - virtual void transliterate(unichar, std::string &); + void transliterate(unichar, std::string &) override; }; - class Decoder: public Codec::Decoder + class MSPCORE_API Decoder: public Codec::Decoder { public: Decoder(ErrorMode em = DEFAULT): Codec::Decoder(em) { } - virtual unichar decode_char(const std::string &, std::string::const_iterator &); + unichar decode_char(const std::string &, std::string::const_iterator &) override; }; Windows1252(ErrorMode em = DEFAULT): StandardCodec(em) { } - virtual const char *get_name() const { return "Windows-1252"; } + const char *get_name() const override { return "Windows-1252"; } }; } // namespace StringCodec diff --git a/source/strings/fmt.cpp b/source/strings/fmt.cpp index 07484dd..60703d8 100644 --- a/source/strings/fmt.cpp +++ b/source/strings/fmt.cpp @@ -91,19 +91,7 @@ void Fmt::parse(const char *s) Fmt &Fmt::reset() { - wd = 0; - prec = 6; - spos = false; - fillc = ' '; - base = DEC; - sbase = false; - fmode = AUTOFLT; - spoint = false; - align = RIGHT; - ucase = false; - type = STR; - - return *this; + return *this = Fmt(); } void Fmt::apply(ostream &out) const diff --git a/source/strings/fmt.h b/source/strings/fmt.h index ee84911..88b297d 100644 --- a/source/strings/fmt.h +++ b/source/strings/fmt.h @@ -4,14 +4,14 @@ #include #include #include +#include namespace Msp { -class format_error: public std::logic_error +class MSPCORE_API format_error: public std::logic_error { public: format_error(const std::string &w): std::logic_error(w) { } - virtual ~format_error() throw() { } }; @@ -35,7 +35,7 @@ Some new conversions are supported: b/B Binary integer conversion P Uppercase pointer conversion (like %#X) */ -class Fmt +class MSPCORE_API Fmt { public: enum Type @@ -68,22 +68,22 @@ public: }; private: - unsigned wd; - unsigned prec; - bool spos; - wchar_t fillc; - Base base; - bool sbase; - FloatMode fmode; - bool spoint; - Align align; - bool ucase; - Type type; + unsigned wd = 0; + unsigned prec = 6; + bool spos = false; + wchar_t fillc = ' '; + Base base = DEC; + bool sbase = false; + FloatMode fmode = AUTOFLT; + bool spoint = false; + Align align = RIGHT; + bool ucase = false; + Type type = STR; public: - Fmt() { reset(); } - Fmt(const char *f) { reset(); parse(f); } - Fmt(const std::string &f) { reset(); parse(f.c_str()); } + Fmt() = default; + Fmt(const char *f) { parse(f); } + Fmt(const std::string &f) { parse(f.c_str()); } private: void parse(const char *); diff --git a/source/strings/format.cpp b/source/strings/format.cpp index d2065e9..42926e1 100644 --- a/source/strings/format.cpp +++ b/source/strings/format.cpp @@ -19,6 +19,9 @@ Formatter::Formatter(const Formatter &other): Formatter &Formatter::operator=(const Formatter &other) { + if(&other==this) + return *this; + fmt = other.fmt; pos = fmt.begin()+(other.pos-other.fmt.begin()); result = other.result; diff --git a/source/strings/format.h b/source/strings/format.h index 49c40e9..7969ef3 100644 --- a/source/strings/format.h +++ b/source/strings/format.h @@ -2,6 +2,7 @@ #define MSP_STRINGS_FORMAT_H_ #include +#include #include "lexicalcast.h" namespace Msp { @@ -9,7 +10,7 @@ namespace Msp { /** Printf-like string formatter class. */ -class Formatter +class MSPCORE_API Formatter { private: std::string fmt; diff --git a/source/strings/glob.h b/source/strings/glob.h index a58d0b1..5ae5f55 100644 --- a/source/strings/glob.h +++ b/source/strings/glob.h @@ -2,11 +2,12 @@ #define MSP_STRINGS_GLOB_H_ #include +#include namespace Msp { -bool globmatch(const std::string &, const std::string &); -bool globcasematch(const std::string &, const std::string &); +MSPCORE_API bool globmatch(const std::string &, const std::string &); +MSPCORE_API bool globcasematch(const std::string &, const std::string &); } // namespace Msp diff --git a/source/strings/lexicalcast.cpp b/source/strings/lexicalcast.cpp index 2c867b2..5e9159c 100644 --- a/source/strings/lexicalcast.cpp +++ b/source/strings/lexicalcast.cpp @@ -1,6 +1,6 @@ #include +#include #include -#include #include "format.h" #include "lexicalcast.h" @@ -530,13 +530,11 @@ void operator<<(LexicalConverter &c, unsigned v) void operator<<(LexicalConverter &c, unsigned long v) { c.result(int_to_str(v, c.get_fmt())); } -#ifdef __GNUC__ void operator<<(LexicalConverter &c, long long v) { c.result(int_to_str(v, c.get_fmt())); } void operator<<(LexicalConverter &c, unsigned long long v) { c.result(int_to_str(v, c.get_fmt())); } -#endif void operator<<(LexicalConverter &c, bool v) { c.result(bool_to_str(v, c.get_fmt())); } @@ -557,7 +555,7 @@ void operator<<(LexicalConverter &c, const char *s) { c.result(str_to_str(s, c.get_fmt())); } void operator<<(LexicalConverter &c, const void *p) -{ c.result(int_to_str(reinterpret_cast(p), c.get_fmt())); } +{ c.result(int_to_str(reinterpret_cast(p), c.get_fmt())); } /*** operator>> ***/ @@ -601,13 +599,11 @@ void operator>>(const LexicalConverter &c, unsigned int &v) void operator>>(const LexicalConverter &c, unsigned long &v) { v = str_to_int(c.get(), c.get_fmt()); } -#ifdef __GNUC__ void operator>>(const LexicalConverter &c, long long &v) { v = str_to_int(c.get(), c.get_fmt()); } void operator>>(const LexicalConverter &c, unsigned long long &v) { v = str_to_int(c.get(), c.get_fmt()); } -#endif void operator>>(const LexicalConverter &c, bool &v) { v = str_to_bool(c.get()); } diff --git a/source/strings/lexicalcast.h b/source/strings/lexicalcast.h index 4f54a85..ccb7790 100644 --- a/source/strings/lexicalcast.h +++ b/source/strings/lexicalcast.h @@ -5,6 +5,7 @@ #include #include #include +#include #include "fmt.h" namespace Msp { @@ -12,37 +13,35 @@ namespace Msp { /** Thrown for errors in lexical conversions. */ -class lexical_error: public std::runtime_error +class MSPCORE_API lexical_error: public std::runtime_error { public: lexical_error(const std::string &w): runtime_error(w) { } - virtual ~lexical_error() throw() { } }; /** Thrown when the format is unsuitable for the type being converted. */ -class format_mismatch: public lexical_error +class MSPCORE_API format_mismatch: public lexical_error { public: format_mismatch(const std::string &w): lexical_error(w) { } - virtual ~format_mismatch() throw() { } }; /** Helper class for lexical_cast to facilitate operator overloading. */ -class LexicalConverter +class MSPCORE_API LexicalConverter { private: Fmt fmt; - bool filled; + bool filled = false; std::string buf; public: - LexicalConverter(const Fmt &f): fmt(f), filled(false) { } + LexicalConverter(const Fmt &f): fmt(f) { } LexicalConverter(const std::string &s, const Fmt &f): fmt(f), filled(true), buf(s) { } const Fmt &get_fmt() const { return fmt; } @@ -51,45 +50,41 @@ public: }; -void operator<<(LexicalConverter &, char); -void operator<<(LexicalConverter &, signed char); -void operator<<(LexicalConverter &, short); -void operator<<(LexicalConverter &, int); -void operator<<(LexicalConverter &, long); -void operator<<(LexicalConverter &, unsigned char); -void operator<<(LexicalConverter &, unsigned short); -void operator<<(LexicalConverter &, unsigned); -void operator<<(LexicalConverter &, unsigned long); -#ifdef __GNUC__ -void operator<<(LexicalConverter &, long long); -void operator<<(LexicalConverter &, unsigned long long); -#endif -void operator<<(LexicalConverter &, bool); -void operator<<(LexicalConverter &, float); -void operator<<(LexicalConverter &, double); -void operator<<(LexicalConverter &, long double); -void operator<<(LexicalConverter &, const std::string &); -void operator<<(LexicalConverter &, const char *); -void operator<<(LexicalConverter &, const void *); - -void operator>>(const LexicalConverter &, char &); -void operator>>(const LexicalConverter &, signed char &); -void operator>>(const LexicalConverter &, short &); -void operator>>(const LexicalConverter &, int &); -void operator>>(const LexicalConverter &, long &); -void operator>>(const LexicalConverter &, unsigned char &); -void operator>>(const LexicalConverter &, unsigned short &); -void operator>>(const LexicalConverter &, unsigned int &); -void operator>>(const LexicalConverter &, unsigned long &); -#ifdef __GNUC__ -void operator>>(const LexicalConverter &, long long &); -void operator>>(const LexicalConverter &, unsigned long long &); -#endif -void operator>>(const LexicalConverter &, bool &); -void operator>>(const LexicalConverter &, float &); -void operator>>(const LexicalConverter &, double &); -void operator>>(const LexicalConverter &, long double &); -void operator>>(const LexicalConverter &, std::string &); +MSPCORE_API void operator<<(LexicalConverter &, char); +MSPCORE_API void operator<<(LexicalConverter &, signed char); +MSPCORE_API void operator<<(LexicalConverter &, short); +MSPCORE_API void operator<<(LexicalConverter &, int); +MSPCORE_API void operator<<(LexicalConverter &, long); +MSPCORE_API void operator<<(LexicalConverter &, unsigned char); +MSPCORE_API void operator<<(LexicalConverter &, unsigned short); +MSPCORE_API void operator<<(LexicalConverter &, unsigned); +MSPCORE_API void operator<<(LexicalConverter &, unsigned long); +MSPCORE_API void operator<<(LexicalConverter &, long long); +MSPCORE_API void operator<<(LexicalConverter &, unsigned long long); +MSPCORE_API void operator<<(LexicalConverter &, bool); +MSPCORE_API void operator<<(LexicalConverter &, float); +MSPCORE_API void operator<<(LexicalConverter &, double); +MSPCORE_API void operator<<(LexicalConverter &, long double); +MSPCORE_API void operator<<(LexicalConverter &, const std::string &); +MSPCORE_API void operator<<(LexicalConverter &, const char *); +MSPCORE_API void operator<<(LexicalConverter &, const void *); + +MSPCORE_API void operator>>(const LexicalConverter &, char &); +MSPCORE_API void operator>>(const LexicalConverter &, signed char &); +MSPCORE_API void operator>>(const LexicalConverter &, short &); +MSPCORE_API void operator>>(const LexicalConverter &, int &); +MSPCORE_API void operator>>(const LexicalConverter &, long &); +MSPCORE_API void operator>>(const LexicalConverter &, unsigned char &); +MSPCORE_API void operator>>(const LexicalConverter &, unsigned short &); +MSPCORE_API void operator>>(const LexicalConverter &, unsigned int &); +MSPCORE_API void operator>>(const LexicalConverter &, unsigned long &); +MSPCORE_API void operator>>(const LexicalConverter &, long long &); +MSPCORE_API void operator>>(const LexicalConverter &, unsigned long long &); +MSPCORE_API void operator>>(const LexicalConverter &, bool &); +MSPCORE_API void operator>>(const LexicalConverter &, float &); +MSPCORE_API void operator>>(const LexicalConverter &, double &); +MSPCORE_API void operator>>(const LexicalConverter &, long double &); +MSPCORE_API void operator>>(const LexicalConverter &, std::string &); // Generic operators using stringstream diff --git a/source/strings/regex.cpp b/source/strings/regex.cpp index c624056..5307c69 100644 --- a/source/strings/regex.cpp +++ b/source/strings/regex.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include "format.h" #include "regex.h" @@ -56,7 +57,6 @@ string bad_regex::make_where(const string &e, const string::const_iterator &i) Regex::Regex(const string &expr) { - n_groups = 0; auto iter = expr.begin(); code = compile(expr, iter, n_groups, false); ++n_groups; @@ -478,7 +478,7 @@ bool Regex::run(const string &str, const string::const_iterator &begin, vector #include +#include #include "regmatch.h" namespace Msp { -class bad_regex: public std::logic_error +class MSPCORE_API bad_regex: public std::logic_error { public: bad_regex(const std::string &, const std::string &, const std::string::const_iterator &); - virtual ~bad_regex() throw() { } private: std::string make_where(const std::string &, const std::string::const_iterator &); @@ -70,7 +70,7 @@ a bitmask. The MATCH_ANY instruction consumes the input character and always succeeds. */ -class Regex +class MSPCORE_API Regex { private: typedef std::basic_string Code; @@ -107,7 +107,7 @@ private: }; Code code; - unsigned n_groups; + unsigned n_groups = 0; public: /** Constructs a new Regex object from a string representation. */ diff --git a/source/strings/regmatch.h b/source/strings/regmatch.h index b79104b..8d4406a 100644 --- a/source/strings/regmatch.h +++ b/source/strings/regmatch.h @@ -3,6 +3,7 @@ #include #include +#include namespace Msp { @@ -16,7 +17,7 @@ part matched by the whole regex. Further groups, if present, indicate parts matched by subregexes. These are ordered from left to right, by the opening parenthesis of the subregex. */ -class RegMatch +class MSPCORE_API RegMatch { public: /** @@ -26,14 +27,13 @@ public: { typedef std::string::size_type size_type; - bool match; //< Whether or not this group matched - size_type begin; //< First offset of the match - size_type end; //< One-past-last offset - size_type length; //< Length of the match (end-begin) - std::string str; //< The part of the string that matched + bool match = false; //< Whether or not this group matched + size_type begin; //< First offset of the match + size_type end; //< One-past-last offset + size_type length; //< Length of the match (end-begin) + std::string str; //< The part of the string that matched - Group(): match(false) { } - operator bool() const { return match; } + explicit operator bool() const { return match; } }; private: @@ -41,7 +41,7 @@ private: public: /** Constructs a RegMatch representing a non-match. */ - RegMatch() { } + RegMatch() = default; /** Constructs a new RegMatch from a string and groups. The length and str members of each group are computed and need not be set. Intended to be used @@ -66,7 +66,7 @@ public: /** Shorthand for the group() function. */ const Group &operator[](unsigned i) const { return group(i); } - operator bool() const { return !empty(); } + explicit operator bool() const { return !empty(); } }; } // namespace Msp diff --git a/source/strings/utils.cpp b/source/strings/utils.cpp index eb2142d..748d717 100644 --- a/source/strings/utils.cpp +++ b/source/strings/utils.cpp @@ -258,7 +258,7 @@ string c_escape(const string &str, bool escape_8bit) result += "\\\'"; else if(c=='\\') result += "\\\\"; - else if(static_cast(c)<' ' || (escape_8bit && (c&0x80))) + else if(static_cast(c)<' ' || c==0x7F || (escape_8bit && (c&0x80))) { char buf[4] = { '\\', 0 }; for(unsigned j=0; j<3; ++j) diff --git a/source/strings/utils.h b/source/strings/utils.h index f7e9433..28763e6 100644 --- a/source/strings/utils.h +++ b/source/strings/utils.h @@ -3,6 +3,7 @@ #include #include +#include namespace Msp { @@ -10,22 +11,22 @@ namespace Msp { than, equal to or greater than zero depending on whether the first string lexicographically precedes, is equal to or follows the second one, respectively. */ -int strcasecmp(const std::string &s1, const std::string &s2); +MSPCORE_API int strcasecmp(const std::string &s1, const std::string &s2); /** Converts a string to lower case. */ -std::string tolower(const std::string &); +MSPCORE_API std::string tolower(const std::string &); /** Converts a string to upper case. */ -std::string toupper(const std::string &); +MSPCORE_API std::string toupper(const std::string &); /** Checks whether a string consists of digits only. */ -bool isnumrc(const std::string &); +MSPCORE_API bool isnumrc(const std::string &); /** Checks whether a string consists of alphabetic characters only. */ -bool isalpha(const std::string &); +MSPCORE_API bool isalpha(const std::string &); /** Checks whether a string consists of alphanumeric characters only. */ -bool isalnum(const std::string &); +MSPCORE_API bool isalnum(const std::string &); /* These are required to make the standard version work from inside the Msp namespace */ @@ -40,27 +41,27 @@ be treated as a single separator. If max_split is non-negative, at most that many split will be performed, i.e. the resulting vector will contain at most max_split+1 elements. */ -std::vector split(const std::string &str, const std::string &sep = " \t\r\n", int max_split = -1); +MSPCORE_API std::vector split(const std::string &str, const std::string &sep = " \t\r\n", int max_split = -1); /** Splits a string on occurrences of a single character. */ -std::vector split(const std::string &str, char sep, int max_split = -1); +MSPCORE_API std::vector split(const std::string &str, char sep, int max_split = -1); /** Splits a string on occurrences of another string. */ -std::vector split_long(const std::string &str, const std::string &sep, int max_split = -1); +MSPCORE_API std::vector split_long(const std::string &str, const std::string &sep, int max_split = -1); /** Splits a string on occurrences of another string. Two consecutive separators will cause an empty string to be placed in the result. */ -std::vector split_fields(const std::string &str, const std::string &sep, int max_split = -1); +MSPCORE_API std::vector split_fields(const std::string &str, const std::string &sep, int max_split = -1); /** Splits a string on occurrences of a single character. Two consecutive separators will cause an empty string to be placed in the result. */ -std::vector split_fields(const std::string &str, char sep, int max_split = -1); +MSPCORE_API std::vector split_fields(const std::string &str, char sep, int max_split = -1); /** Appends a string to another, using a separator if both are non-empty. */ -std::string &append(std::string &str, const std::string &sep, const std::string &other); +MSPCORE_API std::string &append(std::string &str, const std::string &sep, const std::string &other); /** Joins two strings, using a separator if both are non-empty. */ -std::string join(const std::string &str1, const std::string &sep, const std::string &str2); +MSPCORE_API std::string join(const std::string &str1, const std::string &sep, const std::string &str2); /** Concatenates strings from an iterator range. */ template @@ -74,14 +75,14 @@ std::string join(Iter begin, Iter end, const std::string &sep = " ") } /** Strips leading and trailing whitespace from a string. */ -std::string strip(const std::string &); +MSPCORE_API std::string strip(const std::string &); /** Unescapes a string with C escape sequences. */ -std::string c_unescape(const std::string &str); +MSPCORE_API std::string c_unescape(const std::string &str); /** Escapes any non-printable characters in a string with C escape sequences. Optionally, any characters with the high bit set can be escaped as well. */ -std::string c_escape(const std::string &str, bool escape_8bit = true); +MSPCORE_API std::string c_escape(const std::string &str, bool escape_8bit = true); } // namespace Msp diff --git a/source/time/datetime.cpp b/source/time/datetime.cpp index e1abcf7..e011f3b 100644 --- a/source/time/datetime.cpp +++ b/source/time/datetime.cpp @@ -29,7 +29,7 @@ inline unsigned char month_days(int y, unsigned char m) } template -inline int cmp_(T a, T b) +inline int _cmp(T a, T b) { if(a=1000000) throw out_of_range("DateTime::DateTime usec"); if(second>=60) @@ -251,19 +231,19 @@ DateTime &DateTime::operator-=(const TimeDelta &td) int DateTime::cmp(const DateTime &dt) const { - if(int c = cmp_(year, dt.year)) + if(int c = _cmp(year, dt.year)) return c; - if(int c = cmp_(month, dt.month)) + if(int c = _cmp(month, dt.month)) return c; - if(int c = cmp_(mday, dt.mday)) + if(int c = _cmp(mday, dt.mday)) return c; - if(int c = cmp_(hour, dt.hour)) + if(int c = _cmp(hour, dt.hour)) return c; - if(int c = cmp_(minute, dt.minute)) + if(int c = _cmp(minute, dt.minute)) return c; - if(int c = cmp_(second, dt.second)) + if(int c = _cmp(second, dt.second)) return c; - if(int c = cmp_(usec, dt.usec)) + if(int c = _cmp(usec, dt.usec)) return c; return 0; } diff --git a/source/time/datetime.h b/source/time/datetime.h index b7f578c..2336374 100644 --- a/source/time/datetime.h +++ b/source/time/datetime.h @@ -2,6 +2,7 @@ #define MSP_TIME_DATETIME_H_ #include +#include #include "timezone.h" #include "rawtime.h" @@ -20,16 +21,16 @@ Due to the complex internal representation, arithmetic operations on a DateTime are relatively slow. For purposes of internal scheduling in a program, a TimeStamp is a better choice. */ -class DateTime +class MSPCORE_API DateTime { private: - int year; - unsigned char month; - unsigned char mday; - unsigned char hour; - unsigned char minute; - unsigned char second; - unsigned usec; + int year = 1970; + unsigned char month = 1; + unsigned char mday = 1; + unsigned char hour = 0; + unsigned char minute = 0; + unsigned char second = 0; + unsigned usec = 0; TimeZone zone; public: @@ -38,11 +39,7 @@ public: DateTime(int, unsigned char, unsigned char); DateTime(int, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char); DateTime(int, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned); -private: - void init(const TimeStamp &); - void init(int, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned); -public: static DateTime parse_rfc3339(const std::string &); int get_year() const { return year; } diff --git a/source/time/rawtime.h b/source/time/rawtime.h index 1af7956..46b3e4d 100644 --- a/source/time/rawtime.h +++ b/source/time/rawtime.h @@ -1,12 +1,12 @@ #ifndef MSP_TIME_RAWTIME_H_ #define MSP_TIME_RAWTIME_H_ -#include +#include namespace Msp { namespace Time { -typedef Int64 RawTime; +typedef std::int64_t RawTime; } // namespace Time } // namespace Msp diff --git a/source/time/timedelta.cpp b/source/time/timedelta.cpp index a56e0fe..5b381da 100644 --- a/source/time/timedelta.cpp +++ b/source/time/timedelta.cpp @@ -75,14 +75,5 @@ void operator<<(LexicalConverter &conv, const TimeDelta &td) conv.result(result); } -const TimeDelta zero(0); -const TimeDelta usec(1); -const TimeDelta msec(1000); -const TimeDelta sec(1000000); -const TimeDelta min(60*1000000); -const TimeDelta hour(3600*1000000LL); -const TimeDelta day(86400*1000000LL); -const TimeDelta week(7*86400*1000000LL); - } // namespace Time } // namespace Msp diff --git a/source/time/timedelta.h b/source/time/timedelta.h index 2ce6eeb..2ff4bdd 100644 --- a/source/time/timedelta.h +++ b/source/time/timedelta.h @@ -3,6 +3,7 @@ #include #include +#include #include #include "rawtime.h" @@ -12,18 +13,18 @@ namespace Time { /** Represents a quantity of time, such as five seconds. */ -class TimeDelta +class MSPCORE_API TimeDelta { private: - RawTime usec; + RawTime usec = 0; public: /** Constructs a zero TimeDelta. */ - TimeDelta(): usec(0) { } + constexpr TimeDelta() = default; /** Constructs a TimeDelta from a plain number. The purpose of this is to allow serialization together with the raw() function. */ - explicit TimeDelta(RawTime u): usec(u) { } + explicit constexpr TimeDelta(RawTime u): usec(u) { } /** Returns the raw number stored inside the TimeDelta. This should only be used for serialization and the result should not be interpreted in any way. */ @@ -54,24 +55,24 @@ public: bool operator==(const TimeDelta &t) const { return usec==t.usec; } bool operator!=(const TimeDelta &t) const { return usec!=t.usec; } - operator const void *() const { return usec ? this : 0; } + explicit operator bool() const { return usec; } }; template inline TimeDelta operator*(T a, const TimeDelta &t) { return t*a; } -void operator<<(LexicalConverter &, const TimeDelta &); +MSPCORE_API void operator<<(LexicalConverter &, const TimeDelta &); // Constants to be used in creation of TimeDeltas -extern const TimeDelta zero; -extern const TimeDelta usec; -extern const TimeDelta msec; -extern const TimeDelta sec; -extern const TimeDelta min; -extern const TimeDelta hour; -extern const TimeDelta day; -extern const TimeDelta week; +constexpr TimeDelta zero(0); +constexpr TimeDelta usec(1); +constexpr TimeDelta msec(1000); +constexpr TimeDelta sec(1000000); +constexpr TimeDelta min(60*1000000); +constexpr TimeDelta hour(3600*1000000LL); +constexpr TimeDelta day(86400*1000000LL); +constexpr TimeDelta week(7*86400*1000000LL); inline TimeDelta abs(const TimeDelta &t) { return t>=zero ? t : -t; } using std::abs; diff --git a/source/time/timer.cpp b/source/time/timer.cpp index 9411fac..eda782e 100644 --- a/source/time/timer.cpp +++ b/source/time/timer.cpp @@ -9,8 +9,7 @@ namespace Msp { namespace Time { Timer::Timer(): - sem(1), - blocking(false) + sem(1) { } Timer::~Timer() @@ -23,7 +22,7 @@ Timer::Slot &Timer::add(const TimeDelta &td) { Slot *s = new Slot(td); MutexLock l(mutex); - slots.push_back(s); + slots.push_back({ s }); push_heap(slots.begin(), slots.end()); if(blocking) sem.signal(); @@ -34,7 +33,7 @@ Timer::Slot &Timer::add(const TimeStamp &ts) { Slot *s = new Slot(ts); MutexLock l(mutex); - slots.push_back(s); + slots.push_back({ s }); push_heap(slots.begin(), slots.end()); if(blocking) sem.signal(); @@ -72,7 +71,7 @@ void Timer::do_tick(const TimeDelta &timeout) if(timeout>=zero) deadline = now()+timeout; - Slot *next = 0; + Slot *next = nullptr; { MutexLock l(mutex); while(1) @@ -114,7 +113,7 @@ void Timer::do_tick(const TimeDelta &timeout) if(next->signal_timeout.emit() && next->increment()) { MutexLock l(mutex); - slots.push_back(next); + slots.push_back({ next }); push_heap(slots.begin(), slots.end()); } else @@ -153,10 +152,6 @@ bool Timer::Slot::increment() } -Timer::SlotProxy::SlotProxy(Slot *s): - slot(s) -{ } - bool Timer::SlotProxy::operator<(const SlotProxy &sp) const { return slot->get_timeout()>sp.slot->get_timeout(); diff --git a/source/time/timer.h b/source/time/timer.h index 8bd4d07..7cb5c76 100644 --- a/source/time/timer.h +++ b/source/time/timer.h @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -19,7 +20,7 @@ of the returned slot. This class is thread-safe, to allow running timers in a separate thread. */ -class Timer: private NonCopyable +class MSPCORE_API Timer: private NonCopyable { public: class Slot @@ -43,14 +44,13 @@ private: { Slot *slot; - SlotProxy(Slot *); bool operator<(const SlotProxy &) const; }; std::vector slots; Semaphore sem; Mutex mutex; - bool blocking; + bool blocking = false; public: Timer(); diff --git a/source/time/timestamp.h b/source/time/timestamp.h index 1317b26..5081305 100644 --- a/source/time/timestamp.h +++ b/source/time/timestamp.h @@ -1,6 +1,7 @@ #ifndef MSP_TIME_TIMESTAMP_H_ #define MSP_TIME_TIMESTAMP_H_ +#include #include "timedelta.h" #include "rawtime.h" @@ -13,15 +14,15 @@ function. For representing user-specified times, use the DateTime class. */ -class TimeStamp +class MSPCORE_API TimeStamp { private: - RawTime usec; + RawTime usec = 0; public: /** Construct a TimeStamp that represents an arbitarily distant point in the past. It's guaranteed to be less than any valid timestamp. */ - TimeStamp(): usec(0) { } + TimeStamp() = default; /** Constructs a TimeStamp from a plain number. The purpose of this is to allow serialization together with the raw() function. */ @@ -46,7 +47,7 @@ public: bool operator==(const TimeStamp &t) const { return usec==t.usec; } bool operator!=(const TimeStamp &t) const { return usec!=t.usec; } - operator const void *() const { return usec>0 ? this : 0; } + explicit operator bool() const { return usec>0; } static TimeStamp from_unixtime(time_t t) { return TimeStamp(t*1000000LL); } }; diff --git a/source/time/timezone.h b/source/time/timezone.h index 3fbeb54..83b4b58 100644 --- a/source/time/timezone.h +++ b/source/time/timezone.h @@ -1,12 +1,13 @@ #ifndef MSP_TIME_TIMEZONE_H_ #define MSP_TIME_TIMEZONE_H_ +#include #include "timedelta.h" namespace Msp { namespace Time { -class TimeZone +class MSPCORE_API TimeZone { private: std::string name; diff --git a/source/time/unix/utils.cpp b/source/time/unix/utils.cpp index 029c75b..f25f61c 100644 --- a/source/time/unix/utils.cpp +++ b/source/time/unix/utils.cpp @@ -13,7 +13,7 @@ namespace Time { TimeStamp now() { timeval tv; - gettimeofday(&tv, 0); + gettimeofday(&tv, nullptr); return TimeStamp(timeval_to_rawtime(tv)); } @@ -27,7 +27,7 @@ TimeDelta get_cpu_time() void sleep(const TimeDelta &d) { timespec ts = rawtime_to_timespec(d.raw()); - while(nanosleep(&ts, 0)==-1) + while(nanosleep(&ts, nullptr)==-1) if(errno!=EINTR) throw system_error("nanosleep"); } diff --git a/source/time/utils.h b/source/time/utils.h index 00b6ef8..dd325b0 100644 --- a/source/time/utils.h +++ b/source/time/utils.h @@ -2,6 +2,7 @@ #define MSP_TIME_UTILS_H_ #include +#include namespace Msp { namespace Time { @@ -10,15 +11,15 @@ class TimeDelta; class TimeStamp; /** Returns the current timestamp. */ -TimeStamp now(); +MSPCORE_API TimeStamp now(); -std::string format_now(const std::string &); +MSPCORE_API std::string format_now(const std::string &); /** Returns the CPU time used by the program so far. */ -TimeDelta get_cpu_time(); +MSPCORE_API TimeDelta get_cpu_time(); /** Sleeps for the given duration. */ -void sleep(const TimeDelta &); +MSPCORE_API void sleep(const TimeDelta &); } // namespace Time } // namespace Msp diff --git a/source/time/windows/rawtime_platform.h b/source/time/windows/rawtime_platform.h index 60a9a59..bd57889 100644 --- a/source/time/windows/rawtime_platform.h +++ b/source/time/windows/rawtime_platform.h @@ -1,7 +1,7 @@ #ifndef MSP_TIME_RAWTIME_PLATFORM_H_ #define MSP_TIME_RAWTIME_PLATFORM_H_ -#include +#include #include "rawtime.h" namespace Msp { diff --git a/source/time/windows/timezone.cpp b/source/time/windows/timezone.cpp index 570c679..1b52644 100644 --- a/source/time/windows/timezone.cpp +++ b/source/time/windows/timezone.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include "timezone.h" diff --git a/source/time/windows/utils.cpp b/source/time/windows/utils.cpp index 2150a10..4d295a9 100644 --- a/source/time/windows/utils.cpp +++ b/source/time/windows/utils.cpp @@ -1,4 +1,4 @@ -#include +#include #include "rawtime_private.h" #include "timedelta.h" #include "timestamp.h" diff --git a/tests/.gitignore b/tests/.gitignore new file mode 100644 index 0000000..c551524 --- /dev/null +++ b/tests/.gitignore @@ -0,0 +1,4 @@ +/consoletest +/consoletest.* +/test +/test.* diff --git a/tests/path.cpp b/tests/path.cpp index fbb5ff5..d52630a 100644 --- a/tests/path.cpp +++ b/tests/path.cpp @@ -52,6 +52,8 @@ void PathTests::normalization() EXPECT_EQUAL(path.str(), "./foo"); path = "foo/.."; EXPECT_EQUAL(path.str(), "."); + path = "/foo/.."; + EXPECT_EQUAL(path.str(), "/"); path = "//foo"; EXPECT_EQUAL(path.str(), "/foo"); path = "/.."; diff --git a/tests/variant.cpp b/tests/variant.cpp index 99cacdf..8ec8972 100644 --- a/tests/variant.cpp +++ b/tests/variant.cpp @@ -99,11 +99,11 @@ void VariantTests::destruction() void VariantTests::types() { Variant var = 42U; - EXPECT(!var.check_type()); - EXPECT(var.check_type()); - EXPECT(!var.check_type()); - EXPECT(!var.check_type()); - EXPECT(!var.check_type()); + EXPECT(!var.has_type()); + EXPECT(var.has_type()); + EXPECT(!var.has_type()); + EXPECT(!var.has_type()); + EXPECT(!var.has_type()); } void VariantTests::mismatch()