added iOS source code
[wl-app.git] / iOS / Pods / Realm / include / core / realm / util / logger.hpp
diff --git a/iOS/Pods/Realm/include/core/realm/util/logger.hpp b/iOS/Pods/Realm/include/core/realm/util/logger.hpp
new file mode 100644 (file)
index 0000000..0946208
--- /dev/null
@@ -0,0 +1,511 @@
+/*************************************************************************
+ *
+ * Copyright 2016 Realm Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************/
+
+#ifndef REALM_UTIL_LOGGER_HPP
+#define REALM_UTIL_LOGGER_HPP
+
+#include <cstring>
+#include <utility>
+#include <string>
+#include <locale>
+#include <sstream>
+#include <iostream>
+
+#include <realm/util/features.h>
+#include <realm/util/thread.hpp>
+#include <realm/util/file.hpp>
+
+namespace realm {
+namespace util {
+
+
+/// All Logger objects store a reference to a LevelThreshold object which it
+/// uses to efficiently query about the current log level threshold
+/// (`level_threshold.get()`). All messages logged with a level that is lower
+/// than the current threshold will be dropped. For the sake of efficiency, this
+/// test happens before the message is formatted.
+///
+/// A logger is not inherently thread-safe, but specific implementations can be
+/// (see ThreadSafeLogger). For a logger to be thread-safe, the implementation
+/// of do_log() must be thread-safe and the referenced LevelThreshold object
+/// must have a thread-safe get() method.
+///
+/// Examples:
+///
+///    logger.error("Overlong message from master coordinator");
+///    logger.info("Listening for peers on %1:%2", listen_address, listen_port);
+class Logger {
+public:
+    template <class... Params>
+    void trace(const char* message, Params&&...);
+    template <class... Params>
+    void debug(const char* message, Params&&...);
+    template <class... Params>
+    void detail(const char* message, Params&&...);
+    template <class... Params>
+    void info(const char* message, Params&&...);
+    template <class... Params>
+    void warn(const char* message, Params&&...);
+    template <class... Params>
+    void error(const char* message, Params&&...);
+    template <class... Params>
+    void fatal(const char* message, Params&&...);
+
+    /// Specifies criticality when passed to log(). Functions as a criticality
+    /// threshold when returned from LevelThreshold::get().
+    ///
+    ///     error   Be silent unless when there is an error.
+    ///     warn    Be silent unless when there is an error or a warning.
+    ///     info    Reveal information about what is going on, but in a
+    ///             minimalistic fashion to avoid general overhead from logging
+    ///             and to keep volume down.
+    ///     detail  Same as 'info', but prioritize completeness over minimalism.
+    ///     debug   Reveal information that can aid debugging, no longer paying
+    ///             attention to efficiency.
+    ///     trace   A version of 'debug' that allows for very high volume
+    ///             output.
+    enum class Level { all, trace, debug, detail, info, warn, error, fatal, off };
+
+    template <class... Params>
+    void log(Level, const char* message, Params&&...);
+
+    /// Shorthand for `int(level) >= int(level_threshold.get())`.
+    bool would_log(Level level) const noexcept;
+
+    class LevelThreshold;
+
+    const LevelThreshold& level_threshold;
+
+    virtual ~Logger() noexcept;
+
+protected:
+    Logger(const LevelThreshold&) noexcept;
+
+    static void do_log(Logger&, Level, std::string message);
+
+    virtual void do_log(Level, std::string message) = 0;
+
+    static const char* get_level_prefix(Level) noexcept;
+
+private:
+    struct State;
+
+    template <class... Params>
+    REALM_NOINLINE void do_log(Level, const char* message, Params&&...);
+    void log_impl(State&);
+    template <class Param, class... Params>
+    void log_impl(State&, Param&&, Params&&...);
+    template <class Param>
+    static void subst(State&, Param&&);
+};
+
+template <class C, class T>
+std::basic_ostream<C, T>& operator<<(std::basic_ostream<C, T>&, Logger::Level);
+
+template <class C, class T>
+std::basic_istream<C, T>& operator>>(std::basic_istream<C, T>&, Logger::Level&);
+
+class Logger::LevelThreshold {
+public:
+    virtual Level get() const noexcept = 0;
+};
+
+
+/// A root logger that is not thread-safe and allows for the log level threshold
+/// to be changed over time. The initial log level threshold is
+/// Logger::Level::info.
+class RootLogger : private Logger::LevelThreshold, public Logger {
+public:
+    void set_level_threshold(Level) noexcept;
+
+protected:
+    RootLogger();
+
+private:
+    Level m_level_threshold = Level::info;
+    Level get() const noexcept override final;
+};
+
+
+/// A logger that writes to STDERR. This logger is not thread-safe.
+///
+/// Since this class is a RootLogger, it contains modifiable a log level
+/// threshold.
+class StderrLogger : public RootLogger {
+protected:
+    void do_log(Level, std::string) override final;
+};
+
+
+/// A logger that writes to a stream. This logger is not thread-safe.
+///
+/// Since this class is a RootLogger, it contains modifiable a log level
+/// threshold.
+class StreamLogger : public RootLogger {
+public:
+    explicit StreamLogger(std::ostream&) noexcept;
+
+protected:
+    void do_log(Level, std::string) override final;
+
+private:
+    std::ostream& m_out;
+};
+
+
+/// A logger that writes to a file. This logger is not thread-safe.
+///
+/// Since this class is a RootLogger, it contains modifiable a log level
+/// threshold.
+class FileLogger : public StreamLogger {
+public:
+    explicit FileLogger(std::string path);
+    explicit FileLogger(util::File);
+
+private:
+    util::File m_file;
+    util::File::Streambuf m_streambuf;
+    std::ostream m_out;
+};
+
+
+/// A thread-safe logger. This logger ignores the level threshold of the base
+/// logger. Instead, it introduces new a LevelThreshold object with a fixed
+/// value to achieve thread safety.
+class ThreadSafeLogger : private Logger::LevelThreshold, public Logger {
+public:
+    explicit ThreadSafeLogger(Logger& base_logger, Level = Level::info);
+
+protected:
+    void do_log(Level, std::string) override final;
+
+private:
+    const Level m_level_threshold; // Immutable for thread safety
+    Logger& m_base_logger;
+    Mutex m_mutex;
+    Level get() const noexcept override final;
+};
+
+
+/// A logger that adds a fixed prefix to each message. This logger inherits the
+/// LevelThreshold object of the specified base logger. This logger is
+/// thread-safe if, and only if the base logger is thread-safe.
+class PrefixLogger : public Logger {
+public:
+    PrefixLogger(std::string prefix, Logger& base_logger) noexcept;
+
+protected:
+    void do_log(Level, std::string) override final;
+
+private:
+    const std::string m_prefix;
+    Logger& m_base_logger;
+};
+
+
+// Implementation
+
+struct Logger::State {
+    Logger::Level m_level;
+    std::string m_message;
+    std::string m_search;
+    int m_param_num = 1;
+    std::ostringstream m_formatter;
+    std::locale m_locale = std::locale::classic();
+    State(Logger::Level level, const char* s)
+        : m_level(level)
+        , m_message(s)
+        , m_search(m_message)
+    {
+        m_formatter.imbue(m_locale);
+    }
+};
+
+template <class... Params>
+inline void Logger::trace(const char* message, Params&&... params)
+{
+    log(Level::trace, message, std::forward<Params>(params)...); // Throws
+}
+
+template <class... Params>
+inline void Logger::debug(const char* message, Params&&... params)
+{
+    log(Level::debug, message, std::forward<Params>(params)...); // Throws
+}
+
+template <class... Params>
+inline void Logger::detail(const char* message, Params&&... params)
+{
+    log(Level::detail, message, std::forward<Params>(params)...); // Throws
+}
+
+template <class... Params>
+inline void Logger::info(const char* message, Params&&... params)
+{
+    log(Level::info, message, std::forward<Params>(params)...); // Throws
+}
+
+template <class... Params>
+inline void Logger::warn(const char* message, Params&&... params)
+{
+    log(Level::warn, message, std::forward<Params>(params)...); // Throws
+}
+
+template <class... Params>
+inline void Logger::error(const char* message, Params&&... params)
+{
+    log(Level::error, message, std::forward<Params>(params)...); // Throws
+}
+
+template <class... Params>
+inline void Logger::fatal(const char* message, Params&&... params)
+{
+    log(Level::fatal, message, std::forward<Params>(params)...); // Throws
+}
+
+template <class... Params>
+inline void Logger::log(Level level, const char* message, Params&&... params)
+{
+    if (would_log(level))
+        do_log(level, message, std::forward<Params>(params)...); // Throws
+}
+
+inline bool Logger::would_log(Level level) const noexcept
+{
+    return int(level) >= int(level_threshold.get());
+}
+
+inline Logger::~Logger() noexcept
+{
+}
+
+inline Logger::Logger(const LevelThreshold& lt) noexcept
+    : level_threshold(lt)
+{
+}
+
+inline void Logger::do_log(Logger& logger, Level level, std::string message)
+{
+    logger.do_log(level, std::move(message)); // Throws
+}
+
+template <class... Params>
+void Logger::do_log(Level level, const char* message, Params&&... params)
+{
+    State state(level, message);
+    log_impl(state, std::forward<Params>(params)...); // Throws
+}
+
+inline void Logger::log_impl(State& state)
+{
+    do_log(state.m_level, std::move(state.m_message)); // Throws
+}
+
+template <class Param, class... Params>
+inline void Logger::log_impl(State& state, Param&& param, Params&&... params)
+{
+    subst(state, std::forward<Param>(param));         // Throws
+    log_impl(state, std::forward<Params>(params)...); // Throws
+}
+
+template <class Param>
+void Logger::subst(State& state, Param&& param)
+{
+    state.m_formatter << "%" << state.m_param_num;
+    std::string key = state.m_formatter.str();
+    state.m_formatter.str(std::string());
+    std::string::size_type j = state.m_search.find(key);
+    if (j != std::string::npos) {
+        state.m_formatter << std::forward<Param>(param);
+        std::string str = state.m_formatter.str();
+        state.m_formatter.str(std::string());
+        state.m_message.replace(j, key.size(), str);
+        state.m_search.replace(j, key.size(), std::string(str.size(), '\0'));
+    }
+    ++state.m_param_num;
+}
+
+template <class C, class T>
+std::basic_ostream<C, T>& operator<<(std::basic_ostream<C, T>& out, Logger::Level level)
+{
+    switch (level) {
+        case Logger::Level::all:
+            out << "all";
+            return out;
+        case Logger::Level::trace:
+            out << "trace";
+            return out;
+        case Logger::Level::debug:
+            out << "debug";
+            return out;
+        case Logger::Level::detail:
+            out << "detail";
+            return out;
+        case Logger::Level::info:
+            out << "info";
+            return out;
+        case Logger::Level::warn:
+            out << "warn";
+            return out;
+        case Logger::Level::error:
+            out << "error";
+            return out;
+        case Logger::Level::fatal:
+            out << "fatal";
+            return out;
+        case Logger::Level::off:
+            out << "off";
+            return out;
+    }
+    REALM_ASSERT(false);
+    return out;
+}
+
+template <class C, class T>
+std::basic_istream<C, T>& operator>>(std::basic_istream<C, T>& in, Logger::Level& level)
+{
+    std::basic_string<C, T> str;
+    auto check = [&](const char* name) {
+        size_t n = strlen(name);
+        if (n != str.size())
+            return false;
+        for (size_t i = 0; i < n; ++i) {
+            if (in.widen(name[i]) != str[i])
+                return false;
+        }
+        return true;
+    };
+    if (in >> str) {
+        if (check("all")) {
+            level = Logger::Level::all;
+        }
+        else if (check("trace")) {
+            level = Logger::Level::trace;
+        }
+        else if (check("debug")) {
+            level = Logger::Level::debug;
+        }
+        else if (check("detail")) {
+            level = Logger::Level::detail;
+        }
+        else if (check("info")) {
+            level = Logger::Level::info;
+        }
+        else if (check("warn")) {
+            level = Logger::Level::warn;
+        }
+        else if (check("error")) {
+            level = Logger::Level::error;
+        }
+        else if (check("fatal")) {
+            level = Logger::Level::fatal;
+        }
+        else if (check("off")) {
+            level = Logger::Level::off;
+        }
+        else {
+            in.setstate(std::ios_base::failbit);
+        }
+    }
+    return in;
+}
+
+inline void RootLogger::set_level_threshold(Level new_level_threshold) noexcept
+{
+    m_level_threshold = new_level_threshold;
+}
+
+inline RootLogger::RootLogger()
+    : Logger::LevelThreshold()
+    , Logger(static_cast<Logger::LevelThreshold&>(*this))
+{
+}
+
+inline Logger::Level RootLogger::get() const noexcept
+{
+    return m_level_threshold;
+}
+
+inline void StderrLogger::do_log(Level level, std::string message)
+{
+    std::cerr << get_level_prefix(level) << message << '\n'; // Throws
+    std::cerr.flush();                                       // Throws
+}
+
+inline StreamLogger::StreamLogger(std::ostream& out) noexcept
+    : m_out(out)
+{
+}
+
+inline void StreamLogger::do_log(Level level, std::string message)
+{
+    m_out << get_level_prefix(level) << message << '\n'; // Throws
+    m_out.flush();                                       // Throws
+}
+
+inline FileLogger::FileLogger(std::string path)
+    : StreamLogger(m_out)
+    , m_file(path, util::File::mode_Write) // Throws
+    , m_streambuf(&m_file)                 // Throws
+    , m_out(&m_streambuf)                  // Throws
+{
+}
+
+inline FileLogger::FileLogger(util::File file)
+    : StreamLogger(m_out)
+    , m_file(std::move(file))
+    , m_streambuf(&m_file) // Throws
+    , m_out(&m_streambuf)  // Throws
+{
+}
+
+inline ThreadSafeLogger::ThreadSafeLogger(Logger& base_logger, Level threshold)
+    : Logger::LevelThreshold()
+    , Logger(static_cast<Logger::LevelThreshold&>(*this))
+    , m_level_threshold(threshold)
+    , m_base_logger(base_logger)
+{
+}
+
+inline void ThreadSafeLogger::do_log(Level level, std::string message)
+{
+    LockGuard l(m_mutex);
+    Logger::do_log(m_base_logger, level, message); // Throws
+}
+
+inline Logger::Level ThreadSafeLogger::get() const noexcept
+{
+    return m_level_threshold;
+}
+
+inline PrefixLogger::PrefixLogger(std::string prefix, Logger& base_logger) noexcept
+    : Logger(base_logger.level_threshold)
+    , m_prefix(std::move(prefix))
+    , m_base_logger(base_logger)
+{
+}
+
+inline void PrefixLogger::do_log(Level level, std::string message)
+{
+    Logger::do_log(m_base_logger, level, m_prefix + message); // Throws
+}
+
+} // namespace util
+} // namespace realm
+
+#endif // REALM_UTIL_LOGGER_HPP