Add class 'BoostLog'.
This commit is contained in:
commit
ef8d5b0b03
5
CMakeLists.txt
Normal file
5
CMakeLists.txt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.15)
|
||||||
|
|
||||||
|
project(Kylin)
|
||||||
|
|
||||||
|
add_subdirectory(Universal)
|
68
Universal/BoostLog.cpp
Normal file
68
Universal/BoostLog.cpp
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
#include "BoostLog.h"
|
||||||
|
#include <boost/log/expressions.hpp>
|
||||||
|
#include <boost/log/sinks.hpp>
|
||||||
|
#include <boost/log/sources/severity_logger.hpp>
|
||||||
|
#include <boost/log/support/date_time.hpp>
|
||||||
|
#ifdef ANDROID
|
||||||
|
#include "AndroidBoostLog.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void logFormatter(boost::log::record_view const &record, boost::log::formatting_ostream &ostream);
|
||||||
|
|
||||||
|
BOOST_LOG_GLOBAL_LOGGER_INIT(location_logger, LocationLogger<boost::log::trivial::severity_level>) {
|
||||||
|
LocationLogger<boost::log::trivial::severity_level> lg;
|
||||||
|
auto consoleSink = boost::log::add_console_log();
|
||||||
|
consoleSink->set_formatter(&logFormatter);
|
||||||
|
boost::log::add_common_attributes();
|
||||||
|
return lg;
|
||||||
|
}
|
||||||
|
|
||||||
|
void initBoostLog(const std::string &name, boost::log::trivial::severity_level filter) {
|
||||||
|
static bool initialized = false;
|
||||||
|
using namespace boost::log;
|
||||||
|
if (!initialized) {
|
||||||
|
boost::log::core::get()->set_filter(boost::log::trivial::severity >= filter);
|
||||||
|
add_common_attributes();
|
||||||
|
#ifdef ANDROID
|
||||||
|
using AndroidSink = boost::log::sinks::synchronous_sink<AndroidSinkBackend>;
|
||||||
|
auto sink = boost::make_shared<AndroidSink>();
|
||||||
|
sink->set_formatter(&androidLogFormatter);
|
||||||
|
boost::log::core::get()->add_sink(sink);
|
||||||
|
#else
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << name << "_%Y-%m-%d_%H.%M.%S_%N.log";
|
||||||
|
auto fileSink =
|
||||||
|
add_file_log(keywords::file_name = oss.str(), keywords::auto_flush = true, keywords::target = "logs");
|
||||||
|
fileSink->set_formatter(&logFormatter);
|
||||||
|
#endif
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void logFormatter(const boost::log::record_view &record, boost::log::formatting_ostream &ostream) {
|
||||||
|
using namespace boost::log;
|
||||||
|
|
||||||
|
std::string level;
|
||||||
|
boost::log::formatting_ostream oss(level);
|
||||||
|
oss << "[" << record[boost::log::trivial::severity] << "]";
|
||||||
|
|
||||||
|
auto dateTimeFormatter = expressions::stream << expressions::format_date_time<boost::posix_time::ptime>(
|
||||||
|
"TimeStamp", "[%m-%d %H:%M:%S.%f]");
|
||||||
|
|
||||||
|
dateTimeFormatter(record, ostream);
|
||||||
|
ostream << "[" << boost::log::extract<boost::log::attributes::current_thread_id::value_type>("ThreadID", record)
|
||||||
|
<< "]";
|
||||||
|
ostream << std::setw(8) << std::left << level;
|
||||||
|
auto &&category = record[AmassKeywords::category];
|
||||||
|
if (!category.empty()) ostream << " [" << category << "]";
|
||||||
|
const auto &filename = record[AmassKeywords::filename];
|
||||||
|
if (!filename.empty()) {
|
||||||
|
#ifdef QT_CREATOR_CONSOLE
|
||||||
|
ostream << " [file:///" << filename << ":" << record[AmassKeywords::line] << "] ";
|
||||||
|
#else
|
||||||
|
ostream << " [" << filename << ":" << record[AmassKeywords::line] << "] ";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
// Finally, put the record message to the stream
|
||||||
|
ostream << record[expressions::smessage];
|
||||||
|
}
|
182
Universal/BoostLog.h
Normal file
182
Universal/BoostLog.h
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
#ifndef BOOSTLOG_H
|
||||||
|
#define BOOSTLOG_H
|
||||||
|
|
||||||
|
#include <boost/log/common.hpp>
|
||||||
|
#include <boost/log/core.hpp>
|
||||||
|
#include <boost/log/detail/light_rw_mutex.hpp>
|
||||||
|
#include <boost/log/sources/record_ostream.hpp>
|
||||||
|
#include <boost/log/trivial.hpp>
|
||||||
|
#include <boost/log/utility/setup.hpp>
|
||||||
|
#include <boost/thread.hpp>
|
||||||
|
|
||||||
|
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||||
|
#pragma once
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* what i expected.
|
||||||
|
[2020-09-08 17:12:35.229152] [0x00007fa07fc94800] [info] Hello world!
|
||||||
|
[2020-09-08 17:12:35.229204] [0x00007fa07fc94800] [info] server ip: 127.0.0.1,port: 8080
|
||||||
|
[2020-09-08 17:12:35.229211] [0x00007fa07fc94800] [warning] server ip: 127.0.0.1,port: 8080
|
||||||
|
[2020-09-08 17:12:35.230961] [0x00007fa07fc94800] [info] server start successful .
|
||||||
|
*/
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
|
#define LOG_IF(lvl,predic) \
|
||||||
|
if(predic) LOG(lvl)
|
||||||
|
|
||||||
|
#define LOG_IF_EVERY_N(lvl,predic,n) \
|
||||||
|
if(predic) for(static NumberPredicator pred(n);(!!pred);) \
|
||||||
|
LOG(lvl)
|
||||||
|
|
||||||
|
#define LOG_EVERY_N(lvl,n) \
|
||||||
|
LOG_IF_EVERY_N(lvl,true,n)
|
||||||
|
|
||||||
|
#define LOG_IF_FIRST_N(lvl,predic,n) \
|
||||||
|
if(predic) for(static CountPredicator pred(n);(!!pred);) \
|
||||||
|
LOG(lvl)
|
||||||
|
|
||||||
|
#define LOG_FIRST_N(lvl,n) \
|
||||||
|
LOG_IF_FIRST_N(lvl,true,n)
|
||||||
|
|
||||||
|
|
||||||
|
#define LOG_IF_EVERY_T(lvl,predic,n) \
|
||||||
|
if(predic) for(static TimePredicator pred(n);(!!pred);) \
|
||||||
|
LOG(lvl)
|
||||||
|
|
||||||
|
#define LOG_EVERY_T(lvl,n) \
|
||||||
|
LOG_IF_EVERY_T(lvl,true,n)
|
||||||
|
|
||||||
|
// clang-format on
|
||||||
|
#ifndef LOG_FILTER_LEVEL
|
||||||
|
#define LOG_FILTER_LEVEL (boost::log::trivial::info)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void initBoostLog(
|
||||||
|
const std::string &name = "app",
|
||||||
|
boost::log::trivial::severity_level filter = static_cast<boost::log::trivial::severity_level>(LOG_FILTER_LEVEL));
|
||||||
|
|
||||||
|
namespace AmassKeywords {
|
||||||
|
|
||||||
|
BOOST_PARAMETER_KEYWORD(FilenameNS, FilenameTag)
|
||||||
|
BOOST_PARAMETER_KEYWORD(LineNS, LineTag)
|
||||||
|
BOOST_PARAMETER_KEYWORD(CategoryNS, CategoryTag)
|
||||||
|
|
||||||
|
BOOST_LOG_ATTRIBUTE_KEYWORD(filename, "Filename", std::string)
|
||||||
|
BOOST_LOG_ATTRIBUTE_KEYWORD(line, "Line", size_t)
|
||||||
|
BOOST_LOG_ATTRIBUTE_KEYWORD(category, "Category", std::string)
|
||||||
|
|
||||||
|
constexpr const char *pathEnd(const char *path) {
|
||||||
|
return *path ? pathEnd(path + 1) : path;
|
||||||
|
}
|
||||||
|
constexpr bool hasSlant(const char *path) {
|
||||||
|
return (*path == '\\' || *path == '/') ? true : (*path ? hasSlant(path + 1) : false);
|
||||||
|
}
|
||||||
|
constexpr const char *rightSlant(const char *path) {
|
||||||
|
return (*path == '\\' || *path == '/') ? (path + 1) : rightSlant(path - 1);
|
||||||
|
}
|
||||||
|
constexpr const char *fileName(const char *path) {
|
||||||
|
return hasSlant(path) ? rightSlant(pathEnd(path)) : path;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace AmassKeywords
|
||||||
|
|
||||||
|
template <typename BaseT>
|
||||||
|
class CategoryTaggerFeature : public BaseT {
|
||||||
|
public:
|
||||||
|
typedef typename BaseT::char_type char_type;
|
||||||
|
typedef typename BaseT::threading_model threading_model;
|
||||||
|
CategoryTaggerFeature() = default;
|
||||||
|
CategoryTaggerFeature(const CategoryTaggerFeature &obj);
|
||||||
|
|
||||||
|
template <typename ArgsT>
|
||||||
|
CategoryTaggerFeature(const ArgsT &args);
|
||||||
|
|
||||||
|
typedef typename boost::log::strictest_lock<boost::lock_guard<threading_model>, typename BaseT::open_record_lock,
|
||||||
|
typename BaseT::add_attribute_lock,
|
||||||
|
typename BaseT::remove_attribute_lock>::type open_record_lock;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
template <typename ArgsT>
|
||||||
|
boost::log::record open_record_unlocked(const ArgsT &args);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CategoryTagger : public boost::mpl::quote1<CategoryTaggerFeature> {};
|
||||||
|
|
||||||
|
template <typename BaseT>
|
||||||
|
class FilenameTaggerFeature : public BaseT {
|
||||||
|
public:
|
||||||
|
typedef typename BaseT::char_type char_type;
|
||||||
|
typedef typename BaseT::threading_model threading_model;
|
||||||
|
FilenameTaggerFeature() = default;
|
||||||
|
FilenameTaggerFeature(const FilenameTaggerFeature &obj);
|
||||||
|
|
||||||
|
template <typename ArgsT>
|
||||||
|
FilenameTaggerFeature(const ArgsT &args);
|
||||||
|
|
||||||
|
typedef typename boost::log::strictest_lock<boost::lock_guard<threading_model>, typename BaseT::open_record_lock,
|
||||||
|
typename BaseT::add_attribute_lock,
|
||||||
|
typename BaseT::remove_attribute_lock>::type open_record_lock;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
template <typename ArgsT>
|
||||||
|
boost::log::record open_record_unlocked(const ArgsT &args);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FilenameTagger : public boost::mpl::quote1<FilenameTaggerFeature> {};
|
||||||
|
|
||||||
|
template <typename BaseT>
|
||||||
|
class LineTaggerFeature : public BaseT {
|
||||||
|
public:
|
||||||
|
typedef typename BaseT::char_type char_type;
|
||||||
|
typedef typename BaseT::threading_model threading_model;
|
||||||
|
LineTaggerFeature() = default;
|
||||||
|
LineTaggerFeature(const LineTaggerFeature &obj);
|
||||||
|
|
||||||
|
template <typename ArgsT>
|
||||||
|
LineTaggerFeature(const ArgsT &args);
|
||||||
|
|
||||||
|
typedef typename boost::log::strictest_lock<boost::lock_guard<threading_model>, typename BaseT::open_record_lock,
|
||||||
|
typename BaseT::add_attribute_lock,
|
||||||
|
typename BaseT::remove_attribute_lock>::type open_record_lock;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
template <typename ArgsT>
|
||||||
|
boost::log::record open_record_unlocked(const ArgsT &args);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LineTagger : public boost::mpl::quote1<LineTaggerFeature> {};
|
||||||
|
|
||||||
|
template <typename LevelT = int>
|
||||||
|
class LocationLogger
|
||||||
|
: public boost::log::sources::basic_composite_logger<
|
||||||
|
char, LocationLogger<LevelT>, boost::log::sources::multi_thread_model<boost::log::aux::light_rw_mutex>,
|
||||||
|
boost::log::sources::features<boost::log::sources::severity<LevelT>, FilenameTagger, LineTagger,
|
||||||
|
CategoryTagger>> {
|
||||||
|
typedef typename LocationLogger::logger_base base_type;
|
||||||
|
|
||||||
|
public:
|
||||||
|
BOOST_LOG_FORWARD_LOGGER_MEMBERS_TEMPLATE(LocationLogger)
|
||||||
|
};
|
||||||
|
|
||||||
|
BOOST_LOG_GLOBAL_LOGGER(location_logger, LocationLogger<boost::log::trivial::severity_level>)
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
|
#define LOG( lvl) \
|
||||||
|
BOOST_LOG_STREAM_WITH_PARAMS(::location_logger::get(),\
|
||||||
|
(::boost::log::keywords::severity = ::boost::log::trivial::lvl) \
|
||||||
|
(AmassKeywords::FilenameTag = (AmassKeywords::fileName(__FILE__))) \
|
||||||
|
(AmassKeywords::LineTag = __LINE__))
|
||||||
|
|
||||||
|
#define LOG_CAT( lvl, cat) \
|
||||||
|
BOOST_LOG_STREAM_WITH_PARAMS(::location_logger::get(),\
|
||||||
|
(::boost::log::keywords::severity = ::boost::log::trivial::lvl) \
|
||||||
|
(AmassKeywords::FilenameTag = (AmassKeywords::fileName(__FILE__))) \
|
||||||
|
(AmassKeywords::LineTag = __LINE__) \
|
||||||
|
(AmassKeywords::CategoryTag = #cat))
|
||||||
|
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
#include "BoostLog.inl"
|
||||||
|
#endif // BOOSTLOG_H
|
155
Universal/BoostLog.inl
Normal file
155
Universal/BoostLog.inl
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
#ifndef BOOSTLOG_INL
|
||||||
|
#define BOOSTLOG_INL
|
||||||
|
|
||||||
|
#include "BoostLog.h"
|
||||||
|
#include "StreamFormat.h"
|
||||||
|
#include "boost/log/sources/basic_logger.hpp"
|
||||||
|
#include "boost/log/trivial.hpp"
|
||||||
|
#include "boost/scope_exit.hpp"
|
||||||
|
#include <chrono>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
|
template <typename Derived>
|
||||||
|
class LogPredicator {
|
||||||
|
public:
|
||||||
|
operator bool() const {
|
||||||
|
bool ret = m_status;
|
||||||
|
m_status = !m_status;
|
||||||
|
if (ret) {
|
||||||
|
ret = doOnceInterface();
|
||||||
|
if (!ret) m_status = true;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
inline bool doOnceInterface() const { return static_cast<const Derived *>(this)->doOnce(); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
mutable bool m_status = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
class NumberPredicator : public LogPredicator<NumberPredicator> {
|
||||||
|
public:
|
||||||
|
NumberPredicator(int limit) : m_limit(limit) {}
|
||||||
|
inline bool doOnce() const { return (m_current++ % m_limit) == 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_limit;
|
||||||
|
mutable int m_current{0};
|
||||||
|
};
|
||||||
|
|
||||||
|
class CountPredicator : public LogPredicator<CountPredicator> {
|
||||||
|
public:
|
||||||
|
CountPredicator(int limit) : m_limit(limit) {}
|
||||||
|
inline bool doOnce() const { return m_current++ < m_limit; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_limit;
|
||||||
|
mutable int m_current{0};
|
||||||
|
};
|
||||||
|
|
||||||
|
class TimePredicator : public LogPredicator<TimePredicator> {
|
||||||
|
public:
|
||||||
|
TimePredicator(int milliseconds) : m_limit(std::chrono::milliseconds(milliseconds)) {}
|
||||||
|
|
||||||
|
inline bool doOnce() const {
|
||||||
|
auto now = std::chrono::system_clock::now();
|
||||||
|
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now - m_current);
|
||||||
|
bool ret = duration >= m_limit;
|
||||||
|
if (ret) m_current = now;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::chrono::milliseconds m_limit;
|
||||||
|
mutable decltype(std::chrono::system_clock::now()) m_current{std::chrono::system_clock::now()};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename BaseT>
|
||||||
|
CategoryTaggerFeature<BaseT>::CategoryTaggerFeature(const CategoryTaggerFeature &obj)
|
||||||
|
: BaseT(static_cast<const BaseT &>(obj)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename BaseT>
|
||||||
|
template <typename ArgsT>
|
||||||
|
CategoryTaggerFeature<BaseT>::CategoryTaggerFeature(const ArgsT &args) : BaseT(args) {
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename BaseT>
|
||||||
|
template <typename ArgsT>
|
||||||
|
boost::log::record CategoryTaggerFeature<BaseT>::open_record_unlocked(const ArgsT &args) {
|
||||||
|
std::string tag_value = args[AmassKeywords::CategoryTag | std::string()];
|
||||||
|
boost::log::attribute_set &attrs = BaseT::attributes();
|
||||||
|
boost::log::attribute_set::iterator tag = attrs.end();
|
||||||
|
if (!tag_value.empty()) {
|
||||||
|
// Add the tag as a new attribute
|
||||||
|
std::pair<boost::log::attribute_set::iterator, bool> res =
|
||||||
|
BaseT::add_attribute_unlocked("Category", boost::log::attributes::constant<std::string>(tag_value));
|
||||||
|
if (res.second) tag = res.first;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_SCOPE_EXIT_TPL((&tag)(&attrs)) {
|
||||||
|
if (tag != attrs.end()) attrs.erase(tag);
|
||||||
|
}
|
||||||
|
BOOST_SCOPE_EXIT_END
|
||||||
|
|
||||||
|
return BaseT::open_record_unlocked(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename BaseT>
|
||||||
|
FilenameTaggerFeature<BaseT>::FilenameTaggerFeature(const FilenameTaggerFeature &obj)
|
||||||
|
: BaseT(static_cast<const BaseT &>(obj)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename BaseT>
|
||||||
|
template <typename ArgsT>
|
||||||
|
FilenameTaggerFeature<BaseT>::FilenameTaggerFeature(const ArgsT &args) : BaseT(args) {}
|
||||||
|
|
||||||
|
template <typename BaseT>
|
||||||
|
template <typename ArgsT>
|
||||||
|
boost::log::record FilenameTaggerFeature<BaseT>::open_record_unlocked(const ArgsT &args) {
|
||||||
|
std::string tag_value = args[AmassKeywords::FilenameTag | std::string()];
|
||||||
|
boost::log::attribute_set &attrs = BaseT::attributes();
|
||||||
|
boost::log::attribute_set::iterator tag = attrs.end();
|
||||||
|
if (!tag_value.empty()) {
|
||||||
|
// Add the tag as a new attribute
|
||||||
|
std::pair<boost::log::attribute_set::iterator, bool> res =
|
||||||
|
BaseT::add_attribute_unlocked("Filename", boost::log::attributes::constant<std::string>(tag_value));
|
||||||
|
if (res.second) tag = res.first;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_SCOPE_EXIT_TPL((&tag)(&attrs)) {
|
||||||
|
if (tag != attrs.end()) attrs.erase(tag);
|
||||||
|
}
|
||||||
|
BOOST_SCOPE_EXIT_END
|
||||||
|
|
||||||
|
return BaseT::open_record_unlocked(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename BaseT>
|
||||||
|
template <typename ArgsT>
|
||||||
|
LineTaggerFeature<BaseT>::LineTaggerFeature(const ArgsT &args) : BaseT(args) {}
|
||||||
|
|
||||||
|
template <typename BaseT>
|
||||||
|
LineTaggerFeature<BaseT>::LineTaggerFeature(const LineTaggerFeature &obj) : BaseT(static_cast<const BaseT &>(obj)) {}
|
||||||
|
|
||||||
|
template <typename BaseT>
|
||||||
|
template <typename ArgsT>
|
||||||
|
boost::log::record LineTaggerFeature<BaseT>::open_record_unlocked(const ArgsT &args) {
|
||||||
|
size_t tag_value = args[AmassKeywords::LineTag | size_t()];
|
||||||
|
boost::log::attribute_set &attrs = BaseT::attributes();
|
||||||
|
boost::log::attribute_set::iterator tag = attrs.end();
|
||||||
|
|
||||||
|
// Add the tag as a new attribute
|
||||||
|
std::pair<boost::log::attribute_set::iterator, bool> res =
|
||||||
|
BaseT::add_attribute_unlocked("Line", boost::log::attributes::constant<size_t>(tag_value));
|
||||||
|
if (res.second) tag = res.first;
|
||||||
|
|
||||||
|
BOOST_SCOPE_EXIT_TPL((&tag)(&attrs)) {
|
||||||
|
if (tag != attrs.end()) attrs.erase(tag);
|
||||||
|
}
|
||||||
|
BOOST_SCOPE_EXIT_END
|
||||||
|
|
||||||
|
return BaseT::open_record_unlocked(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // BOOSTLOG_INL
|
10
Universal/CMakeLists.txt
Normal file
10
Universal/CMakeLists.txt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
find_package(Boost REQUIRED COMPONENTS log log_setup)
|
||||||
|
|
||||||
|
add_library(Universal
|
||||||
|
BoostLog.h BoostLog.inl BoostLog.cpp
|
||||||
|
StreamFormat.h StreamFormat.inl StreamFormat.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(Universal
|
||||||
|
PRIVATE ${Boost_LIBRARIES}
|
||||||
|
)
|
11
Universal/StreamFormat.cpp
Normal file
11
Universal/StreamFormat.cpp
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#include "StreamFormat.h"
|
||||||
|
namespace std {
|
||||||
|
std::ostream &operator<<(std::ostream &stream, const std::chrono::milliseconds &element) {
|
||||||
|
stream << element.count() << "ms";
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
std::ostream &operator<<(std::ostream &stream, const std::chrono::microseconds &element) {
|
||||||
|
stream << element.count() << "us";
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
} // namespace std
|
47
Universal/StreamFormat.h
Normal file
47
Universal/StreamFormat.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#ifndef STREAMFORMAT_H
|
||||||
|
#define STREAMFORMAT_H
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <list>
|
||||||
|
#include <ostream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
template <typename T1, typename T2>
|
||||||
|
std::ostream &operator<<(std::ostream &stream, const std::pair<T1, T2> &element) {
|
||||||
|
stream << "[" << element.first << "," << element.second << "]";
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::ostream &operator<<(std::ostream &stream, const std::vector<T> &element) {
|
||||||
|
stream << "[";
|
||||||
|
for (const auto &e : element) {
|
||||||
|
stream << e << ",";
|
||||||
|
}
|
||||||
|
stream << "]";
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::ostream &operator<<(std::ostream &stream, const std::list<T> &element) {
|
||||||
|
stream << "[";
|
||||||
|
for (const auto &e : element) {
|
||||||
|
stream << e << ",";
|
||||||
|
}
|
||||||
|
stream << "]";
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream &operator<<(std::ostream &stream, const std::chrono::milliseconds &element);
|
||||||
|
std::ostream &operator<<(std::ostream &stream, const std::chrono::microseconds &element);
|
||||||
|
} // namespace std
|
||||||
|
|
||||||
|
template <typename T1, typename T2>
|
||||||
|
bool operator==(const std::pair<T1, T2> &lhs, const std::pair<T1, T2> &rhs) {
|
||||||
|
return lhs.first == rhs.first && lhs.second == rhs.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "StreamFormat.inl"
|
||||||
|
|
||||||
|
#endif // STREAMFORMAT_H
|
1
Universal/StreamFormat.inl
Normal file
1
Universal/StreamFormat.inl
Normal file
@ -0,0 +1 @@
|
|||||||
|
#include "StreamFormat.h"
|
49
resource/deploy.sh
Normal file
49
resource/deploy.sh
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
base_path=$(pwd)
|
||||||
|
libraries_root="/opt/Libraries"
|
||||||
|
if [ $base_path == /home/* ] || [ -n "${DRONE}" ]; then
|
||||||
|
build_path=${base_path}/build
|
||||||
|
else
|
||||||
|
build_path=/tmp/build
|
||||||
|
fi
|
||||||
|
echo "build directory: $build_path"
|
||||||
|
|
||||||
|
function cmake_scan() {
|
||||||
|
if [ ! -d ${build_path} ]; then
|
||||||
|
mkdir ${build_path}
|
||||||
|
fi
|
||||||
|
/opt/Qt/Tools/CMake/bin/cmake \
|
||||||
|
-G Ninja \
|
||||||
|
-S ${base_path} \
|
||||||
|
-B ${build_path} \
|
||||||
|
-DCMAKE_BUILD_TYPE=Debug \
|
||||||
|
-DBOOST_ROOT=${libraries_root}/boost_1_82_0
|
||||||
|
}
|
||||||
|
|
||||||
|
function build() {
|
||||||
|
if [ ! -f "${build_path}/CMakeCache.txt" ]; then
|
||||||
|
cmake_scan
|
||||||
|
fi
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
/opt/Qt/Tools/CMake/bin/cmake \
|
||||||
|
--build ${build_path} \
|
||||||
|
--target all
|
||||||
|
}
|
||||||
|
|
||||||
|
function main() {
|
||||||
|
local cmd=$1
|
||||||
|
shift 1
|
||||||
|
case $cmd in
|
||||||
|
build)
|
||||||
|
build
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
build
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
main $@
|
Loading…
Reference in New Issue
Block a user