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=85ef592fb1eab68283b12607701e4fb9b9014630 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/source/core/algorithm.h b/source/core/algorithm.h index 51c2369..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,33 +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/main.cpp b/source/core/android/main.cpp index ff811c1..d6ad415 100644 --- a/source/core/android/main.cpp +++ b/source/core/android/main.cpp @@ -1,6 +1,7 @@ #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 = nullptr; if(thread) diff --git a/source/core/application.cpp b/source/core/application.cpp index 8447eed..c214a06 100644 --- a/source/core/application.cpp +++ b/source/core/application.cpp @@ -9,6 +9,7 @@ #include #include #include "application.h" +#include "except.h" #include "getopt.h" using namespace std; @@ -24,7 +25,7 @@ void *Application::_data = nullptr; Application::Application(const string &n) { if(_app) - throw logic_error("instance already exists"); + throw already_called("Application::Application"); if(!n.empty()) _name = n; @@ -94,7 +95,7 @@ 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"); + throw already_called("Application::set_startup_info"); static FS::Path exe; @@ -117,6 +118,21 @@ void Application::set_startup_info(const char *argv0, void *data) _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() { done = false; @@ -146,7 +162,7 @@ void Application::_sighandler(int s) Application::Starter::Starter() { if(_starter) - throw logic_error("Can't create more than one Starter instance"); + throw already_called("Application::Starter::Starter"); _starter = this; } diff --git a/source/core/application.h b/source/core/application.h index 972f3b7..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,10 +11,10 @@ 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(); @@ -53,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 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.h b/source/core/getopt.h index 575184f..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 m_help; public: usage_error(const std::string &w, const std::string &h = std::string()): std::runtime_error(w), m_help(h) { } - ~usage_error() throw() override = default; - const char *help() const throw() { return m_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,7 +69,7 @@ public: REQUIRED_ARG }; - class Option + class MSPCORE_API Option { protected: Option() = default; @@ -89,7 +89,7 @@ public: virtual unsigned get_seen_count() const = 0; }; - class Argument + class MSPCORE_API Argument { protected: Argument() = default; diff --git a/source/core/maputils.h b/source/core/maputils.h index 26b72cc..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 diff --git a/source/core/module.h b/source/core/module.h index 4b1e3e8..64d761f 100644 --- a/source/core/module.h +++ b/source/core/module.h @@ -2,11 +2,12 @@ #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; 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 6582074..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,7 +11,7 @@ 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; @@ -38,7 +39,7 @@ public: /** Locks the mutex for the lifetime of the object. */ -class MutexLock +class MSPCORE_API MutexLock { private: Mutex &mutex; 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 4bb81c8..55d4a30 100644 --- a/source/core/osx/main.cpp +++ b/source/core/osx/main.cpp @@ -1,7 +1,8 @@ #include #include "application.h" +#include "mspcore_api.h" -int main(int argc, char **argv) +MSPCORE_API int main(int argc, char **argv) { void *data = nullptr; diff --git a/source/core/process.cpp b/source/core/process.cpp index 43b7384..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" @@ -78,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 0d7faa6..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; diff --git a/source/core/refptr.h b/source/core/refptr.h index 79401dc..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 diff --git a/source/core/semaphore.h b/source/core/semaphore.h index 28c3b3d..f504289 100644 --- a/source/core/semaphore.h +++ b/source/core/semaphore.h @@ -2,11 +2,12 @@ #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; diff --git a/source/core/systemerror.h b/source/core/systemerror.h index c2387fa..cce3c5c 100644 --- a/source/core/systemerror.h +++ b/source/core/systemerror.h @@ -3,10 +3,11 @@ #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 m_code; @@ -14,9 +15,8 @@ private: public: system_error(const std::string &, int = -1); system_error(const std::string &, const std::string &); - ~system_error() throw() override = default; - int code() const throw() { return m_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 e860d67..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" @@ -39,7 +39,7 @@ void Thread::kill() void Thread::launch() { if(_state>=RUNNING) - throw logic_error("already launched"); + throw already_called("Thread::launch"); platform_launch(); _state = RUNNING; @@ -51,7 +51,7 @@ ThreadReturn THREAD_CALL Thread::Private::main_wrapper(void *arg) thread->platform_setname(); thread->main(); thread->_state = FINISHED; - return nullptr; + return 0; } } // namespace Msp diff --git a/source/core/thread.h b/source/core/thread.h index ef071cd..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; 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/unix/main.cpp b/source/core/unix/main.cpp index 58c9fda..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, nullptr); } diff --git a/source/core/unix/process.cpp b/source/core/unix/process.cpp index 7370b70..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) { @@ -70,7 +73,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"); int status; int pid = waitpid(priv->info.pid, &status, (block ? 0 : WNOHANG)); diff --git a/source/core/variant.h b/source/core/variant.h index af204f2..5cb1b93 100644 --- a/source/core/variant.h +++ b/source/core/variant.h @@ -5,122 +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() override = default; }; -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; + + const Functions *funcs = nullptr; + alignas(void *) char storage[INTERNAL_SIZE]; + +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(); } - Store(const T &d): data(d) { } + template> + Variant &operator=(T &&v) { assign(std::forward(v)); return *this; } - const std::type_info &type_id() const override { return typeid(T); } - StoreBase *clone() const override { return new Store(data); } - bool type_equals(const StoreBase &s) const override { return dynamic_cast *>(&s); } - bool value_equals(const StoreBase &s) const override { return _value_equals(s); } + 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; } - 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); } + void clear(); - template - typename std::enable_if::value, bool>::type _value_equals(const StoreBase &) const - { return false; } - }; +private: + template + void assign(T &&); + + void copy_from(const Variant &); + void move_from(Variant &&); - StoreBase *store = nullptr; + template + T &get(); public: - Variant() = default; template - Variant(const T &v): store(new Store::type>(v)) { } - Variant(const Variant &v): store(v.store ? v.store->clone() : nullptr) { } - ~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) - { - if(&v==this) - 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)); } - delete store; - store = (v.store ? v.store->clone() : nullptr); - return *this; - } + 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); - } + static EnableSmall create(char *s, T &&v) + { new(s) typename std::remove_reference::type(std::forward(v)); } + + 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)); } - bool check_same_type(const Variant &v) const - { return store && v.store && store->type_equals(*v.store); } + 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 3bd03fa..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,6 +44,7 @@ Process::~Process() { CloseHandle(priv->info.hProcess); CloseHandle(priv->info.hThread); + delete priv; } void Process::platform_get_self_info(Private &priv) @@ -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) 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 93aa7bd..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" diff --git a/source/core/windows/thread.cpp b/source/core/windows/thread.cpp index 8890a70..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" 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 98aa4d8..b8e06af 100644 --- a/source/debug/backtrace.h +++ b/source/debug/backtrace.h @@ -4,11 +4,12 @@ #include #include #include +#include namespace Msp { namespace Debug { -class Backtrace +class MSPCORE_API Backtrace { public: struct StackFrame @@ -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.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 edfa002..6591c03 100644 --- a/source/debug/errorreporter.cpp +++ b/source/debug/errorreporter.cpp @@ -16,5 +16,10 @@ ErrorReporter::~ErrorReporter() _current = _prev; } +const ErrorReporter *ErrorReporter::get_current() +{ + return _current; +} + } // namespace Debug } // namespace Msp diff --git a/source/debug/errorreporter.h b/source/debug/errorreporter.h index 9a60f85..b702b7c 100644 --- a/source/debug/errorreporter.h +++ b/source/debug/errorreporter.h @@ -2,12 +2,13 @@ #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 = nullptr; @@ -19,7 +20,7 @@ protected: 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.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.h b/source/debug/profiler.h index 22d2c9a..7d98dc7 100644 --- a/source/debug/profiler.h +++ b/source/debug/profiler.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -25,16 +26,16 @@ 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 = 0; diff --git a/source/debug/profilingscope.h b/source/debug/profilingscope.h index 586efa3..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,7 +14,7 @@ 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; 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 bef89c6..960be2e 100644 --- a/source/fs/dir.h +++ b/source/fs/dir.h @@ -4,12 +4,13 @@ #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 &); @@ -17,50 +18,50 @@ public: }; /// 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 5ab3f49..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" @@ -19,7 +20,7 @@ FileMonitor::~FileMonitor() void FileMonitor::use_event_dispatcher(IO::EventDispatcher &ed) { if(event_disp) - throw logic_error("event_disp!=nullptr"); + throw already_called("FileMonitor::use_event_dispatcher"); event_disp = &ed; platform_use_event_dispatcher(); diff --git a/source/fs/filemonitor.h b/source/fs/filemonitor.h index 220b969..3ce5d79 100644 --- a/source/fs/filemonitor.h +++ b/source/fs/filemonitor.h @@ -1,6 +1,7 @@ #ifndef FILEMONITOR_H_ #define FILEMONITOR_H_ +#include #include #include #include @@ -8,7 +9,7 @@ namespace Msp { namespace FS { -class FileMonitor: NonCopyable +class MSPCORE_API FileMonitor: NonCopyable { private: struct Private; 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 0e86600..1181b92 100644 --- a/source/fs/path.cpp +++ b/source/fs/path.cpp @@ -133,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 30fe683..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; 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.h b/source/fs/stat.h index c32e879..fd6a2f7 100644 --- a/source/fs/stat.h +++ b/source/fs/stat.h @@ -3,6 +3,7 @@ #include #include +#include #include #include "path.h" @@ -22,7 +23,7 @@ typedef uint64_t FileSize; /** Holds file information. */ -class Stat +class MSPCORE_API Stat { private: struct Private; @@ -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/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/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 fde0200..2ba2f1e 100644 --- a/source/fs/windows/dir.cpp +++ b/source/fs/windows/dir.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/source/fs/windows/dir_location.cpp b/source/fs/windows/dir_location.cpp index 4f9b8f6..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; @@ -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"); char datadir[MAX_PATH]; if(SHGetFolderPath(nullptr, CSIDL_LOCAL_APPDATA, nullptr, 0, datadir)==S_OK) 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/stat.cpp b/source/fs/windows/stat.cpp index 8331e60..ee79476 100644 --- a/source/fs/windows/stat.cpp +++ b/source/fs/windows/stat.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/source/fs/windows/stat_platform.h b/source/fs/windows/stat_platform.h index 6440aca..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 { 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/asset.cpp b/source/io/asset.cpp index 9284f97..d605ff4 100644 --- a/source/io/asset.cpp +++ b/source/io/asset.cpp @@ -1,3 +1,4 @@ +#include #include "asset.h" using namespace std; @@ -7,12 +8,12 @@ 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"); } size_t Asset::do_write(const char *, size_t) @@ -22,7 +23,7 @@ size_t Asset::do_write(const char *, size_t) 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 84c2837..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,7 +12,7 @@ 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; diff --git a/source/io/base.h b/source/io/base.h index aadc6ac..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 diff --git a/source/io/buffered.cpp b/source/io/buffered.cpp index 638e4ec..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" @@ -33,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() @@ -179,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 f078ea1..c05fc25 100644 --- a/source/io/buffered.h +++ b/source/io/buffered.h @@ -2,12 +2,13 @@ #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; @@ -32,8 +33,8 @@ protected: public: std::size_t put(char) override; - bool getline(std::string &); - int get(); + bool getline(std::string &) override; + int get() override; const Handle &get_handle(Mode) override; 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 ac66288..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 @@ -64,9 +65,10 @@ public: 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.h b/source/io/eventobject.h index cf987e4..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 diff --git a/source/io/eventreader.h b/source/io/eventreader.h index c4ae56b..11091ab 100644 --- a/source/io/eventreader.h +++ b/source/io/eventreader.h @@ -28,14 +28,14 @@ private: 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 f23cc93..2af56ae 100644 --- a/source/io/file.h +++ b/source/io/file.h @@ -3,6 +3,7 @@ #include #include +#include #include "buffered.h" #include "handle.h" #include "seekable.h" @@ -10,18 +11,16 @@ 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() override = default; }; -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() override = default; }; @@ -30,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 @@ -82,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; diff --git a/source/io/handle.h b/source/io/handle.h index 6140e11..06c2034 100644 --- a/source/io/handle.h +++ b/source/io/handle.h @@ -2,11 +2,12 @@ #define MSP_IO_HANDLE_H_ #include +#include namespace Msp { namespace IO { -class Handle +class MSPCORE_API Handle { public: struct Private; diff --git a/source/io/memory.cpp b/source/io/memory.cpp index 0b2d8f4..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,22 +9,34 @@ using namespace std; namespace Msp { namespace IO { -Memory::Memory(char *b, char *e, Mode m) +Memory::Memory(char *d, std::size_t s, Mode m): + Memory(d, d+s, m) +{ } + +Memory::Memory(char *b, char *e, Mode m): + begin(b), + end(e), + pos(begin) { - begin = b; - end = e; - pos = begin; mode = m; } +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): + 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) @@ -94,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 75cf7f5..e009cfd 100644 --- a/source/io/memory.h +++ b/source/io/memory.h @@ -1,12 +1,13 @@ #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 = nullptr; @@ -14,10 +15,10 @@ private: char *pos = nullptr; public: - Memory(char *d, std::size_t s, Mode m = M_RDWR): Memory(d, d+s, m) { } + Memory(char *d, std::size_t s, Mode m = M_RDWR); Memory(char *, char *, Mode = M_RDWR); - Memory(const char *d, std::size_t s): Memory(const_cast(d), const_cast(d+s), M_READ) { } - Memory(const char *b, const char *e): Memory(const_cast(b), const_cast(e), M_READ) { } + Memory(const char *d, std::size_t s); + Memory(const char *b, const char *e); void set_block(bool) override; void set_inherit(bool) override; diff --git a/source/io/mode.h b/source/io/mode.h index 565eb0f..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() override = default; }; } // namespace IO diff --git a/source/io/pipe.h b/source/io/pipe.h index df5353a..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; diff --git a/source/io/poll.cpp b/source/io/poll.cpp index 4f9b24f..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" @@ -44,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; } @@ -91,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 c873923..53e3808 100644 --- a/source/io/poll.h +++ b/source/io/poll.h @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -31,15 +32,13 @@ 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 = nullptr; - PollEvent events = P_NONE; - - PolledObject(EventObject *o, PollEvent e): object(o), events(e) { } + EventObject *object; + PollEvent events; }; private: @@ -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 84a5561..e549d24 100644 --- a/source/io/seekable.h +++ b/source/io/seekable.h @@ -3,6 +3,7 @@ #include #include +#include #include "base.h" namespace Msp { @@ -20,7 +21,7 @@ enum SeekType }; -class bad_seek: public std::runtime_error +class MSPCORE_API bad_seek: public std::runtime_error { public: bad_seek(SeekOffset, SeekType); @@ -28,7 +29,7 @@ public: }; -class Seekable: public Base +class MSPCORE_API Seekable: public Base { protected: Seekable() = default; diff --git a/source/io/serial.h b/source/io/serial.h index a07cd1f..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 diff --git a/source/io/slice.cpp b/source/io/slice.cpp index 535deae..9ca5966 100644 --- a/source/io/slice.cpp +++ b/source/io/slice.cpp @@ -1,4 +1,4 @@ -#include +#include #include "slice.h" using namespace std; @@ -12,7 +12,7 @@ Slice::Slice(Seekable &b, SeekOffset s, SeekOffset l): 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; @@ -21,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() @@ -108,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 2965f98..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,7 +17,7 @@ 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; diff --git a/source/io/unix/eventreader.cpp b/source/io/unix/eventreader.cpp index afb1463..b87a347 100644 --- a/source/io/unix/eventreader.cpp +++ b/source/io/unix/eventreader.cpp @@ -3,7 +3,7 @@ namespace Msp { namespace IO { -EventReader::EventReader(Handle &h, unsigned): +EventReader::EventReader(Handle &h, size_t): handle(h) { } @@ -21,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/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/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.h b/source/io/utils.h index f73383d..4507f5c 100644 --- a/source/io/utils.h +++ b/source/io/utils.h @@ -2,6 +2,7 @@ #define MSP_IO_UTILS_H_ #include +#include namespace Msp { namespace IO { @@ -14,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. */ -std::size_t read_all(Base &, char *, std::size_t); +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 4a0640f..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" @@ -22,7 +22,7 @@ struct EventReader::Private }; -EventReader::EventReader(Handle &h, unsigned size): +EventReader::EventReader(Handle &h, size_t size): handle(h), priv(new Private) { @@ -92,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/handle.cpp b/source/io/windows/handle.cpp index 6d1219a..e72282a 100644 --- a/source/io/windows/handle.cpp +++ b/source/io/windows/handle.cpp @@ -20,7 +20,7 @@ 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, nullptr)==0) @@ -32,7 +32,7 @@ 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, nullptr)==0) 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/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 ec778ae..62a000f 100644 --- a/source/io/windows/poll_platform.h +++ b/source/io/windows/poll_platform.h @@ -1,7 +1,7 @@ #ifndef MSP_IO_POLL_PLATFORM_H_ #define MSP_IO_POLL_PLATFORM_H_ -#include +#include #include #include "poll.h" 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 bd086dd..d041c87 100644 --- a/source/io/windows/serial.cpp +++ b/source/io/windows/serial.cpp @@ -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 fba71eb..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; @@ -73,7 +74,7 @@ ZlibCompressed::ZlibCompressed(Base &b, Mode m, unsigned level): (void)buffer_size; (void)stream_end; (void)level; - throw zlib_error("unsupported", -1); + throw unsupported("ZlibCompressed"); #endif } @@ -96,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() @@ -261,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 eb35f6c..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 m_code; public: zlib_error(const std::string &, int); - ~zlib_error() throw() override = default; - int code() const throw() { return m_code; } + int code() const noexcept { return m_code; } }; /** @@ -28,7 +28,7 @@ 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; diff --git a/source/stringcodec/ascii.h b/source/stringcodec/ascii.h index bb5d0ee..755edeb 100644 --- a/source/stringcodec/ascii.h +++ b/source/stringcodec/ascii.h @@ -1,15 +1,16 @@ #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) { } @@ -19,7 +20,7 @@ public: 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) { } 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 5e67d46..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,7 +37,7 @@ 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 = THROW_ON_ERROR; @@ -87,7 +88,7 @@ public: Each codec class should contain an Decoder class derived from this. */ - class Decoder + class MSPCORE_API Decoder { protected: ErrorMode err_mode = THROW_ON_ERROR; @@ -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 0c7b690..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) { } - ~codec_error() throw() override = default; }; /** 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 &); - ~invalid_character() throw() override = default; }; /** 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 &); - ~invalid_sequence() throw() override = default; 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 3332922..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" @@ -122,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 a9bc1c2..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,7 +17,7 @@ public: JISX0208 }; - class Encoder: public Codec::Encoder + class MSPCORE_API Encoder: public Codec::Encoder { private: Mode mode = ASCII; @@ -32,7 +33,7 @@ public: void transliterate(unichar, std::string &) override; }; - class Decoder: public Codec::Decoder + class MSPCORE_API Decoder: public Codec::Decoder { private: Mode mode = ASCII; diff --git a/source/stringcodec/iso646fi.h b/source/stringcodec/iso646fi.h index fdb3d60..3f1bb70 100644 --- a/source/stringcodec/iso646fi.h +++ b/source/stringcodec/iso646fi.h @@ -1,15 +1,16 @@ #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) { } @@ -19,7 +20,7 @@ public: 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) { } diff --git a/source/stringcodec/iso88591.h b/source/stringcodec/iso88591.h index a8ba809..a6003ce 100644 --- a/source/stringcodec/iso88591.h +++ b/source/stringcodec/iso88591.h @@ -1,15 +1,16 @@ #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) { } @@ -19,7 +20,7 @@ public: 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) { } diff --git a/source/stringcodec/iso885915.h b/source/stringcodec/iso885915.h index 3791d05..2e81245 100644 --- a/source/stringcodec/iso885915.h +++ b/source/stringcodec/iso885915.h @@ -1,15 +1,16 @@ #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) { } @@ -19,7 +20,7 @@ public: 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) { } diff --git a/source/stringcodec/jisx0201.h b/source/stringcodec/jisx0201.h index 5cbda03..3194c78 100644 --- a/source/stringcodec/jisx0201.h +++ b/source/stringcodec/jisx0201.h @@ -1,15 +1,16 @@ #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) { } @@ -19,7 +20,7 @@ public: 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) { } diff --git a/source/stringcodec/jisx0208.h b/source/stringcodec/jisx0208.h index b0c03b2..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,10 +12,10 @@ 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) { } @@ -24,7 +25,7 @@ public: 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) { } @@ -46,8 +47,8 @@ struct Kuten 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.h b/source/stringcodec/utf16.h index 73d81cb..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,7 +22,7 @@ public: LITTLE }; - class Encoder: public Codec::Encoder + class MSPCORE_API Encoder: public Codec::Encoder { private: Endian endian = BIG; @@ -35,7 +36,7 @@ public: void transliterate(unichar, std::string &) override; }; - class Decoder: public Codec::Decoder + class MSPCORE_API Decoder: public Codec::Decoder { private: Endian endian = AUTO; diff --git a/source/stringcodec/utf8.h b/source/stringcodec/utf8.h index f170916..c3f4a59 100644 --- a/source/stringcodec/utf8.h +++ b/source/stringcodec/utf8.h @@ -1,15 +1,16 @@ #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) { } @@ -19,7 +20,7 @@ public: 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) { } diff --git a/source/stringcodec/windows1252.h b/source/stringcodec/windows1252.h index bcea69b..b89fdae 100644 --- a/source/stringcodec/windows1252.h +++ b/source/stringcodec/windows1252.h @@ -1,15 +1,16 @@ #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) { } @@ -19,7 +20,7 @@ public: 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) { } diff --git a/source/strings/fmt.h b/source/strings/fmt.h index 45ae917..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) { } - ~format_error() throw() override = default; }; @@ -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 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 2b84d9b..5e9159c 100644 --- a/source/strings/lexicalcast.cpp +++ b/source/strings/lexicalcast.cpp @@ -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())); } @@ -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 393622d..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,29 +13,27 @@ 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) { } - ~lexical_error() throw() override = default; }; /** 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) { } - ~format_mismatch() throw() override = default; }; /** Helper class for lexical_cast to facilitate operator overloading. */ -class LexicalConverter +class MSPCORE_API LexicalConverter { private: Fmt 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 915d335..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" @@ -477,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 &); - ~bad_regex() throw() override = default; 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; diff --git a/source/strings/regmatch.h b/source/strings/regmatch.h index 6af309e..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: /** 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.h b/source/time/datetime.h index a5d91cf..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,7 +21,7 @@ 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 = 1970; 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 1a4274b..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 = 0; public: /** Constructs a zero TimeDelta. */ - TimeDelta() = default; + 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. */ @@ -60,18 +61,18 @@ public: 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 04c3074..eda782e 100644 --- a/source/time/timer.cpp +++ b/source/time/timer.cpp @@ -22,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(); @@ -33,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(); @@ -113,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 @@ -152,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 3325731..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 @@ -41,9 +42,8 @@ public: private: struct SlotProxy { - Slot *slot = nullptr; + Slot *slot; - SlotProxy(Slot *); bool operator<(const SlotProxy &) const; }; diff --git a/source/time/timestamp.h b/source/time/timestamp.h index 8068510..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,7 +14,7 @@ function. For representing user-specified times, use the DateTime class. */ -class TimeStamp +class MSPCORE_API TimeStamp { private: RawTime usec = 0; 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/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()