Browse Source

* implemented mp::pair

* code styling
own_hana
bergmann 6 years ago
parent
commit
50c859d708
100 changed files with 4709 additions and 4112 deletions
  1. +2
    -1
      src/CMakeLists.txt
  2. +0
    -257
      src/LoggerImpl.cpp
  3. +0
    -167
      src/cpputils/Exception.h
  4. +0
    -1004
      src/cpputils/HandleManager.h
  5. +0
    -187
      src/cpputils/Logger.h
  6. +0
    -189
      src/cpputils/LoggerImpl.h
  7. +0
    -237
      src/cpputils/Misc.h
  8. +5
    -0
      src/cpputils/container.h
  9. +1005
    -0
      src/cpputils/container/handle_manager.h
  10. +50
    -33
      src/cpputils/container/nullable.h
  11. +23
    -23
      src/cpputils/container/smart_ptr.h
  12. +104
    -0
      src/cpputils/container/wrapper.h
  13. +0
    -0
     
  14. +4
    -0
      src/cpputils/logging/consumer.h
  15. +24
    -0
      src/cpputils/logging/consumer/consumer.h
  16. +25
    -0
      src/cpputils/logging/consumer/consumer_stream.h
  17. +42
    -0
      src/cpputils/logging/global.h
  18. +42
    -0
      src/cpputils/logging/log_message.h
  19. +98
    -0
      src/cpputils/logging/logger.h
  20. +51
    -0
      src/cpputils/logging/logger_impl.h
  21. +6
    -0
      src/cpputils/logging/matcher.h
  22. +20
    -0
      src/cpputils/logging/matcher/matcher.h
  23. +15
    -0
      src/cpputils/logging/matcher/matcher_all.h
  24. +20
    -0
      src/cpputils/logging/matcher/matcher_default.h
  25. +23
    -0
      src/cpputils/logging/matcher/matcher_regex.h
  26. +63
    -0
      src/cpputils/logging/rule.h
  27. +31
    -0
      src/cpputils/logging/types.h
  28. +14
    -0
      src/cpputils/misc.h
  29. +63
    -0
      src/cpputils/misc/convert.h
  30. +36
    -18
      src/cpputils/misc/enum.h
  31. +168
    -0
      src/cpputils/misc/exception.h
  32. +21
    -21
      src/cpputils/misc/flags.h
  33. +39
    -0
      src/cpputils/misc/indent.h
  34. +47
    -30
      src/cpputils/misc/linq.h
  35. +35
    -0
      src/cpputils/misc/misc.h
  36. +28
    -14
      src/cpputils/misc/stream.h
  37. +19
    -47
      src/cpputils/misc/string.h
  38. +2
    -2
      src/cpputils/misc/time.h
  39. +17
    -17
      src/cpputils/misc/transform_iterator.h
  40. +20
    -0
      src/cpputils/misc/type_helper.h
  41. +7
    -0
      src/cpputils/mp.h
  42. +0
    -980
      src/cpputils/mp/MetaProgramming.h.old
  43. +3
    -0
      src/cpputils/mp/container.h
  44. +238
    -0
      src/cpputils/mp/container/pair.h
  45. +6
    -167
      src/cpputils/mp/core.h
  46. +51
    -0
      src/cpputils/mp/core/checker.h
  47. +53
    -0
      src/cpputils/mp/core/conditionals.h
  48. +30
    -0
      src/cpputils/mp/core/const.h
  49. +78
    -0
      src/cpputils/mp/core/modifier.h
  50. +10
    -0
      src/cpputils/mp/core/types.h
  51. +3
    -0
      src/cpputils/mp/intern.h
  52. +39
    -0
      src/cpputils/mp/intern/comparable_equal.h
  53. +36
    -0
      src/cpputils/mp/intern/comparable_less.h
  54. +83
    -0
      src/cpputils/mp/intern/ebo.h
  55. +16
    -0
      src/cpputils/mp/intern/has_value.h
  56. +36
    -0
      src/cpputils/mp/intern/operators_comparable.h
  57. +50
    -0
      src/cpputils/mp/intern/operators_orderable.h
  58. +6
    -0
      src/cpputils/mp/operations.h
  59. +4
    -0
      src/cpputils/mp/operations/compare.h
  60. +73
    -0
      src/cpputils/mp/operations/compare/equal.h
  61. +51
    -0
      src/cpputils/mp/operations/compare/greater.h
  62. +51
    -0
      src/cpputils/mp/operations/compare/greater_equal.h
  63. +73
    -0
      src/cpputils/mp/operations/compare/less.h
  64. +51
    -0
      src/cpputils/mp/operations/compare/less_equal.h
  65. +51
    -0
      src/cpputils/mp/operations/compare/not_equal.h
  66. +59
    -0
      src/cpputils/mp/operations/eval.h
  67. +80
    -0
      src/cpputils/mp/operations/eval_if.h
  68. +46
    -0
      src/cpputils/mp/operations/first.h
  69. +18
    -0
      src/cpputils/mp/operations/if.fwd.h
  70. +52
    -0
      src/cpputils/mp/operations/if.h
  71. +4
    -0
      src/cpputils/mp/operations/logical.h
  72. +63
    -0
      src/cpputils/mp/operations/logical/and.h
  73. +55
    -0
      src/cpputils/mp/operations/logical/not.h
  74. +63
    -0
      src/cpputils/mp/operations/logical/or.h
  75. +46
    -0
      src/cpputils/mp/operations/second.h
  76. +54
    -0
      src/cpputils/mp/operations/value.h
  77. +8
    -151
      src/cpputils/mp/util.h
  78. +33
    -0
      src/cpputils/mp/util/default.h
  79. +38
    -0
      src/cpputils/mp/util/is_a.h
  80. +55
    -0
      src/cpputils/mp/util/make.h
  81. +35
    -0
      src/cpputils/mp/util/tag_of.h
  82. +21
    -16
      src/cpputils/mp/util/to.h
  83. +32
    -0
      src/cpputils/mp/util/when.h
  84. +119
    -0
      src/impl/logging/LoggerImpl.cpp.old
  85. +14
    -0
      src/impl/logging/consumer/consumer.cpp
  86. +66
    -0
      src/impl/logging/consumer/consumer_stream.cpp
  87. +129
    -0
      src/impl/logging/global.cpp
  88. +15
    -0
      src/impl/logging/logger.cpp
  89. +23
    -0
      src/impl/logging/logger_impl.cpp
  90. +41
    -0
      src/impl/logging/matcher.cpp
  91. +1
    -0
      test/CMakeLists.txt
  92. +0
    -61
      test/EnumConversionTests.cpp
  93. +0
    -76
      test/FlagsTests.cpp
  94. +0
    -120
      test/HandleManagerTests.cpp
  95. +0
    -135
      test/LoggingTests.cpp
  96. +0
    -22
      test/MiscTests.cpp
  97. +0
    -97
      test/StringHelperTests.cpp
  98. +120
    -0
      test/container/handle_manager.cpp
  99. +34
    -40
      test/container/nullable.cpp
  100. +124
    -0
      test/logging/logging_tests.cpp

+ 2
- 1
src/CMakeLists.txt View File

@@ -1,8 +1,9 @@
# Project: cpputils ###############################################################################

Project ( cpputils )
File ( GLOB_RECURSE SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp )
File ( GLOB_RECURSE SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/impl/*.cpp )
Add_Library ( cpputils STATIC ${SOURCE_FILES} )
Include_Directories ( ${CMAKE_CURRENT_SOURCE_DIR} )
Target_Include_Directories (
cpputils
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}


+ 0
- 257
src/LoggerImpl.cpp View File

@@ -1,257 +0,0 @@
#include <list>
#include <iomanip>

#include "cpputils/LoggerImpl.h"

using namespace logging;

struct StreamFormatSaver
{
std::ios state;
std::ostream& stream;

StreamFormatSaver(std::ostream& s) :
state (nullptr),
stream (s)
{ state.copyfmt(stream); }

~StreamFormatSaver()
{ stream.copyfmt(state); }
};


struct Manager
{
private:
using LoggerImplPtrU = std::unique_ptr<LoggerImpl>;

LoggerImpl _defaultLogger;
std::map<std::string, LoggerImplPtrU> _logger;
std::list<Rule> _rules;
std::set<Consumer*> _consumer;

LoggerImpl& initLogger(LoggerImpl& logger)
{
for (auto& rule : _rules)
{
if (rule.loggerMatcher->match(logger))
logger.registerRule(rule);
}
return logger;
}

public:
inline Logger& getLogger(const std::string& name)
{
if (name.empty())
return _defaultLogger;
auto it = _logger.find(name);
return (it != _logger.end()
? *it->second
: initLogger(*_logger.emplace(name, LoggerImplPtrU(new LoggerImpl(name))).first->second));
}

void registerConsumer(Consumer& consumer)
{
_consumer.insert(&consumer);
for (auto& rule : _rules)
{
if (rule.consumerMatcher->match(consumer))
rule.registerConsumer(consumer);
}
}

void unregisterConsumer(Consumer& consumer)
{
for (auto& rule : _rules)
rule.unregisterConsumer(consumer);
}

RuleHandle defineRule(MatcherPtrU loggerMatcher, MatcherPtrU consumerMatcher, Level minLevel, Level maxLevel)
{
_rules.emplace_back(std::move(loggerMatcher), std::move(consumerMatcher), minLevel, maxLevel);
auto& rule = _rules.back();
for (auto& c : _consumer)
{
if (rule.consumerMatcher->match(*c))
rule.registerConsumer(*c);
}
if (rule.loggerMatcher->match(_defaultLogger))
_defaultLogger.registerRule(rule);
for (auto& l : _logger)
{
if (rule.loggerMatcher->match(*l.second))
l.second->registerRule(rule);
}
return &rule;
}

void undefineRule(RuleHandle rule)
{
auto r = static_cast<Rule*>(rule);
auto it = _rules.begin();
while (&*it != r && it != _rules.end())
++it;
if (it == _rules.end())
return;
_defaultLogger.unregisterRule(*it);
for (auto& l : _logger)
l.second->unregisterRule(*it);
_rules.erase(it);
}

inline void reset()
{
_logger.clear();
_rules.clear();
_consumer.clear();
}

Manager() :
_defaultLogger(std::string())
{ }
};

Manager& manager()
{
static Manager value;
return value;
}

std::string EmptyString;

Consumer::Consumer(const std::string& n, bool autoRegister) :
_name(n)
{
if (autoRegister)
registerConsumer(*this);
}

Consumer::~Consumer()
{ unregisterConsumer(*this); }

void StreamConsumer::log(DataPtrS data)
{
std::lock_guard<std::mutex> lk(_mutex);

using namespace std;
if (!data)
return;
auto& d = *data;
auto t = std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(d.time.time_since_epoch()).count();
auto f = d.file;
if (f)
{
auto tmp = strrchr(f, '/');
if (tmp)
f = tmp + 1;
}
else
f = "unknown";

StreamFormatSaver formatSaver(*_stream);
if (t >= 0) *_stream << "[" << fixed << setfill(' ') << setw(17) << setprecision(6) << t << "] ";
switch(d.level)
{
case Level::Debug: *_stream << "DEBUG "; break;
case Level::Info: *_stream << "INFO "; break;
case Level::Warn: *_stream << "WARN "; break;
case Level::Error: *_stream << "ERROR "; break;
}

if (d.sender) *_stream << "0x" << hex << setw(2 * sizeof(void*)) << setfill('0') << d.sender;
else *_stream << " ";
if (d.thread != std::thread::id()) *_stream << "@" << hex << setw(2 * sizeof(void*)) << setfill('0') << d.thread;
else *_stream << " ";
if (!d.name.empty()) *_stream << " '" << d.name << "'";
if (d.line) *_stream << " - " << setw(25) << setfill(' ') << f << ":" << setw(5) << setfill(' ') << dec << d.line;
if (!d.message.empty())
{
*_stream << ": " << d.message;
if (d.message.back() != '\n')
*_stream << std::endl;
}
else
*_stream << std::endl;
}



bool AllMatcher::match(const Logger& logger) const
{ return true; }

bool AllMatcher::match(const Consumer& consumer) const
{ return true; }

bool RegexMatcher::match(const Logger& logger) const
{ return !logger.name().empty() && std::regex_match(logger.name(), _regex) != _invert; }

bool RegexMatcher::match(const Consumer& consumer) const
{ return !consumer.name().empty() && std::regex_match(consumer.name(), _regex) != _invert; }

bool DefaultLoggerMatcher::match(const Logger& logger) const
{ return &_defaultLogger == &logger; }



LogHelper::LogHelper(Logger& logger, DataPtrS data) :
_logger (logger),
_data (data)
{ }

LogHelper::~LogHelper()
{ _logger.log(_data); }



const std::string& Logger::name() const
{ return EmptyString; }

bool Logger::isEnabled(Level level) const
{ return false; }

void Logger::log(DataPtrS data) const
{ /* no op */ }



const std::string& LoggerImpl::name() const
{ return _name; }

bool LoggerImpl::isEnabled(Level level) const
{
for (auto& rule : _rules)
{
if (rule->isEnabled(level))
return true;
}
return false;
}

void LoggerImpl::log(DataPtrS data) const
{
std::lock_guard<std::mutex> lk(_mutex);
for (auto& r : _rules)
r->log(data);
}

namespace logging
{
Logger& getLogger(const std::string& name)
{ return manager().getLogger(name); }

void registerConsumer(Consumer& consumer)
{ return manager().registerConsumer(consumer); }

void unregisterConsumer(Consumer& consumer)
{ return manager().unregisterConsumer(consumer); }

RuleHandle defineRule(MatcherPtrU loggerMatcher, MatcherPtrU consumerMatcher, Level minLevel, Level maxLevel)
{ return manager().defineRule(std::move(loggerMatcher), std::move(consumerMatcher), minLevel, maxLevel); }

void undefineRule(RuleHandle rule)
{ return manager().undefineRule(rule); }

void resetLogging()
{ manager().reset(); }
}

+ 0
- 167
src/cpputils/Exception.h View File

@@ -1,167 +0,0 @@
#pragma once

#include <string>
#include <cstdint>
#include <iomanip>
#include <string.h>
#include <execinfo.h>

#include "Flags.h"

namespace utl
{

struct Exception : public std::exception
{
public:
enum class PrintFlag
{
ResolveAddress,
};
using PrintFlags = ShiftedFlags<PrintFlag>;

public:
static constexpr size_t StackSize = 15;
static const PrintFlags& defaultPrintFlags()
{
static const PrintFlags value({ PrintFlag::ResolveAddress });
return value;
};

private:
mutable bool _msgCacheEmpty;
mutable std::string _msgCache;

protected:
virtual void printMessage(std::ostream& os) const
{
os << message;
}

public:
std::string message;
void* stack[StackSize];
int stackSize;

public:
void print(std::ostream& os, const PrintFlags& flags = defaultPrintFlags()) const
{
printMessage(os);
os << std::endl;
char** lines = nullptr;
if (flags.isSet(PrintFlag::ResolveAddress))
lines = backtrace_symbols(stack, stackSize);
for (int i = 0; i < stackSize; ++i)
{
os << " [0x" << std::setw(2 * sizeof(void*)) << std::setfill('0') << std::hex << reinterpret_cast<uintptr_t>(stack[i]) << "]";
if (lines && lines[i])
os << " " << lines[i];
os << std::endl;
}
}

std::string print(const PrintFlags& flags = defaultPrintFlags()) const
{
std::ostringstream os;
print(os, flags);
return os.str();
}

const char* what() const throw() override
{
if (_msgCacheEmpty)
{
_msgCache = print();
_msgCacheEmpty = false;
}
return _msgCache.c_str();
}

inline friend std::ostream& operator <<(std::ostream& os, const Exception& ex)
{
ex.print(os);
return os;
}

public:
Exception() :
Exception("")
{ }

Exception(std::string msg) :
message (msg),
_msgCacheEmpty (true)
{
stackSize = backtrace(stack, StackSize);
}
};

struct ErrorException : public Exception
{
public:
int error;

ErrorException(int e) :
Exception(std::to_string(e) + " - " + strerror(e)),
error(e)
{ }

ErrorException(const std::string& msg, int e) :
Exception(msg + ": " + std::to_string(e) + " - " + strerror(e)),
error(e)
{ }
};

struct EOutOfRange : public Exception
{
protected:
void printMessage(std::ostream& os) const override
{
os << "index out of range (min=" << min << "; max=" << max << "; index=" << index << ")";
if (!message.empty())
os << " - " << message;
}

public:
size_t min;
size_t max;
size_t index;

EOutOfRange(size_t mi, size_t ma, size_t idx, std::string msg = "") :
Exception (msg),
min (mi),
max (ma),
index (idx)
{ }
};

struct EArgument : public Exception
{
protected:
void printMessage(std::ostream& os) const override
{
os << "invalid argument";
if (!argument.empty())
os << "(" << argument << ")";
if (!message.empty())
os << " - " << message;
}

public:
std::string argument;

EArgument(std::string arg, std::string msg) :
Exception (message),
argument (arg)
{ }
};

struct EInvalidOperation : public Exception
{
public:
EInvalidOperation(std::string msg) :
Exception(msg)
{ }
};

}

+ 0
- 1004
src/cpputils/HandleManager.h
File diff suppressed because it is too large
View File


+ 0
- 187
src/cpputils/Logger.h View File

@@ -1,187 +0,0 @@
#pragma once

#include <memory>
#include <chrono>
#include <thread>
#include <sstream>

#include "Exception.h"

// () mandatory
// [] optional
// (logger), (LogLevel: Debug|Info|Warn|Error), [Sender], [Message, [Arguments]]
#define logMessage(logger, level, ...) \
if (logger.isEnabled(logging::Level::level)) \
logger.makeLogHelper(logging::Level::level, __FILE__, __LINE__, ## __VA_ARGS__ ) = logging::LogMessage()

// () mandatory
// [] optional
// (LogLevel: Debug|Info|Warn|Error), [Sender], [Message, [Arguments]]
#define logGlobalMessage(level, ...) \
if (logging::isEnabled(logging::Level::level)) \
logging::makeLogHelper(logging::Level::level, __FILE__, __LINE__, ## __VA_ARGS__ ) = logging::LogMessage()


namespace logging
{

enum class Level
{
Debug = 0,
Info,
Warn,
Error,
};

struct Data
{
Level level;
std::chrono::steady_clock::time_point time;
void* sender;
std::thread::id thread;
const char* file;
int line;
std::string name;
std::string message;
};
using DataPtrS = std::shared_ptr<Data>;

struct Logger;

struct LogMessage
{
private:
std::ostringstream _msg;

public:
inline std::string str() const
{ return _msg.str(); }

template <typename T>
inline LogMessage& operator <<(const T& value)
{
_msg << value;
return *this;
}

inline LogMessage& operator <<(std::ostream& (*callback)(std::ostream&))
{
callback(_msg);
return *this;
}

LogMessage() :
_msg()
{ }

LogMessage(const std::string& msg) :
_msg(msg)
{ }

private:
LogMessage(const LogMessage&) = delete;
LogMessage(LogMessage&&) = delete;
};

struct LogHelper
{
private:
Logger& _logger;
DataPtrS _data;

public:
inline void operator=(const LogMessage& msg)
{ _data->message += msg.str(); }

LogHelper(Logger& logger, DataPtrS data);
~LogHelper();
};

struct Logger
{
private:
Logger(const Logger&) = delete;
Logger(Logger&&) = delete;

public:
Logger() { }

virtual const std::string& name() const;
virtual bool isEnabled(Level level) const;
virtual void log(DataPtrS data) const;

template<class Sender>
inline LogHelper makeLogHelper(Level level, const char* file, int line, Sender* sender, std::string message)
{ return makeLogHelper<void>(level, file, line, static_cast<void*>(sender), message); }

template<class Sender>
inline LogHelper makeLogHelper(Level level, const char* file, int line, Sender* sender)
{ return makeLogHelper<void>(level, file, line, static_cast<void*>(sender), std::string()); }

inline LogHelper makeLogHelper(Level level, const char* file, int line, std::string message)
{ return makeLogHelper(level, file, line, nullptr, message); }

inline LogHelper makeLogHelper(Level level, const char* file, int line)
{ return makeLogHelper(level, file, line, nullptr, std::string()); }

template<class Sender, class... Args>
inline LogHelper makeLogHelper(Level level, const char* file, int line, Sender* sender, std::string message, Args... args)
{
std::unique_ptr<char, decltype(&free)> buff(static_cast<char*>(malloc(0x8000)), &free);
auto len = snprintf(buff.get(), 10240, message.c_str(), args...);
if (len < 0)
throw utl::ErrorException(errno);
return makeLogHelper<Sender>(level, file, line, sender, std::string(buff.get(), len));
}

template<class... Args>
inline LogHelper makeLogHelper(Level level, const char* file, int line, std::string message, Args... args)
{ return makeLogHelper<void, Args...>(level, file, line, nullptr, message, args...); }

};

template<>
inline LogHelper Logger::makeLogHelper<void>(Level level, const char* file, int line, void* sender, std::string message)
{
DataPtrS data(new Data());
data->level = level;
data->time = std::chrono::steady_clock::now();
data->thread = std::this_thread::get_id();
data->file = file;
data->line = line;
data->sender = sender;
data->name = name();
data->message = message;
return LogHelper(*this, data);
}

Logger& getLogger(const std::string& name = "");

inline bool isEnabled(Level level)
{ return getLogger().isEnabled(level); }

template <class Sender>
inline LogHelper makeLogHelper(Level level, const char* file, int line, Sender* sender, std::string message)
{ return getLogger().makeLogHelper<Sender>(level, file, line, sender, message); }

template <class Sender>
inline LogHelper makeLogHelper(Level level, const char* file, int line, Sender* sender)
{ return getLogger().makeLogHelper<Sender>(level, file, line, sender, std::string()); }

inline LogHelper makeLogHelper(Level level, const char* file, int line, std::string message)
{ return getLogger().makeLogHelper<void>(level, file, line, nullptr, message); }

inline LogHelper makeLogHelper(Level level, const char* file, int line)
{ return getLogger().makeLogHelper<void>(level, file, line, nullptr, std::string()); }

template <class Sender, class... Args>
inline LogHelper makeLogHelper(Level level, const char* file, int line, Sender* sender, std::string message, Args... args)
{ return getLogger().makeLogHelper<Sender, Args...>(level, file, line, sender, message, args...); }

template <class... Args>
inline LogHelper makeLogHelper(Level level, const char* file, int line, std::string message, Args... args)
{ return getLogger().makeLogHelper<void, Args...>(level, file, line, nullptr, message, args...); }

void resetLogging();

}

+ 0
- 189
src/cpputils/LoggerImpl.h View File

@@ -1,189 +0,0 @@
#pragma once

#include <set>
#include <map>
#include <regex>
#include <mutex>
#include <iostream>

#include "Logger.h"

namespace logging
{

struct Consumer
{
private:
std::string _name;

public:
virtual void log(DataPtrS data) = 0;

inline const std::string& name() const
{ return _name; }

Consumer(const std::string& n, bool autoRegister);
~Consumer();
};

struct StreamConsumer : public Consumer
{
private:
mutable std::mutex _mutex;
std::ostream* _stream;
bool _ownsStream;

public:
void log(DataPtrS data) override;

StreamConsumer(const std::string& name, std::ostream& stream, bool ownsStream, bool autoRegister) :
Consumer (name, autoRegister),
_stream (&stream),
_ownsStream (ownsStream)
{ }

virtual ~StreamConsumer()
{
if (_ownsStream && _stream)
{
delete _stream;
_stream = nullptr;
}
}
};



struct Matcher
{
virtual bool match(const Logger& logger) const
{ return false; }

virtual bool match(const Consumer& consumer) const
{ return false; }
};

struct AllMatcher : public Matcher
{
bool match(const Logger& logger) const override;
bool match(const Consumer& consumer) const override;
};

struct RegexMatcher : public Matcher
{
private:
std::regex _regex;
bool _invert;

public:
bool match(const Logger& logger) const override;
bool match(const Consumer& consumer) const override;

RegexMatcher(const std::string expression, bool invert = false) :
_regex (expression),
_invert (invert)
{ }
};

struct DefaultLoggerMatcher : public Matcher
{
private:
Logger& _defaultLogger;

public:
using Matcher::match;
bool match(const Logger& logger) const override;

DefaultLoggerMatcher() :
_defaultLogger(getLogger(std::string()))
{ }
};

using RuleHandle = void*;
using MatcherPtrU = std::unique_ptr<Matcher>;

struct Rule
{
private:
mutable std::mutex _mutex;
std::set<Consumer*> _consumer;

public:
MatcherPtrU loggerMatcher;
MatcherPtrU consumerMatcher;
Level minLevel;
Level maxLevel;

inline bool isEnabled(Level level) const
{
return minLevel <= level
&& maxLevel >= level;
}

inline void registerConsumer(Consumer& consumer)
{
std::lock_guard<std::mutex> lk(_mutex);
_consumer.insert(&consumer);
}

inline void unregisterConsumer(Consumer& consumer)
{
std::lock_guard<std::mutex> lk(_mutex);
_consumer.erase(&consumer);
}

inline void log(DataPtrS data)
{
std::lock_guard<std::mutex> lk(_mutex);
if (isEnabled(data->level))
{
for (auto& c : _consumer)
c->log(data);
}
}

Rule(MatcherPtrU lm, MatcherPtrU cm, Level min, Level max) :
loggerMatcher (std::move(lm)),
consumerMatcher(std::move(cm)),
minLevel (min),
maxLevel (max)
{ }
};


struct LoggerImpl : public Logger
{
private:
mutable std::mutex _mutex;
std::string _name;
std::set<Rule*> _rules;

public:
const std::string& name() const override;
bool isEnabled(Level level) const override;
void log(DataPtrS data) const override;

inline void registerRule(Rule& rule)
{
std::lock_guard<std::mutex> lk(_mutex);
_rules.insert(&rule);
}

inline void unregisterRule(Rule& rule)
{
std::lock_guard<std::mutex> lk(_mutex);
_rules.erase(&rule);
}

LoggerImpl(const std::string& n) :
_name(n)
{ }
};

void registerConsumer (Consumer& consumer);
void unregisterConsumer(Consumer& consumer);

RuleHandle defineRule(MatcherPtrU loggerMatcher, MatcherPtrU consumerMatcher, Level minLevel = Level::Debug, Level maxLevel = Level::Error);
void undefineRule(RuleHandle handle);

}

+ 0
- 237
src/cpputils/Misc.h View File

@@ -1,237 +0,0 @@
#pragma once

#include <cxxabi.h>
#include <iostream>

#if defined(__linux__)
# include <endian.h>
#elif defined(__FreeBSD__) || defined(__NetBSD__)
# include <sys/endian.h>
#elif defined(__OpenBSD__)
# include <sys/types.h>
# define be16toh(x) betoh16(x)
# define be32toh(x) betoh32(x)
# define be64toh(x) betoh64(x)
#endif

namespace utl
{

/* TypeHelper ********************************************************************************/
template<class T>
struct TypeHelper
{
public:
static inline std::string name()
{
int status;
auto name = abi::__cxa_demangle(typeid(T).name(), 0, 0, &status);
return std::string(name ? name : typeid(T).name());
}
};

/* simple class that stores a value of type T */
template<class T>
struct wrapper
{
using value_type = T;

value_type value;

inline value_type& operator*()
{ return value; }

inline const value_type& operator*() const
{ return value; }

inline wrapper& operator=(const value_type v)
{
value = v;
return *this;
}

inline wrapper& operator=(const wrapper& other)
{
value = other.value;
return *this;
}

inline wrapper& operator=(wrapper&& other)
{
value = std::move(other).value;
return *this;
}

inline wrapper() :
value(value_type())
{ }

inline wrapper(const value_type& v) :
value(v)
{ }

inline wrapper(const wrapper& other) :
value(other.value)
{ }

inline wrapper(wrapper&& other) :
value(std::move(other.value))
{ }
};

template<class T>
struct wrapper<T&>
{
using value_type = T&;
using storage_type = T*;

storage_type value;

inline value_type operator*() const
{
assert(value != nullptr);
return *value;
}

inline wrapper& operator=(const value_type v)
{
value = &v;
return *this;
}

inline wrapper& operator=(const wrapper& other)
{
value = other.value;
return *this;
}

inline wrapper& operator=(wrapper&& other)
{
value = std::move(other.value);
return *this;
}

inline wrapper() :
value(nullptr)
{ }

inline wrapper(value_type v) :
value(&v)
{ }

inline wrapper(const wrapper& other) :
value(other.value)
{ }

inline wrapper(wrapper&& other) :
value(std::move(other.value))
{ }
};

/* Helper Methods ****************************************************************************/
inline int bitCount(uint32_t u)
{
u = u
- ((u >> 1) & 033333333333)
- ((u >> 2) & 011111111111);
return ((u + (u >> 3)) & 030707070707) % 63;
}

template<class T, class S>
inline bool tryCast(T* t, S*& s)
{
s = dynamic_cast<S*>(t);
return static_cast<bool>(s);
}

namespace __impl
{
template<class T, size_t N = sizeof(T)>
struct network_convert_helper;
}

template<class T>
inline T hton(const T& value)
{ return __impl::network_convert_helper<T>::hton(value); }

template<class T>
inline T ntoh(const T& value)
{ return __impl::network_convert_helper<T>::ntoh(value); }


/* Indent Stream *****************************************************************************/
namespace __impl
{
inline int identStreamIndex()
{
const int value = std::ios::xalloc();
return value;
}
}

inline std::ostream& incindent(std::ostream& os)
{
++os.iword(__impl::identStreamIndex());
return os;
}

inline std::ostream& decindent(std::ostream& os)
{
auto& indent = os.iword(__impl::identStreamIndex());
if (--indent < 0)
indent = 0;
return os;
}

inline std::ostream& indent(std::ostream& os)
{
auto i = os.iword(__impl::identStreamIndex());
while (i--)
os << " ";
return os;
}

/* implementation ****************************************************************************/
namespace __impl
{
template<class T>
struct network_convert_helper<T, 1>
{
static inline T hton(const T& t)
{ return t; }

static inline T ntoh(const T& t)
{ return t; }
};

template<class T>
struct network_convert_helper<T, 2>
{
static inline T hton(const T& t)
{ return reinterpret_cast<T>(htobe16(reinterpret_cast<uint16_t>(t))); }

static inline T ntoh(const T& t)
{ return reinterpret_cast<T>(be16toh(reinterpret_cast<uint16_t>(t))); }
};

template<class T>
struct network_convert_helper<T, 4>
{
static inline T hton(const T& t)
{ return reinterpret_cast<T>(htobe32(reinterpret_cast<uint32_t>(t))); }

static inline T ntoh(const T& t)
{ return reinterpret_cast<T>(be32toh(reinterpret_cast<uint32_t>(t))); }
};

template<class T>
struct network_convert_helper<T, 8>
{
static inline T hton(const T& t)
{ return reinterpret_cast<T>(htobe64(reinterpret_cast<uint64_t>(t))); }

static inline T ntoh(const T& t)
{ return reinterpret_cast<T>(be64toh(reinterpret_cast<uint64_t>(t))); }
};
}
}

+ 5
- 0
src/cpputils/container.h View File

@@ -0,0 +1,5 @@
#pragma once

#include <cpputils/container/handle_manager.h>
#include <cpputils/container/nullable.h>
#include <cpputils/container/smart_ptr.h>

+ 1005
- 0
src/cpputils/container/handle_manager.h
File diff suppressed because it is too large
View File


src/cpputils/Nullable.h → src/cpputils/container/nullable.h View File

@@ -2,13 +2,15 @@

#include <memory>
#include <type_traits>
#include "Exception.h"

#include <cpputils/misc/string.h>
#include <cpputils/misc/exception.h>

namespace utl
{

template<class T>
struct Nullable
struct nullable
{
public:
using value_type = T;
@@ -16,23 +18,23 @@ namespace utl
using pointer_type = clean_type*;

private:
struct Container
struct container
{
value_type value;

template<class... Args>
Container(Args&&... args) :
container(Args&&... args) :
value(std::forward<Args>(args)...)
{ }
};

private:
std::unique_ptr<Container> _container;
std::unique_ptr<container> _container;

inline void check() const
{
if (!_container)
throw EInvalidOperation("nullable does not have a value");
throw invalid_operation_exception("nullable does not have a value");
}

public:
@@ -42,7 +44,7 @@ namespace utl
inline const value_type& value() const
{ check(); return _container->value; }

inline bool hasValue() const
inline bool has_value() const
{ return static_cast<bool>(_container); }

inline void reset()
@@ -69,75 +71,90 @@ namespace utl
{ return value(); }

inline explicit operator bool() const
{ return hasValue(); }
{ return has_value(); }

inline bool operator==(T v) const
{ return hasValue() && value() == v; }
{ return has_value() && value() == v; }

inline bool operator==(const Nullable& other) const
{ return hasValue() && other.hasValue() && value() == other.value(); }
inline bool operator==(const nullable& other) const
{ return has_value() && other.has_value() && value() == other.value(); }

inline bool operator<(const Nullable& other) const
inline bool operator<(const nullable& other) const
{
return this->hasValue()
&& other.hasValue()
return this->has_value()
&& other.has_value()
&& value() < other.value();
}

inline bool operator>(const Nullable& other) const
inline bool operator>(const nullable& other) const
{
return this->hasValue()
&& other.hasValue()
return this->has_value()
&& other.has_value()
&& value() < other.value();
}

inline bool operator<=(const Nullable& other) const
inline bool operator<=(const nullable& other) const
{
return this->hasValue()
&& other.hasValue()
return this->has_value()
&& other.has_value()
&& value() < other.value();
}

inline bool operator>=(const Nullable& other) const
inline bool operator>=(const nullable& other) const
{
return this->hasValue()
&& other.hasValue()
return this->has_value()
&& other.has_value()
&& value() < other.value();
}

inline void operator=(value_type&& t)
{ _container.reset(new Container(std::forward<value_type>(t))); }
{ _container.reset(new container(std::forward<value_type>(t))); }

inline void operator=(const Nullable& other)
inline void operator=(const nullable& other)
{
if (other.hasValue())
if (other.has_value())
*this = other.value();
else
reset();
}

inline void operator=(Nullable&& other)
inline void operator=(nullable&& other)
{ _container = std::move(other._container); }



Nullable()
nullable()
{ }

template<class... Args>
Nullable(Args&&... args) :
_container(new Container(std::forward<Args>(args)...))
nullable(Args&&... args) :
_container(new container(std::forward<Args>(args)...))
{ }

Nullable(Nullable& other)
nullable(nullable& other)
{ if (static_cast<bool>(other)) *this = other(); }

Nullable(const Nullable& other)
nullable(const nullable& other)
{ if (static_cast<bool>(other)) *this = other(); }

Nullable(Nullable&& other) :
nullable(nullable&& other) :
_container(std::move(other._container))
{ }
};

namespace __impl
{
template<class T>
struct op_to_string<nullable<T>, void>
{
inline void operator()(std::ostream& os, const nullable<T>& s) const
{
if (s.has_value())
op_to_string<T>()(os, s.value());
else
os << "null";
}
};
}

}

src/cpputils/SmartPtr.h → src/cpputils/container/smart_ptr.h View File

@@ -2,13 +2,13 @@

#include <memory>
#include "MetaProgramming.h"
#include "Exception.h"
#include "exception.h"

namespace utl
{

template<class T>
struct SmartPtr
struct smart_ptr
{
private:
template<class Tt_base, class Tt_derived>
@@ -23,7 +23,7 @@ namespace utl
public utl::mp_false { };

template<template<class> class F, class X>
struct __impl_cop_is_value<F<X>, utl::mp_enable_if<cop_is_base_of<SmartPtr<X>, F<X>>>> :
struct __impl_cop_is_value<F<X>, utl::mp_enable_if<cop_is_base_of<smart_ptr<X>, F<X>>>> :
public utl::mp_false { };

template<class X>
@@ -40,20 +40,20 @@ namespace utl
std::shared_ptr<T> _value;

public:
inline bool hasValue() const
inline bool has_value() const
{ return static_cast<bool>(_value); }

inline T& value()
{
if (!_value)
throw utl::EInvalidOperation("SmartPtr does not have a value");
throw utl::invalid_operation_exception("smart_ptr does not have a value");
return *_value;
}

inline const T& value() const
{
if (!_value)
throw utl::EInvalidOperation("SmartPtr does not have a value");
throw utl::invalid_operation_exception("smart_ptr does not have a value");
return *_value;
}

@@ -70,95 +70,95 @@ namespace utl
{ return &value(); }

inline operator bool() const
{ return hasValue(); }
{ return has_value(); }

inline SmartPtr& reset()
inline smart_ptr& reset()
{
_value.reset();
return *this;
}

template<class X = T, utl::mp_enable_if_c<cop_is_value<X>::value, int> = 0>
inline SmartPtr& reset(X& x)
inline smart_ptr& reset(X& x)
{
_value.reset(new X(x));
return *this;
}

template<class X = T, utl::mp_enable_if_c<cop_is_value<X>::value, int> = 0>
inline SmartPtr& reset(X&& x)
inline smart_ptr& reset(X&& x)
{
_value.reset(new X(std::move(x)));
return *this;
}

template<class X = T, utl::mp_enable_if_c<cop_is_base_of<T, X>::value, int> = 0>
inline SmartPtr& reset(const SmartPtr<X>& other)
inline smart_ptr& reset(const smart_ptr<X>& other)
{
_value = other._value;
return *this;
}

template<class X = T, utl::mp_enable_if_c<cop_is_base_of<T, X>::value, int> = 0>
inline SmartPtr& reset(SmartPtr<X>&& other)
inline smart_ptr& reset(smart_ptr<X>&& other)
{
_value = std::move(other._value);
return *this;
}

template<class X = T, utl::mp_enable_if_c<cop_is_base_of<T, X>::value, int> = 0>
inline SmartPtr& reset(std::reference_wrapper<X>&& ref)
inline smart_ptr& reset(std::reference_wrapper<X>&& ref)
{
_value.reset(&ref.get(), op_deleter_noop());
return *this;
}

template<class... Args>
inline SmartPtr& reset(Args&&... args)
inline smart_ptr& reset(Args&&... args)
{
_value.reset(new T(std::forward<Args>(args)...));
return *this;
}

template<class X = T>
inline SmartPtr& operator=(X&& x)
inline smart_ptr& operator=(X&& x)
{ return reset(std::forward<X>(x)); }

SmartPtr()
smart_ptr()
{ }

template<class X = T, utl::mp_enable_if_c<cop_is_value<X>::value, int> = 0>
SmartPtr(X& x) :
smart_ptr(X& x) :
_value(new X(x))
{ }

template<class X = T, utl::mp_enable_if_c<cop_is_value<X>::value, int> = 0>
SmartPtr(X&& x) :
smart_ptr(X&& x) :
_value(new X(std::move(x)))
{ }

template<class X = T, utl::mp_enable_if_c<std::is_base_of<T, X>::value, int> = 0>
SmartPtr(X* x) :
smart_ptr(X* x) :
_value(x)
{ }

template<class X = T, utl::mp_enable_if_c<std::is_base_of<T, X>::value, int> = 0>
SmartPtr(const SmartPtr<X>& other) :
smart_ptr(const smart_ptr<X>& other) :
_value(other._value)
{ }

template<class X = T, utl::mp_enable_if_c<std::is_base_of<T, X>::value, int> = 0>
SmartPtr(SmartPtr<X>&& other) :
smart_ptr(smart_ptr<X>&& other) :
_value(std::move(other._value))
{ }

template<class X = T, utl::mp_enable_if_c<std::is_base_of<T, X>::value, int> = 0>
SmartPtr(std::reference_wrapper<X>&& ref) :
smart_ptr(std::reference_wrapper<X>&& ref) :
_value(&ref.get(), op_deleter_noop())
{ }

template<class... Args>
SmartPtr(Args... args) :
smart_ptr(Args... args) :
_value(new T(args...))
{ }
};

+ 104
- 0
src/cpputils/container/wrapper.h View File

@@ -0,0 +1,104 @@
#pragma once

namespace utl
{

/* simple class that stores a value of type T */
template<class T>
struct wrapper
{
using value_type = T;

value_type value;

inline value_type& operator*()
{ return value; }

inline const value_type& operator*() const
{ return value; }

inline wrapper& operator=(value_type v)
{
value = v;
return *this;
}

inline wrapper& operator=(const wrapper& other)
{
value = other.value;
return *this;
}

inline wrapper& operator=(wrapper&& other)
{
value = std::move(other).value;
return *this;
}

inline wrapper() :
value(value_type())
{ }

inline wrapper(const value_type& v) :
value(v)
{ }

inline wrapper(const wrapper& other) :
value(other.value)
{ }

inline wrapper(wrapper&& other) :
value(std::move(other.value))
{ }
};

template<class T>
struct wrapper<T&>
{
using value_type = T&;
using storage_type = T*;

storage_type value;

inline value_type operator*() const
{
assert(value != nullptr);
return *value;
}

inline wrapper& operator=(value_type v)
{
value = &v;
return *this;
}

inline wrapper& operator=(const wrapper& other)
{
value = other.value;
return *this;
}

inline wrapper& operator=(wrapper&& other)
{
value = std::move(other.value);
return *this;
}

inline wrapper() :
value(nullptr)
{ }

inline wrapper(value_type v) :
value(&v)
{ }

inline wrapper(const wrapper& other) :
value(other.value)
{ }

inline wrapper(wrapper&& other) :
value(std::move(other.value))
{ }
};

}

+ 0
- 0
View File


+ 4
- 0
src/cpputils/logging/consumer.h View File

@@ -0,0 +1,4 @@
#pragma once

#include <cpputils/logging/consumer/consumer.h>
#include <cpputils/logging/consumer/consumer_stream.h>

+ 24
- 0
src/cpputils/logging/consumer/consumer.h View File

@@ -0,0 +1,24 @@
#pragma once

#include <cpputils/logging/types.h>

namespace utl {
namespace logging {

struct consumer
{
private:
std::string _name;

public:
virtual void log(data_ptr_s data) = 0;

inline const std::string& name() const
{ return _name; }

consumer(const std::string& n, bool autoRegister);
~consumer();
};

}
}

+ 25
- 0
src/cpputils/logging/consumer/consumer_stream.h View File

@@ -0,0 +1,25 @@
#pragma once

#include <mutex>

#include <cpputils/logging/consumer/consumer.h>

namespace utl {
namespace logging {

struct consumer_stream : public consumer
{
private:
mutable std::mutex _mutex;
std::ostream* _stream;
bool _ownsStream;

public:
void log(data_ptr_s data) override;

consumer_stream(const std::string& name, std::ostream& stream, bool ownsStream, bool autoRegister);
virtual ~consumer_stream();
};

}
}

+ 42
- 0
src/cpputils/logging/global.h View File

@@ -0,0 +1,42 @@
#pragma once

#include <cpputils/logging/types.h>
#include <cpputils/logging/logger.h>

// () mandatory
// [] optional
// (LogLevel: debug|info|warn|error), [T_sender], [Message, [Arguments]]
#define log_global_message(level, ...) \
if (::utl::logging::is_enabled(::utl::logging::log_level::level)) \
::utl::logging::make_log_helper(::utl::logging::log_level::level, __FILE__, __LINE__, ## __VA_ARGS__ ) = ::utl::logging::log_message()

namespace utl {
namespace logging {

inline bool is_enabled(log_level level)
{ return get_logger().is_enabled(level); }

template <class T_sender>
inline logger::helper make_log_helper(log_level level, const char* file, int line, T_sender* sender, std::string message)
{ return get_logger().make_log_helper<T_sender>(level, file, line, sender, message); }

template <class T_sender>
inline logger::helper make_log_helper(log_level level, const char* file, int line, T_sender* sender)
{ return get_logger().make_log_helper<T_sender>(level, file, line, sender, std::string()); }

inline logger::helper make_log_helper(log_level level, const char* file, int line, std::string message)
{ return get_logger().make_log_helper<void>(level, file, line, nullptr, message); }

inline logger::helper make_log_helper(log_level level, const char* file, int line)
{ return get_logger().make_log_helper<void>(level, file, line, nullptr, std::string()); }

template <class T_sender, class... Args>
inline logger::helper make_log_helper(log_level level, const char* file, int line, T_sender* sender, std::string message, Args... args)
{ return get_logger().make_log_helper<T_sender, Args...>(level, file, line, sender, message, args...); }

template <class... Args>
inline logger::helper make_log_helper(log_level level, const char* file, int line, std::string message, Args... args)
{ return get_logger().make_log_helper<void, Args...>(level, file, line, nullptr, message, args...); }

}
}

+ 42
- 0
src/cpputils/logging/log_message.h View File

@@ -0,0 +1,42 @@
#pragma once

namespace utl {
namespace logging {

struct log_message
{
private:
std::ostringstream _msg;

public:
inline std::string str() const
{ return _msg.str(); }

template <typename T>
inline log_message& operator <<(const T& value)
{
_msg << value;
return *this;
}

inline log_message& operator <<(std::ostream& (*callback)(std::ostream&))
{
callback(_msg);
return *this;
}

log_message() :
_msg()
{ }

log_message(const std::string& msg) :
_msg(msg)
{ }

private:
log_message(log_message&&) = delete;
log_message(const log_message&) = delete;
};

}
}

+ 98
- 0
src/cpputils/logging/logger.h View File

@@ -0,0 +1,98 @@
#pragma once

#include <cpputils/misc/exception.h>
#include <cpputils/logging/types.h>
#include <cpputils/logging/log_message.h>

// () mandatory
// [] optional
// (logger), (LogLevel: debug|info|warn|error), [Sender], [Message, [Arguments]]
#define log_message(logger, level, ...) \
if (logger.is_enabled(::utl::logging::log_level::level)) \
logger.make_log_helper(::utl::logging::log_level::level, __FILE__, __LINE__, ## __VA_ARGS__ ) = ::utl::logging::log_message()

namespace utl {
namespace logging {

struct logger
{
public:
struct helper
{
private:
logger& _logger;
data_ptr_s _data;

public:
inline void operator=(const log_message& msg)
{ _data->message += msg.str(); }

inline helper(logger& logger, data_ptr_s data) :
_logger (logger),
_data (data)
{ }

inline ~helper()
{ _logger.log(_data); }

public:
static inline helper create(logger& logger, log_level level, const char* file, int line, void* sender, const std::string& name, std::string message)
{
using namespace ::utl::logging;
data_ptr_s ret(new data());
ret->level = level;
ret->time = std::chrono::steady_clock::now();
ret->thread = std::this_thread::get_id();
ret->file = file;
ret->line = line;
ret->sender = sender;
ret->name = name;
ret->message = message;
return helper(logger, ret);
}
};

private:
logger(logger&&) = delete;
logger(const logger&) = delete;

public:
logger() { }

virtual const std::string& name () const;
virtual bool is_enabled (log_level level) const;
virtual void log (data_ptr_s data) const;

template<class Sender, class... Args>
inline logger::helper make_log_helper(log_level level, const char* file, int line, Sender* sender, std::string message, Args... args)
{
std::unique_ptr<char, decltype(&free)> buff(static_cast<char*>(malloc(0x8000)), &free);
auto len = snprintf(buff.get(), 10240, message.c_str(), args...);
if (len < 0)
throw utl::error_exception(errno);
return helper::create(*this, level, file, line, static_cast<void*>(sender), name(), std::string(buff.get(), len));
}

template<class... Args>
inline logger::helper make_log_helper(log_level level, const char* file, int line, std::string message, Args... args)
{ return make_log_helper<void, Args...>(level, file, line, nullptr, message, args...); }

template<class Sender>
inline logger::helper make_log_helper(log_level level, const char* file, int line, Sender* sender, std::string message)
{ return helper::create(*this, level, file, line, static_cast<void*>(sender), name(), message); }

template<class Sender>
inline logger::helper make_log_helper(log_level level, const char* file, int line, Sender* sender)
{ return make_log_helper<void>(level, file, line, static_cast<void*>(sender), std::string()); }

inline logger::helper make_log_helper(log_level level, const char* file, int line, std::string message)
{ return make_log_helper<void>(level, file, line, nullptr, message); }

inline logger::helper make_log_helper(log_level level, const char* file, int line)
{ return make_log_helper<void>(level, file, line, nullptr, std::string()); }
};

logger& get_logger(const std::string& name = "");

}
}

+ 51
- 0
src/cpputils/logging/logger_impl.h View File

@@ -0,0 +1,51 @@
#pragma once

#include <set>
#include <mutex>

#include <cpputils/logging/rule.h>
#include <cpputils/logging/logger.h>

namespace utl {
namespace logging {

struct logger_impl : public logger
{
private:
mutable std::mutex _mutex;
std::string _name;
std::set<rule*> _rules;

public:
const std::string& name () const override;
bool is_enabled (log_level level) const override;
void log (data_ptr_s data) const override;

inline void registerRule(rule& rule)
{
std::lock_guard<std::mutex> lk(_mutex);
_rules.insert(&rule);
}

inline void unregisterRule(rule& rule)
{
std::lock_guard<std::mutex> lk(_mutex);
_rules.erase(&rule);
}

logger_impl(const std::string& n) :
_name(n)
{ }
};

using logger_impl_ptr_u = std::unique_ptr<logger_impl>;

void register_consumer (consumer& consumer);
void unregister_consumer(consumer& consumer);

rule_handle define_rule (matcher_ptr_u logger_matcher, matcher_ptr_u consumer_matcher, log_level min_level = log_level::debug, log_level max_level = log_level::error);
void undefine_rule (rule_handle handle);

void reset_logging();

} }

+ 6
- 0
src/cpputils/logging/matcher.h View File

@@ -0,0 +1,6 @@
#pragma once

#include <cpputils/logging/matcher/matcher.h>
#include <cpputils/logging/matcher/matcher_all.h>
#include <cpputils/logging/matcher/matcher_default.h>
#include <cpputils/logging/matcher/matcher_regex.h>

+ 20
- 0
src/cpputils/logging/matcher/matcher.h View File

@@ -0,0 +1,20 @@
#pragma once

#include <memory>

#include <cpputils/logging/logger.h>
#include <cpputils/logging/consumer/consumer.h>

namespace utl {
namespace logging {

struct matcher
{
virtual bool match(const logger& logger) const;
virtual bool match(const consumer& consumer) const;
};

using matcher_ptr_u = std::unique_ptr<matcher>;

}
}

+ 15
- 0
src/cpputils/logging/matcher/matcher_all.h View File

@@ -0,0 +1,15 @@
#pragma once

#include <cpputils/logging/matcher/matcher.h>

namespace utl {
namespace logging {

struct matcher_all : public matcher
{
bool match(const logger& logger) const override;
bool match(const consumer& consumer) const override;
};

}
}

+ 20
- 0
src/cpputils/logging/matcher/matcher_default.h View File

@@ -0,0 +1,20 @@
#pragma once

#include <cpputils/logging/matcher/matcher.h>

namespace utl {
namespace logging {

struct matcher_default : public matcher
{
private:
logger& _defaultLogger;

public:
using matcher::match;
bool match(const logger& logger) const override;
matcher_default();
};

}
}

+ 23
- 0
src/cpputils/logging/matcher/matcher_regex.h View File

@@ -0,0 +1,23 @@
#pragma once

#include <regex>

#include <cpputils/logging/matcher/matcher.h>

namespace utl {
namespace logging {

struct matcher_regex : public matcher
{
private:
std::regex _regex;
bool _invert;

public:
bool match(const logger& logger) const override;
bool match(const consumer& consumer) const override;
matcher_regex(const std::string expression, bool invert = false);
};

}
}

+ 63
- 0
src/cpputils/logging/rule.h View File

@@ -0,0 +1,63 @@
#pragma once

#include <set>
#include <mutex>

#include <cpputils/logging/matcher/matcher.h>
#include <cpputils/logging/consumer/consumer.h>

namespace utl {
namespace logging {

struct rule
{
private:
mutable std::mutex _mutex;
std::set<consumer*> _consumer;

public:
matcher_ptr_u logger_matcher;
matcher_ptr_u consumer_matcher;
log_level min_level;
log_level max_level;

inline bool is_enabled(log_level level) const
{
return min_level <= level
&& max_level >= level;
}

inline void register_consumer(consumer& consumer)
{
std::lock_guard<std::mutex> lk(_mutex);
_consumer.insert(&consumer);
}

inline void unregister_consumer(consumer& consumer)
{
std::lock_guard<std::mutex> lk(_mutex);
_consumer.erase(&consumer);
}

inline void log(data_ptr_s data)
{
std::lock_guard<std::mutex> lk(_mutex);
if (is_enabled(data->level))
{
for (auto& c : _consumer)
c->log(data);
}
}

rule(matcher_ptr_u lm, matcher_ptr_u cm, log_level min, log_level max) :
logger_matcher (std::move(lm)),
consumer_matcher(std::move(cm)),
min_level (min),
max_level (max)
{ }
};

using rule_handle = void*;

}
}

+ 31
- 0
src/cpputils/logging/types.h View File

@@ -0,0 +1,31 @@
#pragma once

#include <chrono>
#include <thread>

namespace utl {
namespace logging {

enum class log_level
{
debug = 0,
info,
warn,
error,
};

struct data
{
log_level level;
std::chrono::steady_clock::time_point time;
void* sender;
std::thread::id thread;
const char* file;
int line;
std::string name;
std::string message;
};
using data_ptr_s = std::shared_ptr<data>;

}
}

+ 14
- 0
src/cpputils/misc.h View File

@@ -0,0 +1,14 @@
#pragma once

#include <cpputils/misc/convert.h>
#include <cpputils/misc/enum.h>
#include <cpputils/misc/exception.h>
#include <cpputils/misc/flags.h>
#include <cpputils/misc/indent.h>
#include <cpputils/misc/misc.h>
#include <cpputils/misc/stream.h>
#include <cpputils/misc/string.h>
#include <cpputils/misc/time.h>
#include <cpputils/misc/transform_iterator.h>
#include <cpputils/misc/type_helper.h>
#include <cpputils/misc/wrapper.h>

+ 63
- 0
src/cpputils/misc/convert.h View File

@@ -0,0 +1,63 @@
#pragma once

namespace utl
{

namespace __impl
{
template<class T, size_t N = sizeof(T)>
struct network_convert_helper;
}

template<class T>
inline T hton(const T& value)
{ return __impl::network_convert_helper<T>::hton(value); }

template<class T>
inline T ntoh(const T& value)
{ return __impl::network_convert_helper<T>::ntoh(value); }

namespace __impl
{
template<class T>
struct network_convert_helper<T, 1>
{
static inline T hton(const T& t)
{ return t; }

static inline T ntoh(const T& t)
{ return t; }
};

template<class T>
struct network_convert_helper<T, 2>
{
static inline T hton(const T& t)
{ return reinterpret_cast<T>(htobe16(reinterpret_cast<uint16_t>(t))); }

static inline T ntoh(const T& t)
{ return reinterpret_cast<T>(be16toh(reinterpret_cast<uint16_t>(t))); }
};

template<class T>
struct network_convert_helper<T, 4>
{
static inline T hton(const T& t)
{ return reinterpret_cast<T>(htobe32(reinterpret_cast<uint32_t>(t))); }

static inline T ntoh(const T& t)
{ return reinterpret_cast<T>(be32toh(reinterpret_cast<uint32_t>(t))); }
};

template<class T>
struct network_convert_helper<T, 8>
{
static inline T hton(const T& t)
{ return reinterpret_cast<T>(htobe64(reinterpret_cast<uint64_t>(t))); }

static inline T ntoh(const T& t)
{ return reinterpret_cast<T>(be64toh(reinterpret_cast<uint64_t>(t))); }
};
}

}

src/cpputils/EnumConversion.h → src/cpputils/misc/enum.h View File

@@ -3,9 +3,10 @@
#include <map>
#include <type_traits>

#include "Exception.h"
#include <cpputils/misc/string.h>
#include <cpputils/misc/exception.h>

#define DefEnumToStringMap(enum, ...) \
#define DEFINE_ENUM_TO_STRING_MAP(enum, ...) \
namespace utl { \
namespace __impl { \
template<> \
@@ -21,7 +22,7 @@
} \
}; } }

#define DefStringToEnumMap(enum, less, ...) \
#define DEFINE_STRING_TO_ENUM_MAP(enum, less, ...) \
namespace utl { \
namespace __impl { \
template<> \
@@ -37,7 +38,7 @@
} \
}; } }

#define DefDefaultEnumValue(enum, value) \
#define DEFINE_DEFAULT_ENUM_VALUE(enum, value) \
namespace utl { \
namespace __impl { \
template<> \
@@ -99,23 +100,23 @@ namespace utl
struct default_enum_value
{
static inline T value()
{ throw Exception("unable to convert string to enum"); }
{ throw exception("unable to convert string to enum"); }
};
}

using InvariantStringLess = __impl::invariant_string_less;
using invariant_string_less = __impl::invariant_string_less;

template<class T>
struct EnumConversion
struct enum_conversion
{
using map_enum_to_string = __impl::map_enum_to_string<T>;
using map_string_to_enum = __impl::map_string_to_enum<T>;
using default_enum_value = __impl::default_enum_value<T>;
using base_type = typename std::underlying_type<T>::type;
using map_enum_to_string_type = __impl::map_enum_to_string<T>;
using map_string_to_enum_type = __impl::map_string_to_enum<T>;
using default_enum_value_type = __impl::default_enum_value<T>;
using base_type = typename std::underlying_type<T>::type;

static inline std::string toString(T value, bool addValue)
static inline std::string to_string(T value, bool addValue)
{
static const auto& map = map_enum_to_string::value();
static const auto& map = map_enum_to_string_type::value();
auto it = map.find(value);
std::string ret;
if (it != map.end())
@@ -129,9 +130,9 @@ namespace utl
return ret;
}

static inline bool tryToEnum(const std::string& str, T& value, bool acceptNumeric)
static inline bool try_to_enum(const std::string& str, T& value, bool acceptNumeric)
{
static const auto& map = map_string_to_enum::value();
static const auto& map = map_string_to_enum_type::value();
auto it = map.find(str);
if (it != map.end())
{
@@ -146,13 +147,30 @@ namespace utl
return (c != e);
}

static inline T toEnum(const std::string& str)
static inline T to_enum(const std::string& str)
{
T value;
return tryToEnum(str, value)
return try_to_enum(str, value)
? value
: default_enum_value::value();
: default_enum_value_type::value();
}
};

namespace __impl
{
template<class T>
struct op_to_string<T, typename std::enable_if<std::is_enum<T>::value>::type>
{
inline void operator()(std::ostream& os, const T& s) const
{ os << enum_conversion<T>::to_string(s, true); }
};

template<class T>
struct op_from_string<T, typename std::enable_if<std::is_enum<T>::value>::type>
{
inline bool operator()(const std::string& s, T& value) const
{ return enum_conversion<T>::try_to_enum(s, value, true); }
};
}

}

+ 168
- 0
src/cpputils/misc/exception.h View File

@@ -0,0 +1,168 @@
#pragma once

#include <string>
#include <cstdint>
#include <iomanip>
#include <string.h>
#include <execinfo.h>

#include "flags.h"

namespace utl
{

struct exception : public std::exception
{
public:
enum class print_flag
{
ResolveAddress,
};
using print_flags = shifted_flags<print_flag>;

public:
static constexpr size_t max_stack_size = 15;
static const print_flags& default_print_flag()
{
static const print_flags value({ print_flag::ResolveAddress });
return value;
};

private:
mutable bool _msg_cache_empty;
mutable std::string _msg_cache;

protected:
virtual void print_message(std::ostream& os) const
{
os << message;
}

public:
std::string message;
void* stack[max_stack_size];
int stack_size;

public:
void print(std::ostream& os, const print_flags& flags = default_print_flag()) const
{
print_message(os);
os << std::endl;
char** lines = nullptr;
if (flags.is_set(print_flag::ResolveAddress))
lines = backtrace_symbols(stack, stack_size);
for (int i = 0; i < stack_size; ++i)
{
os << " [0x" << std::setw(2 * sizeof(void*)) << std::setfill('0') << std::hex << reinterpret_cast<uintptr_t>(stack[i]) << "]";
if (lines && lines[i])
os << " " << lines[i];
os << std::endl;
}
}

std::string print(const print_flags& flags = default_print_flag()) const
{
std::ostringstream os;
print(os, flags);
return os.str();
}

const char* what() const throw() override
{
if (_msg_cache_empty)
{
_msg_cache = print();
_msg_cache_empty = false;
}
return _msg_cache.c_str();
}

inline friend std::ostream& operator <<(std::ostream& os, const exception& ex)
{
ex.print(os);
return os;
}

public:
exception() :
exception("")
{ }

exception(std::string msg) :
message (msg),
stack_size (0),
_msg_cache_empty(true)
{
stack_size = backtrace(&stack[0], max_stack_size);
}
};

struct error_exception : public exception
{
public:
int error;

error_exception(int e) :
exception(std::to_string(e) + " - " + strerror(e)),
error(e)
{ }

error_exception(const std::string& msg, int e) :
exception(msg + ": " + std::to_string(e) + " - " + strerror(e)),
error(e)
{ }
};

struct out_of_range_exception : public exception
{
protected:
void print_message(std::ostream& os) const override
{
os << "index out of range (min=" << min << "; max=" << max << "; index=" << index << ")";
if (!message.empty())
os << " - " << message;
}

public:
size_t min;
size_t max;
size_t index;

out_of_range_exception(size_t mi, size_t ma, size_t idx, std::string msg = "") :
exception (msg),
min (mi),
max (ma),
index (idx)
{ }
};

struct argument_exception : public exception
{
protected:
void print_message(std::ostream& os) const override
{
os << "invalid argument";
if (!argument.empty())
os << "(" << argument << ")";
if (!message.empty())
os << " - " << message;
}

public:
std::string argument;

argument_exception(std::string arg, std::string msg) :
exception (msg),
argument (arg)
{ }
};

struct invalid_operation_exception : public exception
{
public:
invalid_operation_exception(std::string msg) :
exception(msg)
{ }
};

}

src/cpputils/Flags.h → src/cpputils/misc/flags.h View File

@@ -9,14 +9,14 @@ namespace utl
template<class TEnum, class TBase>
struct op_flag_convert_none
{
static inline TBase toBase(const TEnum e)
static inline TBase to_base(const TEnum e)
{ return static_cast<TBase>(e); }
};

template<class TEnum, class TBase>
struct op_flag_convert_shift
{
static inline TBase toBase(const TEnum e)
static inline TBase to_base(const TEnum e)
{ return static_cast<TBase>(1 << static_cast<int>(e)); }
};

@@ -24,20 +24,20 @@ namespace utl
class TEnum,
class TBase = typename std::underlying_type<TEnum>::type,
class Op = op_flag_convert_none<TEnum, TBase>>
struct Flags
struct flags
{
public:
TBase value;

public:
inline bool isSet(TEnum e) const
{ return static_cast<bool>(value & Op::toBase(e)); }
inline bool is_set(TEnum e) const
{ return static_cast<bool>(value & Op::to_base(e)); }

inline void set(TEnum e)
{ value = static_cast<TBase>(value | Op::toBase(e)); }
{ value = static_cast<TBase>(value | Op::to_base(e)); }

inline void clear(TEnum e)
{ value = static_cast<TBase>(value & ~Op::toBase(e)); }
{ value = static_cast<TBase>(value & ~Op::to_base(e)); }

inline void reset()
{ value = 0; }
@@ -50,42 +50,42 @@ namespace utl
{ return static_cast<bool>(value); }

bool operator[](TEnum e) const
{ return isSet(e); }
{ return is_set(e); }

public:
Flags() :
flags() :
value(0)
{ }

explicit Flags(TBase v) :
explicit flags(TBase v) :
value(v)
{ }

Flags(TEnum e) :
value(Op::toBase(e))
flags(TEnum e) :
value(Op::to_base(e))
{ }

Flags(const Flags& other) :
flags(const flags& other) :
value(other.value)
{ }

Flags(std::initializer_list<TEnum> list) :
Flags()
flags(std::initializer_list<TEnum> list) :
flags()
{
for (auto& e : list)
set(e);
}

public:
static inline const Flags& empty()
static inline const flags& empty()
{
static const Flags value(0);
static const flags value(0);
return value;
}

static inline const Flags& all()
static inline const flags& all()
{
static const Flags value(std::numeric_limits<TBase>::max());
static const flags value(std::numeric_limits<TBase>::max());
return value;
}
};
@@ -93,11 +93,11 @@ namespace utl
template<
class TEnum,
class TBase = typename std::underlying_type<TEnum>::type>
using ShiftedFlags = Flags<TEnum, TBase, op_flag_convert_shift<TEnum, TBase>>;
using shifted_flags = flags<TEnum, TBase, op_flag_convert_shift<TEnum, TBase>>;

template<
class TEnum,
class TBase = typename std::underlying_type<TEnum>::type>
using SimpleFlags = Flags<TEnum, TBase, op_flag_convert_none<TEnum, TBase>>;
using simple_flags = flags<TEnum, TBase, op_flag_convert_none<TEnum, TBase>>;

}

+ 39
- 0
src/cpputils/misc/indent.h View File

@@ -0,0 +1,39 @@
#pragma once

#include <iostream>

namespace utl
{

namespace __impl
{
inline int indent_stream_index()
{
const int value = std::ios::xalloc();
return value;
}
}

inline std::ostream& incindent(std::ostream& os)
{
++os.iword(__impl::indent_stream_index());
return os;
}

inline std::ostream& decindent(std::ostream& os)
{
auto& indent = os.iword(__impl::indent_stream_index());
if (--indent < 0)
indent = 0;
return os;
}

inline std::ostream& indent(std::ostream& os)
{
auto i = os.iword(__impl::indent_stream_index());
while (i--)
os << " ";
return os;
}

}

src/cpputils/Linq.h → src/cpputils/misc/linq.h View File

@@ -4,21 +4,23 @@
#include <map>
#include <list>
#include <vector>
#include <cassert>
#include <algorithm>

#include "Misc.h"
#include "Nullable.h"
#include "Exception.h"
#include "mp/core.h"
#include <cpputils/mp/core.h>
#include <cpputils/misc/exception.h>
#include <cpputils/container/wrapper.h>
#include <cpputils/container/nullable.h>

// #define LINQ_DEBUG

#ifdef LINQ_DEBUG
#include "Misc.h"
#define LINQ_TYPE_NAME() utl::TypeHelper<decltype(*this)>::name()
#define LINQ_CTOR() do { std::cout << "CTOR(this=" << this << ")" << LINQ_TYPE_NAME() << std::endl; } while(0)
#define LINQ_COPY_CTOR() do { std::cout << "COPY(this=" << this << ")" << LINQ_TYPE_NAME() << std::endl; } while(0)
#define LINQ_MOVE_CTOR() do { std::cout << "MOVE(this=" << this << ")" << LINQ_TYPE_NAME() << std::endl; } while(0)
#define LINQ_DTOR() do { std::cout << "DTOR(this=" << this << ")" << LINQ_TYPE_NAME() << std::endl; } while(0)
#include <cpputils/misc/type_helper.h>
#define LINQ_TYPE_NAME() utl::type_helper<decltype(*this)>::name()
#define LINQ_CTOR() do { std::cout << "CTOR " << ++::utl::linq::__impl::ref_counter<decltype(*this)>::value() << "(this=" << this << ")" << LINQ_TYPE_NAME() << std::endl; } while(0)
#define LINQ_COPY_CTOR() do { std::cout << "COPY " << ++::utl::linq::__impl::ref_counter<decltype(*this)>::value() << "(this=" << this << ")" << LINQ_TYPE_NAME() << std::endl; } while(0)
#define LINQ_MOVE_CTOR() do { std::cout << "MOVE " << ++::utl::linq::__impl::ref_counter<decltype(*this)>::value() << "(this=" << this << ")" << LINQ_TYPE_NAME() << std::endl; } while(0)
#define LINQ_DTOR() do { std::cout << "DTOR " << --::utl::linq::__impl::ref_counter<decltype(*this)>::value() << "(this=" << this << ")" << LINQ_TYPE_NAME() << std::endl; } while(0)
#else
#define LINQ_TYPE_NAME() while(0)
#define LINQ_CTOR() while(0)
@@ -27,10 +29,23 @@
#define LINQ_DTOR() while(0)
#endif

namespace linq
{
namespace utl{
namespace linq {

namespace __impl
{
#ifdef LINQ_DEBUG
template<typename... T>
struct ref_counter
{
static inline size_t& value()
{
static size_t value = 0;
return value;
}
};
#endif

struct tag_range { };
struct tag_builder { };

@@ -220,7 +235,7 @@ namespace linq
assert(current != end);
return value_type(
*current->first,
std::move(container.createRange(range_indices)));
container.createRange(range_indices));
}

inline bool next()
@@ -315,11 +330,11 @@ namespace linq

template<class TBuilder>
inline auto operator >> (TBuilder&& builder) &
{ return builder.build(std::move(lookup_key_value_range(*this))); }
{ return builder.build(lookup_key_value_range(*this)); }

template<class TBuilder>
inline auto operator >> (TBuilder&& builder) &&
{ return builder.build(std::move(lookup_key_value_range(std::move(*this)))); }
{ return builder.build(lookup_key_value_range(std::move(*this))); }

private:
inline lookup(keys_type&& k, values_type&& v) :
@@ -606,7 +621,7 @@ namespace linq
using this_type = select_range<range_type, predicate_type>;
using range_value_type = mp_range_value_type<range_type>;
using value_type = decltype(std::declval<predicate_type>()(std::declval<range_value_type>()));
using cache_type = utl::Nullable<value_type>;
using cache_type = utl::nullable<value_type>;

predicate_type predicate;
range_type range;
@@ -670,12 +685,12 @@ namespace linq
using this_type = where_range<range_type, predicate_type>;
using range_value_type = mp_range_value_type<range_type>;
using predicate_return_type = decltype(std::declval<predicate_type>()(std::declval<range_value_type>()));
using inner_range_type = utl::mp::eval_if<
using inner_range_type = utl::mp::eval_if_t<
std::is_base_of<tag_range, predicate_return_type>,
predicate_return_type,
mp_make_inner_range, predicate_return_type>;
using value_type = mp_range_value_type<inner_range_type>;
using inner_range_cache_type = utl::Nullable<inner_range_type>;
using inner_range_cache_type = utl::nullable<inner_range_type>;

predicate_type predicate;
range_type range;
@@ -757,7 +772,7 @@ namespace linq
inline value_type& front()
{
assert(current >= 0 && static_cast<size_t>(current) < values.size());
return *values.at(current);
return *values.at(static_cast<typename vector_type::size_type>(current));
}

inline bool next()
@@ -1179,10 +1194,10 @@ namespace linq
using range_value_type = mp_range_value_type<TRange>;

if (!range.next())
throw utl::Exception("range is empty");
throw utl::exception("range is empty");
auto ret = std::forward<range_value_type>(range.front());
if (range.next())
throw utl::Exception("range contains more than one value");
throw utl::exception("range contains more than one value");
return ret;
}
};
@@ -1210,7 +1225,7 @@ namespace linq
{
using range_value_type = mp_range_value_type<TRange>;
if (!range.next())
throw utl::Exception("range is empty");
throw utl::exception("range is empty");
return std::forward<range_value_type>(range.front());
}
};
@@ -1281,7 +1296,7 @@ namespace linq
while(range.next())
tmp = std::forward<range_value_type>(range.front());
if (!static_cast<bool>(tmp))
throw utl::Exception("range is empty");
throw utl::exception("range is empty");
return std::forward<range_value_type>(*tmp);
}
};
@@ -1318,7 +1333,7 @@ namespace linq
vector_type ret;
ret.reserve(capacity);
while (range.next())
ret.emplace_back(std::move(range.front()));
ret.emplace_back(std::forward<range_value_type>(range.front()));
return ret;
}

@@ -1338,7 +1353,7 @@ namespace linq

list_type ret;
while (range.next())
ret.emplace_back(std::move(range.front()));
ret.emplace_back(std::forward<range_value_type>(range.front()));
return ret;
}
};
@@ -1369,7 +1384,7 @@ namespace linq
key_predicate(range.front()),
value_predicate(range.front()));
if (!ret.second)
throw utl::Exception("duplicate key in range");
throw utl::exception("duplicate key in range");
}
return map;
}
@@ -1590,10 +1605,10 @@ namespace linq

template<class TKeyPredicate>
inline auto to_map(TKeyPredicate&& kp)
{ return to_map(std::forward<TKeyPredicate>(kp), std::move(op_select_value_default())); }
{ return to_map(std::forward<TKeyPredicate>(kp), op_select_value_default()); }

inline auto to_map()
{ return to_map(std::move(op_select_key_default()), std::move(op_select_value_default())); }
{ return to_map(op_select_key_default(), op_select_value_default()); }

template<class TPredicate>
inline auto for_each(TPredicate&& p)
@@ -1605,14 +1620,16 @@ namespace linq

template<class TKeyPredicate>
inline auto to_lookup(TKeyPredicate&& kp)
{ return to_lookup(std::forward<TKeyPredicate>(kp), std::move(op_select_value_default())); }
{ return to_lookup(std::forward<TKeyPredicate>(kp), op_select_value_default()); }

inline auto to_lookup()
{ return to_lookup(std::move(op_select_key_default()), std::move(op_select_value_default())); }
{ return to_lookup(op_select_key_default(), op_select_value_default()); }

template <class TKey, class TValue>
using lookup_value_range_type = typename __impl::lookup<TKey, TValue>::lookup_range_wrapper;

template <class TKey, class TValue>
using lookup_key_value_range_type = typename __impl::lookup<TKey, TValue>::lookup_key_value_range_wrapper;

}
}

+ 35
- 0
src/cpputils/misc/misc.h View File

@@ -0,0 +1,35 @@
#pragma once

#include <cxxabi.h>
#include <iostream>

#if defined(__linux__)
# include <endian.h>
#elif defined(__FreeBSD__) || defined(__NetBSD__)
# include <sys/endian.h>
#elif defined(__OpenBSD__)
# include <sys/types.h>
# define be16toh(x) betoh16(x)
# define be32toh(x) betoh32(x)
# define be64toh(x) betoh64(x)
#endif

namespace utl
{

inline int bit_count(uint32_t u)
{
u = u
- ((u >> 1) & 033333333333)
- ((u >> 2) & 011111111111);
return ((u + (u >> 3)) & 030707070707) % 63;
}

template<class T, class S>
inline bool try_cast(T* t, S*& s)
{
s = dynamic_cast<S*>(t);
return static_cast<bool>(s);
}

}

src/cpputils/StreamHelper.h → src/cpputils/misc/stream.h View File

@@ -1,7 +1,7 @@
#pragma once

#include <iostream>
#include "Exception.h"
#include "exception.h"

namespace utl
{
@@ -14,10 +14,10 @@ namespace utl
inline void operator()(std::ostream& os, const T& t)
{
if (!os)
throw Exception("unable to write data to stream: invalid stream");
throw exception("unable to write data to stream: invalid stream");
os.write(reinterpret_cast<const char*>(&t), sizeof(t));
if (!os)
throw Exception("unable to write data to stream: stream error");
throw exception("unable to write data to stream: stream error");
}
};

@@ -27,11 +27,11 @@ namespace utl
inline void operator()(std::istream& is, T& t)
{
if (!is)
throw Exception("unable to read data from stream: invalid stream");
throw exception("unable to read data from stream: invalid stream");
if (is.read(reinterpret_cast<char*>(&t), sizeof(t)).gcount() != sizeof(t))
throw Exception("unable to read data from stream: EOF");
throw exception("unable to read data from stream: EOF");
if (!is)
throw Exception("unable to read data from stream: stream error");
throw exception("unable to read data from stream: stream error");
}
};

@@ -41,13 +41,13 @@ namespace utl
inline void operator()(std::ostream& os, const std::string& t)
{
if (t.size() > std::numeric_limits<uint32_t>::max())
throw Exception("unable to write data to stream: string is to large");
throw exception("unable to write data to stream: string is to large");
op_write_stream<uint32_t, void>()(os, static_cast<uint32_t>(t.size()));
if (!os)
throw Exception("unable to write data to stream: invalid stream");
os.write(t.data(), t.size());
throw exception("unable to write data to stream: invalid stream");
os.write(t.data(), static_cast<std::streamsize>(t.size()));
if (!os)
throw Exception("unable to write data to stream: stream error");
throw exception("unable to write data to stream: stream error");
}
};

@@ -59,13 +59,13 @@ namespace utl
uint32_t sz;
op_read_stream<uint32_t, void>()(is, sz);
if (!is)
throw Exception("unable to read data from stream: invalid stream");
throw exception("unable to read data from stream: invalid stream");
std::string tmp;
tmp.resize(sz);
if (is.read(const_cast<char*>(tmp.data()), sz).gcount() != sz)
throw Exception("unable to read data from stream: EOF");
throw exception("unable to read data from stream: EOF");
if (!is)
throw Exception("unable to read data from stream: stream error");
throw exception("unable to read data from stream: stream error");
t = std::move(tmp);
}
};
@@ -85,7 +85,7 @@ namespace utl
};
}

struct StreamHelper
struct stream_helper
{
template<class T>
static inline void write(std::ostream& os, const T& t)
@@ -104,4 +104,18 @@ namespace utl
}
};

struct stream_format_saver
{
std::ios state;
std::ostream& stream;

stream_format_saver(std::ostream& s) :
state (nullptr),
stream (s)
{ state.copyfmt(stream); }

~stream_format_saver()
{ stream.copyfmt(state); }
};

}

src/cpputils/StringHelper.h → src/cpputils/misc/string.h View File

@@ -1,8 +1,7 @@
#pragma once

#include <sstream>
#include "Nullable.h"
#include "EnumConversion.h"
#include <cpputils/misc/exception.h>

namespace utl
{
@@ -17,39 +16,19 @@ namespace utl
};

template<class T>
struct op_to_string<T, decltype(std::declval<T>().toString(std::declval<std::ostream&>()), void())>
struct op_to_string<T, decltype(std::declval<T>().to_string(std::declval<std::ostream&>()), void())>
{
inline void operator()(std::ostream& os, const T& s) const
{ s.toString(os); }
{ s.to_string(os); }
};

template<class T>
struct op_to_string<T, decltype(std::declval<T>().toString(), void())>
struct op_to_string<T, decltype(std::declval<T>().to_string(), void())>
{
inline void operator()(std::ostream& os, const T& s) const
{ os << s.toString(); }
{ os << s.to_string(); }
};

template<class T>
struct op_to_string<T, typename std::enable_if<std::is_enum<T>::value>::type>
{
inline void operator()(std::ostream& os, const T& s) const
{ os << EnumConversion<T>::toString(s, true); }
};

template<class T>
struct op_to_string<Nullable<T>, void>
{
inline void operator()(std::ostream& os, const Nullable<T>& s) const
{
if (s.hasValue())
op_to_string<T>()(os, s.value());
else
os << "null";
}
};


template<class T, class Enable = void>
struct op_from_string
{
@@ -82,24 +61,17 @@ namespace utl
};

template<class T>
struct op_from_string<T, decltype(std::declval<T&>().fromString(std::declval<const std::string&>()), void())>
{
inline bool operator()(const std::string& s, T& value) const
{ return value.fromString(s); }
};

template<class T>
struct op_from_string<T, decltype(T::fromString(std::declval<const std::string&>(), std::declval<T&>()), void())>
struct op_from_string<T, decltype(std::declval<T&>().from_string(std::declval<const std::string&>()), void())>
{
inline bool operator()(const std::string& s, T& value) const
{ return T::fromString(s, value); }
{ return value.from_string(s); }
};

template<class T>
struct op_from_string<T, typename std::enable_if<std::is_enum<T>::value>::type>
struct op_from_string<T, decltype(T::from_string(std::declval<const std::string&>(), std::declval<T&>()), void())>
{
inline bool operator()(const std::string& s, T& value) const
{ return EnumConversion<T>::tryToEnum(s, value, true); }
{ return T::from_string(s, value); }
};

template<class T>
@@ -128,42 +100,42 @@ namespace utl
}

template<class T>
inline void toString(std::ostream& os, const T& t)
inline void to_string(std::ostream& os, const T& t)
{ __impl::op_to_string<T>()(os, t); }

template<class T>
inline std::string toString(const T& t)
inline std::string to_string(const T& t)
{
std::ostringstream ss;
toString(ss, t);
to_string(ss, t);
return ss.str();
}

template<>
inline std::string toString<std::string>(const std::string& s)
inline std::string to_string<std::string>(const std::string& s)
{ return s; }



template<class T>
inline bool tryFromString(const std::string& s, T& value)
inline bool try_from_string(const std::string& s, T& value)
{ return __impl::op_from_string<T>()(s, value); }

template<class T>
inline T fromString(const std::string& s, T defaultValue)
inline T from_string(const std::string& s, T defaultValue)
{
T tmp;
return tryFromString<T>(s, tmp)
return try_from_string<T>(s, tmp)
? tmp
: defaultValue;
}

template<class T>
inline T fromString(const std::string& s)
inline T from_string(const std::string& s)
{
T tmp;
if (!tryFromString<T>(s, tmp))
throw Exception(std::string("unable to convert string to specific value: ") + s);
if (!try_from_string<T>(s, tmp))
throw exception(std::string("unable to convert string to specific value: ") + s);
return tmp;
}


src/cpputils/Time.h → src/cpputils/misc/time.h View File

@@ -20,7 +20,7 @@ namespace utl
const std::chrono::seconds sec = std::chrono::duration_cast<std::chrono::seconds>(d);
tv.tv_sec = sec.count();
tv.tv_usec = std::chrono::duration_cast<std::chrono::microseconds>(d - sec).count();
return std::move(tv);
return tv;
}

};
@@ -44,7 +44,7 @@ namespace utl
const std::chrono::seconds sec = std::chrono::duration_cast<std::chrono::seconds>(d);
ts.tv_sec = sec.count();
ts.tv_nsec = std::chrono::duration_cast<std::chrono::nanoseconds>(d - sec).count();
return std::move(ts);
return ts;
}

};

src/cpputils/TransformIterator.h → src/cpputils/misc/transform_iterator.h View File

@@ -10,13 +10,13 @@ namespace utl
}

template<class It, class Transform, class Enable = void>
struct TransformIterator;
struct transform_iterator;

template<class It, class Transform>
struct TransformIterator<It, Transform, __impl::mp_enable_if_has_iterator_tag<It, std::forward_iterator_tag>>
struct transform_iterator<It, Transform, __impl::mp_enable_if_has_iterator_tag<It, std::forward_iterator_tag>>
{
public:
using iterator_type = TransformIterator;
using iterator_type = transform_iterator;
using iterator_category = std::input_iterator_tag;
using difference_type = typename It::difference_type;
using return_type = decltype(std::declval<Transform>()(std::declval<typename It::reference>()));
@@ -29,10 +29,10 @@ namespace utl
Transform _transform;

public:
TransformIterator()
transform_iterator()
{ }

TransformIterator(It it, Transform transform) :
transform_iterator(It it, Transform transform) :
_it (it),
_transform (transform)
{ }
@@ -66,10 +66,10 @@ namespace utl
};

template<class It, class Transform>
struct TransformIterator<It, Transform, __impl::mp_enable_if_has_iterator_tag<It, std::bidirectional_iterator_tag>>
struct transform_iterator<It, Transform, __impl::mp_enable_if_has_iterator_tag<It, std::bidirectional_iterator_tag>>
{
public:
using iterator_type = TransformIterator;
using iterator_type = transform_iterator;
using iterator_category = std::input_iterator_tag;
using difference_type = typename It::difference_type;
using return_type = decltype(std::declval<Transform>()(std::declval<typename It::reference>()));
@@ -82,10 +82,10 @@ namespace utl
Transform _transform;

public:
TransformIterator()
transform_iterator()
{ }

TransformIterator(It it, Transform transform) :
transform_iterator(It it, Transform transform) :
_it (it),
_transform (transform)
{ }
@@ -128,10 +128,10 @@ namespace utl
};

template<class It, class Transform>
struct TransformIterator<It, Transform, __impl::mp_enable_if_has_iterator_tag<It, std::random_access_iterator_tag>>
struct transform_iterator<It, Transform, __impl::mp_enable_if_has_iterator_tag<It, std::random_access_iterator_tag>>
{
public:
using iterator_type = TransformIterator;
using iterator_type = transform_iterator;
using iterator_category = std::input_iterator_tag;
using difference_type = typename It::difference_type;
using return_type = decltype(std::declval<Transform>()(std::declval<typename It::reference>()));
@@ -144,10 +144,10 @@ namespace utl
Transform _transform;

public:
TransformIterator()
transform_iterator()
{ }

TransformIterator(It it, Transform transform) :
transform_iterator(It it, Transform transform) :
_it (it),
_transform (transform)
{ }
@@ -226,11 +226,11 @@ namespace utl
};

template<class It, class Transform>
TransformIterator<It, Transform> makeTransformIterator(const It& it, const Transform& transform)
{ return TransformIterator<It, Transform>(it, transform); }
transform_iterator<It, Transform> make_transform_iterator(const It& it, const Transform& transform)
{ return transform_iterator<It, Transform>(it, transform); }

template<class It, class Transform, __impl::mp_enable_if_has_iterator_tag<It, std::random_access_iterator_tag, int> = 0>
inline TransformIterator<It, Transform>
operator+(const typename TransformIterator<It, Transform>::difference_type& n, const TransformIterator<It, Transform>& it)
inline transform_iterator<It, Transform>
operator+(const typename transform_iterator<It, Transform>::difference_type& n, const transform_iterator<It, Transform>& it)
{ return it + n; }
}

+ 20
- 0
src/cpputils/misc/type_helper.h View File

@@ -0,0 +1,20 @@
#pragma once

#include <cxxabi.h>

namespace utl
{

template<class T>
struct type_helper
{
public:
static inline std::string name()
{
int status;
auto name = abi::__cxa_demangle(typeid(T).name(), 0, 0, &status);
return std::string(name ? name : typeid(T).name());
}
};

}

+ 7
- 0
src/cpputils/mp.h View File

@@ -0,0 +1,7 @@
#pragma once

#include <cpputils/mp/core.h>
#include <cpputils/mp/util.h>
#include <cpputils/mp/intern.h>
#include <cpputils/mp/container.h>
#include <cpputils/mp/operations.h>

+ 0
- 980
src/cpputils/mp/MetaProgramming.h.old View File

@@ -1,980 +0,0 @@
#pragma once

#include <tuple>
#include <string>
#include <cstdlib>
#include <cstdint>
#include <type_traits>

#define MP_DEBUG

#if defined __GNUC__
# define LIKELY(EXPR) __builtin_expect(!!(EXPR), 1)
#else
# define LIKELY(EXPR) (!!(EXPR))
#endif

#if defined MP_DEBUG
# define X_ASSERT(CHECK) void(0)
#else
# define X_ASSERT(CHECK) ( LIKELY(CHECK) ? void(0) : []{assert(!#CHECK);}() )
#endif

namespace utl
{

/* types */
template<class T, T t>
using mp_const = std::integral_constant<T, t>;

template<bool B>
using mp_bool = mp_const<bool, B>;

template<size_t S>
using mp_size_t = mp_const<size_t, S>;

template<class...>
struct mp_list { };

template<class T>
struct mp_identity
{ using type = T; };

template<class... T>
struct mp_inherit : T...
{ };

template<class T, T... Ints>
struct mp_integer_sequence
{ };

template<size_t... Ints>
using mp_index_sequence = mp_integer_sequence<size_t, Ints...>;



/* constants */
using mp_true = mp_bool<true>;
using mp_false = mp_bool<false>;
using mp_zero = mp_size_t<0>;



/* modifier */
template<class T>
using mp_add_pointer = T*;

template<class T>
using mp_add_reference = T&;

template<class T>
using mp_remove_ptr = typename std::remove_pointer<T>::type;

template<class T>
using mp_remove_const = typename std::remove_const<T>::type;

template<class T>
using mp_remove_cv = typename std::remove_cv<T>::type;

template<class T>
using mp_remove_ref = typename std::remove_reference<T>::type;

template<class T>
using mp_clean_type = mp_remove_cv<mp_remove_ptr<mp_remove_ref<T>>>;



/* conditionals */
template<class T, class S>
using mp_is_same = mp_bool<std::is_same<T, S>::value>;

template<class Base, class Derived>
using mp_is_base_of = mp_bool<std::is_base_of<Base, Derived>::value>;

template<class T, class S = void>
using mp_enable_if = typename std::enable_if<T::value, S>::type;

template<bool B, class S = void>
using mp_enable_if_c = typename std::enable_if<B, S>::type;



namespace __impl
{
/* logical operations */
template<bool C, class T, class E>
struct mp_if_c_impl;

template<bool C, class T, template<class...> class E, class... A>
struct mp_eval_if_c_impl;

template<class L>
struct mp_not_impl;

template<class L>
struct mp_and_impl;

template<class L>
struct mp_or_impl;



/* arithmetic */
template<class L>
struct mp_plus_impl;

template<class L>
struct mp_minus_impl;

template<class L>
struct mp_multiply_impl;

template<class L>
struct mp_divide_impl;



/* generator functions */
template<class S>
struct next_integer_sequence;

template<class T, T I, T N>
struct mp_make_int_seq_impl;

template<size_t N, class... T>
struct mp_repeat_impl;



/* list operations returning a numeric value */
template<class L>
struct mp_size_impl;

template<class L, class V>
struct mp_count_impl;

template<class L, template<class...> class P>
struct mp_count_if_impl;



/* operations to manipulate list content */
template<class L, class... T>
struct mp_push_front_impl;

template<class L>
struct mp_pop_front_impl;

template<class L, class... T>
struct mp_push_back_impl;

template<class... L>
struct mp_concat_impl;

template<class L, template<class> class F>
struct mp_filter_impl;



/* list operations returning a bool value */
template<class... L>
struct mp_empty_impl;

template<class L, class V>
struct mp_contains_impl;



/* list operations returing elements from the list */
template<class L>
struct mp_front_impl;

template<class L>
struct mp_second_impl;

template<class L, size_t I>
struct mp_at_c_impl;

template<class L, template<class> class F, class TDefault>
struct mp_search_impl;

template<class L, class V>
struct mp_find_impl;

template<class M, class K>
struct mp_map_find_impl;



/* list manipulators returning a new list */
template<class L>
struct mp_clear_impl;

template<class L, class C>
struct mp_unique_impl;

template<class A, template<class...> class B>
struct mp_rename_impl;

template<class... L>
struct mp_append_impl;

template<class L, class S>
struct mp_map_from_list_impl;

template<template<class...> class F, class E, class... L>
struct mp_transform_impl;



/* unique id */
template<class Counter>
struct mp_unique_counter;

template<class Counter, class... Args>
struct mp_unique_id;



/* strings */
struct tag_reference { };
struct tag_array { };

template<size_t N, class T>
struct mp_string_impl;

template<class I, int Base>
struct mp_int_to_string_impl;

template<size_t N>
using mp_array_string = mp_string_impl<N, tag_array>;

template<class J, class L>
struct mp_string_type_join_impl;



/* tuple */
template<bool, class F, class T, class... Args>
struct mp_tuple_call_helper
{
static inline void exec(F f, T& t, Args&&... args)
{ }
};

template<class F, class T, class... Args>
struct mp_tuple_call_helper<true, F, T, Args...>
{
static inline void exec(F f, T& t, Args&&... args)
{ f(t, std::forward<Args>(args)...); }
};

template<class T>
using mp_tuple_filter = mp_true;

template<template<class> class Filter, class T, class F, size_t... I, class... Args>
void for_each_in_tuple_filter(T& t, F f, const mp_index_sequence<I...>&, Args&&... args)
{
using expander = int[];
(void) f;
(void) expander { (mp_tuple_call_helper<
Filter<decltype(std::get<I>(t))>::value,
F,
decltype(std::get<I>(t)),
Args...>::exec(
f,
std::get<I>(t),
std::forward<Args>(args)...), 0)... };
}
}



/* logical operations */
template<class B, class T, class E>
using mp_if = typename __impl::mp_if_c_impl<B::value != 0, T, E>::type;

template<bool B, class T, class E>
using mp_if_c = typename __impl::mp_if_c_impl<B, T, E>::type;

template<class C, class T, template<class...> class E, class... A>
using mp_eval_if = typename __impl::mp_eval_if_c_impl<C::value != 0, T, E, A...>::type;

template<bool C, class T, template<class...> class E, class... A>
using mp_eval_if_c = typename __impl::mp_eval_if_c_impl<C, T, E, A...>::type;

template<class L>
using mp_not = typename __impl::mp_not_impl<L>::type;

template<class L>
using mp_and = typename __impl::mp_and_impl<L>::type;

template<class L>
using mp_or = typename __impl::mp_or_impl<L>::type;



/* arithmetic */
template<class L>
using mp_plus = typename __impl::mp_plus_impl<L>::type;

template<class L>
using mp_minus = typename __impl::mp_minus_impl<L>::type;

template<class L>
using mp_multiply = typename __impl::mp_multiply_impl<L>::type;

template<class L>
using mp_divide = typename __impl::mp_divide_impl<L>::type;



/* generator functions */
template<class T, T N>
using mp_make_integer_sequence = typename __impl::mp_make_int_seq_impl<T, 0, N>::type;

template<size_t N>
using mp_make_index_sequence = mp_make_integer_sequence<size_t, N>;

template<size_t N, class... T>
using mp_repeat = typename __impl::mp_repeat_impl<N, T...>::type;



/* list operations returning a numeric value */
template<class... T>
using mp_length = mp_const<size_t, sizeof...(T)>;

template<class L>
using mp_size = typename __impl::mp_rename_impl<L, mp_length>::type;

template<class L, class V>
using mp_count = typename __impl::mp_count_impl<L, V>::type;

template<class L, template<class...> class P>
using mp_count_if = typename __impl::mp_count_if_impl<L, P>::type;



/* operations to manipulate list content */
template<class L, class... T>
using mp_push_front = typename __impl::mp_push_front_impl<L, T...>::type;

template<class L, class... T>
using mp_pop_front = typename __impl::mp_pop_front_impl<L>::type;

template<class L, class... T>
using mp_push_back = typename __impl::mp_push_back_impl<L, T...>::type;

template<class... L>
using mp_concat = typename __impl::mp_concat_impl<L...>::type;

template<class L, template<class> class F>
using mp_filter = typename __impl::mp_filter_impl<L, F>::type;



/* list operations returning a bool value */
template<class... L>
using mp_empty = typename __impl::mp_empty_impl<L...>::type;

template<class L, class V>
using mp_contains = mp_bool<mp_count<L, V>::value != 0>;



/* list operations returing elements from the list */
template<class L>
using mp_front = typename __impl::mp_front_impl<L>::type;

template<class L>
using mp_second = typename __impl::mp_second_impl<L>::type;

template<class L, class I>
using mp_at = typename __impl::mp_at_c_impl<L, I::value>::type;

template<class L, size_t I>
using mp_at_c = typename __impl::mp_at_c_impl<L, I>::type;

template<class L, template<class> class F, class TDefault = void>
using mp_search = typename __impl::mp_search_impl<L, F, TDefault>::type;

template<class L, class V>
using mp_find = typename __impl::mp_find_impl<L, V>::type;

template<class M, class K>
using mp_map_find = typename __impl::mp_map_find_impl<M, K>::type;



/* list manipulators returning a new list */
template<class L>
using mp_clear = typename __impl::mp_clear_impl<L>::type;

template<class L>
using mp_unique = typename __impl::mp_unique_impl<L, mp_clear<L>>::type;

template<class A, template<class...> class B>
using mp_rename = typename __impl::mp_rename_impl<A, B>::type;

template<class... L>
using mp_append = typename __impl::mp_append_impl<L...>::type;

template<class L>
using mp_map_from_list = typename __impl::mp_map_from_list_impl<L, mp_make_index_sequence<mp_size<L>::value>>::type;

template<template<class...> class F, class... L>
using mp_transform = typename __impl::mp_transform_impl<F, mp_empty<L...>, L...>::type;



/* unique id */
template<class Counter>
inline size_t nextUniqueId()
{ return __impl::mp_unique_counter<Counter>::next(); }

template<class Counter, class... Args>
inline size_t getUniqueId()
{ return __impl::mp_unique_id<Counter, Args...>::value(); }



/* strings */
template<size_t N>
using mp_string = __impl::mp_string_impl<N, __impl::tag_reference>;

template<class I, int Base>
constexpr auto mp_int_to_string()
{ return __impl::mp_int_to_string_impl<I, Base>::value; }

template <int N>
constexpr mp_string<N - 1> mp_make_string(const char (&data)[N])
{ return mp_string<N - 1>(data); }

template <size_t N1, size_t N2, class T1, class T2>
constexpr __impl::mp_array_string<N1 + N2> mp_string_cat(
const __impl::mp_string_impl<N1, T1>& s1,
const __impl::mp_string_impl<N2, T2>& s2)
{ return __impl::mp_array_string<N1 + N2>(s1, s2); };

template <size_t N1, size_t N2, class T1, class T2>
constexpr auto operator + (
const __impl::mp_string_impl<N1, T1>& s1,
const __impl::mp_string_impl<N2, T2>& s2)
{ return mp_string_cat(s1, s2); };

template<size_t NJ, size_t N1, size_t N2, class TJ, class T1, class T2>
constexpr auto mp_string_join(
const __impl::mp_string_impl<NJ, TJ>& j,
const __impl::mp_string_impl<N1, T1>& s1,
const __impl::mp_string_impl<N2, T2>& s2)
{ return mp_string_cat(s1, mp_string_cat(j, s2)); }

template<size_t NJ, size_t N1, size_t... NX, class TJ, class T1, class... TX>
constexpr auto mp_string_join(
const __impl::mp_string_impl<NJ, TJ>& j,
const __impl::mp_string_impl<N1, T1>& s,
const __impl::mp_string_impl<NX, TX>&... rest)
{ return mp_string_cat(s, mp_string_cat(j, mp_string_join(j, rest...))); }

template<class J, class L>
using mp_string_type_join = __impl::mp_string_type_join_impl<J, L>;



/* tuple */
template<class... T, class F, class... Args>
void mp_for_each_in_tuple(std::tuple<T...>& t, F f, Args&&... args)
{ __impl::for_each_in_tuple_filter<__impl::mp_tuple_filter>(t, f, mp_make_index_sequence<mp_length<T...>::value>(), std::forward<Args>(args)...); }

template<class... T, class F, class... Args>
void mp_for_each_in_tuple(const std::tuple<T...>& t, F f, Args&&... args)
{ __impl::for_each_in_tuple_filter<__impl::mp_tuple_filter>(t, f, mp_make_index_sequence<mp_length<T...>::value>(), std::forward<Args>(args)...); }

template<template<class> class Filter, class... T, class F, class... Args>
void mp_for_each_in_tuple_filter(std::tuple<T...>& t, F f, Args&&... args)
{ __impl::for_each_in_tuple_filter<Filter>(t, f, mp_make_index_sequence<mp_length<T...>::value>(), std::forward<Args>(args)...); }

template<template<class> class Filter, class... T, class F, class... Args>
void mp_for_each_in_tuple_filter(const std::tuple<T...>& t, F f, Args&&... args)
{ __impl::for_each_in_tuple_filter<Filter>(t, f, mp_make_index_sequence<mp_length<T...>::value>(), std::forward<Args>(args)...); }

template<template<class...> class F>
struct mp_for_each_proxy
{
template<class T, class... Args>
inline void operator()(T& t, Args&&... args) const
{ F<mp_clean_type<T>>::exec(t, std::forward<Args>(args)...); }
};



namespace __impl
{
/* helper */
constexpr size_t cx_plus()
{ return 0; }

template<class T1, class... T>
constexpr size_t cx_plus(T1 t1, T... t)
{ return t1 + cx_plus(t...); }

constexpr bool cx_and()
{ return true; }

template<class... T>
constexpr bool cx_and(bool b, T... t)
{ return b && cx_and(t...); }

constexpr bool cx_or()
{ return false; }

template<class... T>
constexpr bool cx_or(bool b, T... t)
{ return b || cx_or(t...); }

constexpr size_t cx_find_index( bool const * first, bool const * last )
{ return first == last || *first ? 0 : 1 + cx_find_index(first + 1, last); }



/* logical operations */
template<class T, class F>
struct mp_if_c_impl<true, T, F>
{ using type = T; };

template<class T, class F>
struct mp_if_c_impl<false, T, F>
{ using type = F; };

template<class T, template<class...> class E, class... A>
struct mp_eval_if_c_impl<true, T, E, A...>
{ using type = T; };

template<class T, template<class...> class E, class... A>
struct mp_eval_if_c_impl<false, T, E, A...>
{ using type = E<A...>; };

template<template<class...> class L, class... T>
struct mp_not_impl<L<T...>>
{ using type = L<mp_bool<T::value == 0>...>; };

template<template<class...> class L, class... T>
struct mp_and_impl<L<T...>>
{ using type = mp_bool<cx_and(mp_bool<T::value>::value...)>; };

template<template<class...> class L, class... T>
struct mp_or_impl<L<T...>>
{ using type = mp_bool<cx_or(mp_bool<T::value>::value...)>; };



/* arithmetic */
template<template<class...> class L, class T>
struct mp_plus_impl<L<T>>
{ using type = T; };

template<template<class...> class L, class T1, class... T>
struct mp_plus_impl<L<T1, T...>>
{
using _type = mp_remove_const<decltype(T1::value)>;
static constexpr _type _value = T1::value + mp_plus<L<T...>>::value;
using type = mp_const<_type, _value>;
};

template<template<class...> class L, class T>
struct mp_minus_impl<L<T>>
{ using type = T; };

template<template<class...> class L, class T1, class... T>
struct mp_minus_impl<L<T1, T...>>
{
using _type = mp_remove_const<decltype(T1::value)>;
static constexpr _type _value = T1::value - mp_plus<L<T...>>::value;
using type = mp_const<_type, _value>;
};

template<template<class...> class L, class T>
struct mp_multiply_impl<L<T>>
{ using type = T; };

template<template<class...> class L, class T1, class... T>
struct mp_multiply_impl<L<T1, T...>>
{
using _type = mp_remove_const<decltype(T1::value)>;
static constexpr _type _value = T1::value * mp_multiply<L<T...>>::value;
using type = mp_const<_type, _value>;
};

template<template<class...> class L, class T>
struct mp_divide_impl<L<T>>
{ using type = T; };

template<template<class...> class L, class T1, class... T>
struct mp_divide_impl<L<T1, T...>>
{
using _type = mp_remove_const<decltype(T1::value)>;
static constexpr _type _value = T1::value / mp_multiply<L<T...>>::value;
using type = mp_const<_type, _value>;
};



/* generator functions */
template<class S>
struct next_integer_sequence;

template<class T, T... Ints>
struct next_integer_sequence<mp_integer_sequence<T, Ints...>>
{ using type = mp_integer_sequence<T, Ints..., sizeof...(Ints)>; };

template<class T, T I, T N>
struct mp_make_int_seq_impl
{ using type = typename next_integer_sequence<typename mp_make_int_seq_impl<T, I+1, N>::type>::type; };

template<class T, T N>
struct mp_make_int_seq_impl<T, N, N>
{ using type = mp_integer_sequence<T>; };

template<size_t N, class... T>
struct mp_repeat_impl
{
using _l1 = typename mp_repeat_impl<N/2, T...>::type;
using _l2 = typename mp_repeat_impl<N%2, T...>::type;
using type = mp_append<_l1, _l1, _l2>;
};

template<class... T> struct mp_repeat_impl<0, T...>
{ using type = mp_list<>; };

template<class... T> struct mp_repeat_impl<1, T...>
{ using type = mp_list<T...>; };



/* list operations returning a numeric value */
template<template<class...> class L, class... T>
struct mp_size_impl<L<T...>>
{ using type = mp_length<T...>; };

template<template<class...> class L, class... T, class V>
struct mp_count_impl<L<T...>, V>
{ using type = mp_size_t<cx_plus(std::is_same<T, V>::value...)>; };

template<template<class...> class L, class... T, template<class...> class P>
struct mp_count_if_impl<L<T...>, P>
{ using type = mp_size_t<cx_plus(P<T>::value...)>; };



/* operations to manipulate list content */
template<template<class...> class L, class... U, class... T>
struct mp_push_front_impl<L<U...>, T...>
{ using type = L<T..., U...>; };

template<template<class...> class L, class T1, class... T>
struct mp_pop_front_impl<L<T1, T...>>
{ using type = L<T...>; };

template<template<class...> class L, class... U, class... T>
struct mp_push_back_impl<L<U...>, T...>
{ using type = L<U..., T...>; };

template<template<class...> class L1, template<class...> class L2, class... T1, class... T2>
struct mp_concat_impl<L1<T1...>, L2<T2...>>
{ using type = L1<T1..., T2...>; };

template<template<class...> class L1, template<class...> class L2, class... T1, class... T2, class... L>
struct mp_concat_impl<L1<T1...>, L2<T2...>, L...>
{
using _rest = mp_concat<L2<T2...>, L...>;
using type = mp_concat<L1<T1...>, _rest>;
};

template<template<class...> class L, template<class> class F>
struct mp_filter_impl<L<>, F>
{ using type = L<>; };

template<template<class...> class L, template<class> class F, class T1, class... T>
struct mp_filter_impl<L<T1, T...>, F>
{
using _rest = mp_filter<L<T...>, F>;
using _match = F<T1>;
using type = mp_eval_if_c<_match::value == 0, _rest, mp_push_front, _rest, T1>;
};



/* list operations returning a bool value */
template<template<class...> class L1, class... T>
struct mp_empty_impl<L1<T...>>
{ using type = mp_bool<mp_length<T...>::value == 0>; };

template<template<class...> class L1, class... T, class... L>
struct mp_empty_impl<L1<T...>, L...>
{
static constexpr bool _first = !static_cast<bool>(mp_length<T...>::value);
static constexpr bool _other = static_cast<bool>(mp_empty<L...>::value);
using type = mp_bool<_first && _other>;
};



/* list operations returing elements from the list */
template<template<class...> class L, class T1, class... T>
struct mp_front_impl<L<T1, T...>>
{ using type = T1; };

template<template<class...> class L, class T1, class T2, class... T>
struct mp_second_impl<L<T1, T2, T...>>
{ using type = T2; };

template<class L, size_t I>
struct mp_at_c_impl
{
using map = mp_map_from_list<L>;
using type = mp_second<mp_map_find<map, mp_size_t<I>>>;
};

template<bool B, class L, template<class> class F, class TDefault>
struct mp_search_helper;

template<template<class...> class L, template<class> class F, class TDefault, class T1, class... T>
struct mp_search_helper<true, L<T1, T...>, F, TDefault>
{ using type = T1; };

template<template<class...> class L, template<class> class F, class TDefault, class T1, class... T>
struct mp_search_helper<false, L<T1, T...>, F, TDefault>
{ using type = mp_search<L<T...>, F, TDefault>; };

template<template<class...> class L, template<class> class F, class TDefault>
struct mp_search_impl<L<>, F, TDefault>
{ using type = TDefault; };

template<template<class...> class L, template<class> class F, class TDefault, class T1, class... T>
struct mp_search_impl<L<T1, T...>, F, TDefault>
{
using c_value = F<T1>;
using type = typename mp_search_helper<c_value::value, L<T1, T...>, F, TDefault>::type;
};

template<template<class...> class L, class V>
struct mp_find_impl<L<>, V>
{ using type = mp_zero; };

template<template<class...> class L, class... T, class V>
struct mp_find_impl<L<T...>, V>
{
static constexpr bool _v[] = { std::is_same<T, V>::value... };
using type = mp_size_t<cx_find_index(_v, _v + sizeof...(T))>;
};

template<template<class...> class M, class... T, class K>
struct mp_map_find_impl<M<T...>, K>
{
static mp_identity<void> f( ... );

template<template<class...> class L, class... U>
static mp_identity<L<K, U...>>
f( mp_identity<L<K, U...>>* );

using U = mp_inherit<mp_identity<T>...>;
using V = decltype( f((U*)0) );
using type = typename V::type;
};



/* list manipulators returning a new list */
template<template<class...> class L, class... T>
struct mp_clear_impl<L<T...>>
{ using type = L<>; };

template<template<class...> class L, class... T>
struct mp_unique_impl<L<>, L<T...>>
{ using type = L<T...>; };

template<template<class...> class L, class C, class T1, class... T>
struct mp_unique_impl<L<T1, T...>, C>
{
using type = mp_if<
mp_contains<C, T1>,
typename mp_unique_impl<L<T...>, C>::type,
typename mp_unique_impl<L<T...>, mp_push_back<C, T1>>::type
>;
};

template<template<class...> class A, class... T, template<class...> class B>
struct mp_rename_impl<A<T...>, B>
{ using type = B<T...>; };

template<>
struct mp_append_impl<>
{ using type = mp_list<>; };

template<template<class...> class L, class... T>
struct mp_append_impl<L<T...>>
{ using type = L<T...>; };

template<
template<class...> class L1, class... T1,
template<class...> class L2, class... T2, class... Lr>
struct mp_append_impl<L1<T1...>, L2<T2...>, Lr...>
{ using type = mp_append<L1<T1..., T2...>, Lr...>; };

template<template<class...> class L, class... T, size_t... J>
struct mp_map_from_list_impl<L<T...>, mp_integer_sequence<size_t, J...>>
{ using type = mp_list<mp_list<mp_size_t<J>, T>...>; };

template<template<class...> class F, class L1, class... L>
struct mp_transform_impl<F, mp_true, L1, L...>
{ using type = mp_clear<L1>; };

template<template<class...> class F, class... L>
struct mp_transform_impl<F, mp_false, L...>
{
using _first = F< typename mp_front_impl<L>::type... >;
using _rest = mp_transform< F, typename mp_pop_front_impl<L>::type... >;
using type = mp_push_front<_rest, _first>;
};



/* unique id */
template<class Counter>
struct mp_unique_counter
{
static inline size_t next()
{
static size_t value;
return value++;
}
};

template<class Counter, class... Args>
struct mp_unique_id
{
static inline size_t value()
{
static const size_t value = mp_unique_counter<Counter>::next();
return value;
}
};



/* string */
template <size_t N>
struct mp_string_impl<N, tag_reference>
{
private:
const char (&_data)[N + 1];

public:
inline std::string str() const
{ return std::string(_data, N); }

inline constexpr const char* data() const
{ return _data; }

inline constexpr size_t size() const
{ return N; }

inline constexpr char operator[](size_t i) const
{ return X_ASSERT(i >= 0 && i < N), _data[i]; }

constexpr mp_string_impl(const char (&data)[N + 1]) :
_data((X_ASSERT(data[N] == '\0'), data))
{ }
};

template <size_t N>
struct mp_string_impl<N, tag_array>
{
private:
constexpr static size_t strsize(const char* s)
{
size_t ret = 0;
while (s[ret] != 0)
++ret;
return ret;
}

private:
char _data[N + 1];

template <size_t N1, class T1, class T2, size_t... I1, size_t... I2>
constexpr mp_string_impl(
const mp_string_impl< N1, T1>& s1,
const mp_string_impl<N - N1, T2>& s2,
mp_index_sequence<I1...>,
mp_index_sequence<I2...>) :
_data { s1[I1]..., s2[I2]..., '\0' }
{ }

public:
inline std::string str() const
{ return std::string(_data, N); }

inline constexpr const char* data() const
{ return _data; }

inline constexpr size_t size() const
{ return N; }

inline constexpr char operator[](size_t i) const
{ return X_ASSERT(i >= 0 && i < N), _data[i]; }

template<size_t X = N, class Enable = mp_enable_if_c<(X == 1), char>>
constexpr mp_string_impl(char c) :
_data { c, '\0' }
{ }

template <size_t N1, class T1, class T2, mp_enable_if_c<(N1 <= N), bool> = true>
constexpr mp_string_impl(
const mp_string_impl<N1, T1>& s1,
const mp_string_impl<N - N1, T2>& s2) :
mp_string_impl(s1, s2, mp_make_index_sequence<N1>(), mp_make_index_sequence<N - N1>())
{ }
};

template<class X, class Enable = void>
struct __int_to_char;

template<class X>
struct __int_to_char<X, mp_enable_if_c<X::value >= 0 && X::value <= 9>>
{ static constexpr auto value = mp_array_string<1>('0' + X::value); };

template<class X>
struct __int_to_char<X, mp_enable_if_c<X::value >= 10 && X::value <= 16>>
{ static constexpr auto value = mp_array_string<1>('A' + X::value - 10); };

template<class X, int Base, bool b>
struct __int_to_string_helper
{
using _type = typename X::value_type;
using _next = mp_const<_type, X::value / static_cast<_type>(Base)>;
using _this = mp_const<_type, X::value % static_cast<_type>(Base)>;
static constexpr auto value = mp_string_cat(
__int_to_string_helper<_next, Base, _next::value == 0>::value,
__int_to_char<_this>::value);
};

template<class X, int Base>
struct __int_to_string_helper<X, Base, true>
{ static constexpr auto value = mp_make_string(""); };

template<class I, int Base>
struct mp_int_to_string_impl
{
static constexpr auto value = __int_to_string_helper<I, Base, I::value == 0>::value;
};

template<class J, template<class...> class L, class... T>
struct mp_string_type_join_impl<J, L<T...>>
{
static constexpr auto value = mp_string_join(J::value, T::value...);
};

}
}

+ 3
- 0
src/cpputils/mp/container.h View File

@@ -0,0 +1,3 @@
#pragma once

#include <cpputils/mp/container/pair.h>

+ 238
- 0
src/cpputils/mp/container/pair.h View File

@@ -0,0 +1,238 @@
#pragma once

#include <cpputils/mp/core.h>
#include <cpputils/mp/util/make.h>
#include <cpputils/mp/util/tag_of.h>
#include <cpputils/mp/intern/ebo.h>
#include <cpputils/mp/intern/operators_orderable.h>
#include <cpputils/mp/intern/operators_comparable.h>
#include <cpputils/mp/operations/first.h>
#include <cpputils/mp/operations/second.h>
#include <cpputils/mp/operations/compare/less.h>
#include <cpputils/mp/operations/compare/less_equal.h>
#include <cpputils/mp/operations/compare/equal.h>
#include <cpputils/mp/operations/logical/or.h>
#include <cpputils/mp/operations/logical/and.h>
#include <cpputils/mp/operations/logical/not.h>

namespace utl {
namespace mp {

struct tag_pair { };

constexpr auto make_pair = make<tag_pair>;

namespace __impl
{
template<int>
struct pair_index;
}

template<typename First, typename Second>
struct pair :
private intern::ebo<__impl::pair_index<0>, First>,
private intern::ebo<__impl::pair_index<1>, Second>
{
using this_type = pair<First, Second>;

// default constructor
template<typename... dummy, typename = enable_if_c<
is_constructible<First, dummy...>::value &&
is_constructible<Second, dummy...>::value>>
constexpr pair()
: intern::ebo<__impl::pair_index<0>, First>()
, intern::ebo<__impl::pair_index<1>, Second>()
{ }

// variadic constructors
template<typename... dummy, typename = enable_if_c<
is_constructible<First, const First&, dummy...>::value &&
is_constructible<Second, const Second&, dummy...>::value>>
constexpr pair(First f, Second s)
: intern::ebo<__impl::pair_index<0>, First>(f)
, intern::ebo<__impl::pair_index<1>, Second>(s)
{ }

template<typename F, typename S, typename = enable_if_c<
is_convertible<F&&, First>::value &&
is_convertible<S&&, Second>::value>>
constexpr pair(F&& f, S&& s)
: intern::ebo<__impl::pair_index<0>, First>(std::forward<F>(f))
, intern::ebo<__impl::pair_index<1>, Second>(std::forward<S>(s))
{ }

// copy and move constructor
template<typename F, typename S, typename = enable_if_c<
is_constructible<First, const F&>::value &&
is_constructible<Second, const S&>::value &&
is_convertible<const F&, First>::value &&
is_convertible<const S&, Second>::value>>
constexpr pair(const pair<F, S>& other)
: intern::ebo<__impl::pair_index<0>, First>(mp::first(other))
, intern::ebo<__impl::pair_index<1>, Second>(mp::second(other))
{ }

template<typename F, typename S, typename = enable_if_c<
is_constructible<First, const F&>::value &&
is_constructible<Second, const S&>::value &&
is_convertible<const F&, First>::value &&
is_convertible<const S&, Second>::value>>
constexpr pair(pair<F, S>&& other)
: intern::ebo<__impl::pair_index<0>, First>(mp::first(std::forward<pair<F, S>>(other)))
, intern::ebo<__impl::pair_index<1>, Second>(mp::second(std::forward<pair<F, S>>(other)))
{ }

// copy and move assignment
template <typename F, typename S, typename = enable_if_c<
is_assignable<First&, const F&>::value &&
is_assignable<Second&, const S&>::value>>
constexpr pair& operator=(const pair<F, S>& other) {
mp::first(*this) = mp::first(other);
mp::second(*this) = mp::second(other);
return *this;
}

template <typename F, typename S, typename = enable_if_c<
is_assignable<First&, const F &>::value &&
is_assignable<Second&, const S &>::value>>
constexpr pair& operator=(pair<F, S>&& other) {
mp::first(*this) = mp::first(std::move<pair<F, S>>(other));
mp::second(*this) = mp::second(std::move<pair<F, S>>(other));
return *this;
}

constexpr auto first() const
{ return mp::first(*this); }

constexpr auto second() const
{ return mp::second(*this); }

// Prevent the compiler from defining the default copy and move
// constructors, which interfere with the SFINAE above.
~pair() = default;

friend struct __impl::first_impl<tag_pair>;
friend struct __impl::second_impl<tag_pair>;
};

namespace intern {

template<>
struct operators_comparable<tag_pair>
{ static constexpr bool value = true; };

template<>
struct operators_orderable<tag_pair>
{ static constexpr bool value = true; };

}

namespace __impl
{
/* tag_of */
template<typename First, typename Second>
struct tag_of_impl<pair<First, Second>>
{ using type = tag_pair; };

/* make */
template<>
struct make_impl<tag_pair>
{
template<typename F, typename S>
static constexpr pair<decay_type<F>, decay_type<S>> apply(F&& f, S&& s)
{ return { static_cast<F&&>(f), static_cast<S&&>(s) }; }
};

/* first */
template<>
struct first_impl<tag_pair>
{
using type = int;

template<typename First, typename Second>
static constexpr auto apply(pair<First, Second>& p)
{
return intern::ebo_get<pair_index<0>>(
static_cast<intern::ebo<pair_index<0>, First>&>(p)
);
}

template<typename First, typename Second>
static constexpr auto apply(pair<First, Second>&& p)
{
return intern::ebo_get<pair_index<0>>(
static_cast<intern::ebo<pair_index<0>, First>&&>(p)
);
}

template<typename First, typename Second>
static constexpr auto apply(const pair<First, Second>& p)
{
return intern::ebo_get<pair_index<0>>(
static_cast<const intern::ebo<pair_index<0>, First>&>(p)
);
}
};

/* second */
template<>
struct second_impl<tag_pair>
{
template<typename First, typename Second>
static constexpr auto apply(pair<First, Second>& p)
{
return intern::ebo_get<pair_index<1>>(
static_cast<intern::ebo<pair_index<1>, Second>&>(p)
);
}

template<typename First, typename Second>
static constexpr auto apply(pair<First, Second>&& p)
{
return intern::ebo_get<pair_index<1>>(
static_cast<intern::ebo<pair_index<1>, Second>&&>(p)
);
}

template<typename First, typename Second>
static constexpr auto apply(const pair<First, Second>& p)
{
return intern::ebo_get<pair_index<1>>(
static_cast<const intern::ebo<pair_index<1>, Second>&>(p)
);
}
};

/* equal */
template<>
struct equal_impl<tag_pair, tag_pair>
{
template<typename L, typename R>
static constexpr auto apply(const L& l, const R& r)
{
return and_(
equal(first(l), first(r)),
equal(second(l), second(r)));
}
};

/* less */
template<>
struct less_impl<tag_pair, tag_pair>
{
template<typename L, typename R>
static constexpr auto apply(const L& l, const R& r)
{
return or_(
less(first(l), first(r)),
and_(
less_equal(first (l), first (r)),
less (second(l), second(r))
)
);
}
};
}

}
}

+ 6
- 167
src/cpputils/mp/core.h View File

@@ -1,168 +1,7 @@
#include <cstddef>
#include <utility>
#pragma once

namespace utl {
namespace mp {

/*********************************************************************************************/
/* types *************************************************************************************/
/*********************************************************************************************/
template<typename T>
struct tag_const { };

template<typename T, T t>
struct integral_constant :
public std::integral_constant<T, t>
{
using tag = tag_const<T>;
};

template<typename T, T t>
constexpr integral_constant<T, t> make_const { };

template<bool B>
using c_bool = integral_constant<bool, B>;

template<size_t S>
using c_size_t = integral_constant<size_t, S>;

template<typename...>
struct list { };

template<typename... T>
struct inherit : T...
{ };

template<typename T, T... Ints>
struct integer_sequence
{ };

template<size_t... Ints>
using index_sequence = integer_sequence<size_t, Ints...>;



/*********************************************************************************************/
/* constants *********************************************************************************/
/*********************************************************************************************/
using c_true = c_bool<true>;
using c_false = c_bool<false>;
using c_zero = c_size_t<0>;



/*********************************************************************************************/
/* modifier **********************************************************************************/
/*********************************************************************************************/
template<typename T>
using add_pointer = T*;

template<typename T>
using add_reference = T&;

template<typename T>
using remove_ptr = typename std::remove_pointer<T>::type;

template<typename T>
using remove_const = typename std::remove_const<T>::type;

template<typename T>
using remove_cv = typename std::remove_cv<T>::type;

template<typename T>
using remove_ref = typename std::remove_reference<T>::type;

template<typename T>
using clean_type = remove_cv<remove_ptr<remove_ref<T>>>;

namespace __impl /* forward declaration */
{
template<typename T, typename U = remove_ref<T>>
struct decay_impl;
}

template<class T>
using decay = typename __impl::decay_impl<T>::type;

namespace __impl /* implementation */
{
template <typename T, typename U = remove_ref<T>>
struct decay
{ using type = remove_cv<U>; };

template <typename T, typename U>
struct decay<T, U[]>
{ using type = U*; };

template <typename T, typename U, std::size_t N>
struct decay<T, U[N]>
{ using type = U*; };

template <typename T, typename R, typename ...A>
struct decay<T, R(A...)>
{ using type = R(*)(A...); };

template <typename T, typename R, typename ...A>
struct decay<T, R(A..., ...)>
{ using type = R(*)(A..., ...); };
}



/*********************************************************************************************/
/* conditionals ******************************************************************************/
/*********************************************************************************************/
namespace __impl /* forward declaration */
{
template<bool C, typename T, typename E>
struct if_c_impl;

template<bool C, typename T, template<typename...> typename E, typename... A>
struct eval_if_c_impl;
}

template<typename T, typename S>
using is_same = c_bool<std::is_same<T, S>::value>;

template<typename Base, typename Derived>
using is_base_of = c_bool<std::is_base_of<Base, Derived>::value>;

template<typename T, typename S = void>
using enable_if = typename std::enable_if<T::value, S>::type;

template<bool B, typename S = void>
using enable_if_c = typename std::enable_if<B, S>::type;

template<typename B, typename T, typename E>
using if_t = typename __impl::if_c_impl<B::value != 0, T, E>::type;

template<bool B, typename T, typename E>
using if_c = typename __impl::if_c_impl<B, T, E>::type;

template<typename C, typename T, template<typename...> typename E, typename... A>
using eval_if = typename __impl::eval_if_c_impl<C::value != 0, T, E, A...>::type;

template<bool C, typename T, template<typename...> typename E, typename... A>
using eval_if_c = typename __impl::eval_if_c_impl<C, T, E, A...>::type;

namespace __impl /* implementation */
{
template<typename T, typename F>
struct if_c_impl<true, T, F>
{ using type = T; };

template<typename T, typename F>
struct if_c_impl<false, T, F>
{ using type = F; };

template<typename T, template<typename...> typename E, typename... A>
struct eval_if_c_impl<true, T, E, A...>
{ using type = T; };

template<typename T, template<typename...> typename E, typename... A>
struct eval_if_c_impl<false, T, E, A...>
{ using type = E<A...>; };
}

}
}
#include <cpputils/mp/core/checker.h>
#include <cpputils/mp/core/conditionals.h>
#include <cpputils/mp/core/const.h>
#include <cpputils/mp/core/modifier.h>
#include <cpputils/mp/core/types.h>

+ 51
- 0
src/cpputils/mp/core/checker.h View File

@@ -0,0 +1,51 @@
#pragma once

#include <type_traits>
#include <cpputils/mp/core/const.h>

namespace utl {
namespace mp {

namespace __impl /* forward declaration */
{
template<typename...>
struct is_valid_impl;
}

template<typename T, typename S>
using is_same = c_bool<std::is_same<T, S>::value>;

template<typename Base, typename Derived>
using is_base_of = c_bool<std::is_base_of<Base, Derived>::value>;

template<typename... T>
using is_constructible = c_bool<std::is_constructible<T...>::value>;

template<typename... T>
using is_empty = c_bool<std::is_empty<T...>::value>;

template<typename... T>
using is_final = c_bool<std::is_final<T...>::value>;

template<typename T, typename U>
using is_convertible = c_bool<std::is_convertible<T, U>::value>;

template<typename T, typename U>
using is_assignable = c_bool<std::is_assignable<T, U>::value>;

template<typename... T>
using is_valid = __impl::is_valid_impl<T...>;

template<typename T>
using is_arithmetic = c_bool<std::is_arithmetic<T>::value>;

namespace __impl /* implementation */
{
template<typename...>
struct is_valid_impl :
public c_true
{ };
}

}
}

+ 53
- 0
src/cpputils/mp/core/conditionals.h View File

@@ -0,0 +1,53 @@
#pragma once

namespace utl {
namespace mp {

namespace __impl /* forward declaration */
{
template<bool C, typename T, typename E>
struct if_c_impl;

template<bool C, typename T, template<typename...> class E, typename... A>
struct eval_if_c_impl;
}

template<typename T, typename S = void>
using enable_if = typename std::enable_if<T::value, S>::type;

template<bool B, typename S = void>
using enable_if_c = typename std::enable_if<B, S>::type;

template<typename B, typename T, typename E>
using if_t = typename __impl::if_c_impl<B::value != 0, T, E>::type;

template<bool B, typename T, typename E>
using if_c = typename __impl::if_c_impl<B, T, E>::type;

template<typename C, typename T, template<typename...> class E, typename... A>
using eval_if_t = typename __impl::eval_if_c_impl<C::value != 0, T, E, A...>::type;

template<bool C, typename T, template<typename...> class E, typename... A>
using eval_if_c = typename __impl::eval_if_c_impl<C, T, E, A...>::type;

namespace __impl /* implementation */
{
template<typename T, typename F>
struct if_c_impl<true, T, F>
{ using type = T; };

template<typename T, typename F>
struct if_c_impl<false, T, F>
{ using type = F; };

template<typename T, template<typename...> class E, typename... A>
struct eval_if_c_impl<true, T, E, A...>
{ using type = T; };

template<typename T, template<typename...> class E, typename... A>
struct eval_if_c_impl<false, T, E, A...>
{ using type = E<A...>; };
}

}
}

+ 30
- 0
src/cpputils/mp/core/const.h View File

@@ -0,0 +1,30 @@
#pragma once

#include <cstddef>
#include <type_traits>

namespace utl {
namespace mp {

template<typename T>
struct tag_const { };

template<typename T, T t>
struct integral_constant :
public std::integral_constant<T, t>
{
using tag = tag_const<T>;
};

template<bool B>
using c_bool = integral_constant<bool, B>;

template<size_t S>
using c_size_t = integral_constant<size_t, S>;

using c_true = c_bool<true>;
using c_false = c_bool<false>;
using c_zero = c_size_t<0>;

}
}

+ 78
- 0
src/cpputils/mp/core/modifier.h View File

@@ -0,0 +1,78 @@
#pragma once

#include <type_traits>

namespace utl {
namespace mp {

template<typename T>
using add_pointer = T*;

template<typename T>
using add_reference = T&;

template<typename T>
using remove_ptr = typename std::remove_pointer<T>::type;

template<typename T>
using remove_const = typename std::remove_const<T>::type;

template<typename T>
using remove_cv = typename std::remove_cv<T>::type;

template<typename T>
using remove_ref = typename std::remove_reference<T>::type;

template<typename T>
using clean_type = remove_cv<remove_ptr<remove_ref<T>>>;

namespace __impl /* forward declaration */
{
template<typename T, typename U = remove_ref<T>>
struct decay_impl;

template<typename T, typename U, typename = void>
struct common_type_impl
{ };
}

template<class T>
using decay = __impl::decay_impl<T>;

template<class T>
using decay_type = typename __impl::decay_impl<T>::type;

template<typename T, typename U>
using common_type = __impl::common_type_impl<T, U>;

namespace __impl /* implementation */
{
/* decay */
template <typename T, typename U>
struct decay_impl
{ using type = remove_cv<U>; };

template <typename T, typename U>
struct decay_impl<T, U[]>
{ using type = U*; };

template <typename T, typename U, std::size_t N>
struct decay_impl<T, U[N]>
{ using type = U*; };

template <typename T, typename R, typename ...A>
struct decay_impl<T, R(A...)>
{ using type = R(*)(A...); };

template <typename T, typename R, typename ...A>
struct decay_impl<T, R(A..., ...)>
{ using type = R(*)(A..., ...); };

/* common_type */
template<typename T, typename U>
struct common_type_impl<T, U, decltype((void)(true ? std::declval<T>() : std::declval<U>()))>
{ using type = decay<decltype((void)(true ? std::declval<T>() : std::declval<U>()))>; };
}

}
}

+ 10
- 0
src/cpputils/mp/core/types.h View File

@@ -0,0 +1,10 @@
#pragma once

namespace utl {
namespace mp {

template<typename...>
using void_t = void;

}
}

+ 3
- 0
src/cpputils/mp/intern.h View File

@@ -0,0 +1,3 @@
#pragma once

#include <cpputils/mp/intern/ebo.h>

+ 39
- 0
src/cpputils/mp/intern/comparable_equal.h View File

@@ -0,0 +1,39 @@
#pragma once

#include <utility>
#include <cpputils/mp/core.h>

namespace utl {
namespace mp {
namespace intern {

template<typename T, typename U = T, typename = void>
struct comparable_equal
: c_false
{ };

template<typename T>
struct comparable_equal<T, T, void_t<
decltype(std::forward<T>(std::declval<T>()) == std::forward<T>(std::declval<T>()) ? 0 : 0),
decltype(std::forward<T>(std::declval<T>()) != std::forward<T>(std::declval<T>()) ? 0 : 0)>>
: c_true
{ };

template <typename T, typename U>
struct comparable_equal<T, U, enable_if_c<
!is_same<T, U>::value,
void_t<
decltype(std::forward<T>(std::declval<T>()) == std::forward<U>(std::declval<U>()) ? 0 : 0),
decltype(std::forward<U>(std::declval<U>()) == std::forward<T>(std::declval<T>()) ? 0 : 0),
decltype(std::forward<T>(std::declval<T>()) != std::forward<U>(std::declval<U>()) ? 0 : 0),
decltype(std::forward<U>(std::declval<U>()) != std::forward<T>(std::declval<T>()) ? 0 : 0),
common_type<T, U>>>>
: c_bool<
comparable_equal<T>::value &&
comparable_equal<U>::value &&
comparable_equal<common_type<T, U>>::value>
{ };

}
}
}

+ 36
- 0
src/cpputils/mp/intern/comparable_less.h View File

@@ -0,0 +1,36 @@
#pragma once

#include <utility>
#include <cpputils/mp/core.h>

namespace utl {
namespace mp {
namespace intern {

template<typename T, typename U = T, typename = void>
struct comparable_less
: c_false
{ };

template<typename T>
struct comparable_less<T, T, void_t<
decltype(std::forward<T>(std::declval<T>()) < std::forward<T>(std::declval<T>()) ? 0 : 0)>>
: c_true
{ };

template <typename T, typename U>
struct comparable_less<T, U, enable_if_c<
!is_same<T, U>::value,
void_t<
decltype(std::forward<T>(std::declval<T>()) < std::forward<U>(std::declval<U>()) ? 0 : 0),
decltype(std::forward<U>(std::declval<U>()) < std::forward<T>(std::declval<T>()) ? 0 : 0),
common_type<T, U>>>>
: c_bool<
comparable_less<T>::value &&
comparable_less<U>::value &&
comparable_less<common_type<T, U>>::value>
{ };

}
}
}

+ 83
- 0
src/cpputils/mp/intern/ebo.h View File

@@ -0,0 +1,83 @@
#pragma once

#include "../core.h"

namespace utl {
namespace mp {
namespace intern {

template<typename Key, typename Value, bool = is_empty<Value>::value && !is_final<Value>::value>
struct ebo;

template<typename Key, typename Value>
constexpr const Value& ebo_get(const ebo<Key, Value, true>& x)
{ return x; }

template<typename Key, typename Value>
constexpr Value& ebo_get(ebo<Key, Value, true>& x)
{ return x; }

template<typename Key, typename Value>
constexpr Value&& ebo_get(ebo<Key, Value, true>&& x)
{ return x; }

template<typename Key, typename Value>
constexpr const Value& ebo_get(const ebo<Key, Value, false>& x)
{ return x._data; }

template<typename Key, typename Value>
constexpr Value& ebo_get(ebo<Key, Value, false>& x)
{ return x._data; }

template<typename Key, typename Value>
constexpr Value&& ebo_get(ebo<Key, Value, false>&& x)
{ return static_cast<Value&&>(x._data); }

template<typename Key, typename Value>
struct ebo<Key, Value, true> :
public Value
{
constexpr ebo()
{ }

template<typename T>
explicit constexpr ebo(T&& t) :
Value(std::forward<T>(t))
{ }

constexpr auto get() const&
{ return ebo_get(*this); }

constexpr auto get() &
{ return ebo_get(*this); }

constexpr auto get() &&
{ return ebo_get(std::move(*this)); }
};

template<typename Key, typename Value>
struct ebo<Key, Value, false>
{
Value _data;

constexpr ebo()
{ }

template<typename T>
explicit constexpr ebo(T&& t) :
_data(std::forward<T>(t))
{ }

constexpr auto get() const&
{ return ebo_get(*this); }

constexpr auto get() &
{ return ebo_get(*this); }

constexpr auto get() &&
{ return ebo_get(std::move(*this)); }
};

}
}
}

+ 16
- 0
src/cpputils/mp/intern/has_value.h View File

@@ -0,0 +1,16 @@
#pragma once

#include <cpputils/mp/operations/value.h>

namespace utl {
namespace mp {
namespace intern {

template<typename C>
struct has_value
: c_bool<!is_default<__impl::value_impl<tag_of<C>>>::value>
{ };

}
}
}

+ 36
- 0
src/cpputils/mp/intern/operators_comparable.h View File

@@ -0,0 +1,36 @@
#pragma once

#include <utility>
#include <cpputils/mp/core/conditionals.h>
#include <cpputils/mp/util/tag_of.h>
#include <cpputils/mp/operations/compare/equal.h>
#include <cpputils/mp/operations/compare/not_equal.h>

namespace utl {
namespace mp {

namespace intern {

template<typename T>
struct operators_comparable
{ static constexpr bool value = false; };

}

namespace operators
{
template<typename X, typename Y, typename = enable_if_c<
intern::operators_comparable<tag_of<X>>::value &&
intern::operators_comparable<tag_of<Y>>::value>>
constexpr auto operator == (X&& x, Y&& y)
{ return equal(std::forward<X>(x), std::forward<Y>(y)); }

template<typename X, typename Y, typename = enable_if_c<
intern::operators_comparable<tag_of<X>>::value &&
intern::operators_comparable<tag_of<Y>>::value>>
constexpr auto operator != (X&& x, Y&& y)
{ return not_equal(std::forward<X>(x), std::forward<Y>(y)); }
}

}
}

+ 50
- 0
src/cpputils/mp/intern/operators_orderable.h View File

@@ -0,0 +1,50 @@
#pragma once

#include <utility>
#include <cpputils/mp/core/conditionals.h>
#include <cpputils/mp/util/tag_of.h>
#include <cpputils/mp/operations/compare/less.h>
#include <cpputils/mp/operations/compare/less_equal.h>
#include <cpputils/mp/operations/compare/greater.h>
#include <cpputils/mp/operations/compare/greater_equal.h>

namespace utl {
namespace mp {

namespace intern {

template<typename T>
struct operators_orderable
{ static constexpr bool value = false; };

}

namespace operators
{
template<typename X, typename Y, typename = enable_if_c<
intern::operators_orderable<tag_of<X>>::value &&
intern::operators_orderable<tag_of<Y>>::value>>
constexpr auto operator < (X&& x, Y&& y)
{ return less(std::forward<X>(x), std::forward<Y>(y)); }

template<typename X, typename Y, typename = enable_if_c<
intern::operators_orderable<tag_of<X>>::value &&
intern::operators_orderable<tag_of<Y>>::value>>
constexpr auto operator <= (X&& x, Y&& y)
{ return less_equal(std::forward<X>(x), std::forward<Y>(y)); }

template<typename X, typename Y, typename = enable_if_c<
intern::operators_orderable<tag_of<X>>::value &&
intern::operators_orderable<tag_of<Y>>::value>>
constexpr auto operator > (X&& x, Y&& y)
{ return greater(std::forward<X>(x), std::forward<Y>(y)); }

template<typename X, typename Y, typename = enable_if_c<
intern::operators_orderable<tag_of<X>>::value &&
intern::operators_orderable<tag_of<Y>>::value>>
constexpr auto operator >= (X&& x, Y&& y)
{ return greater_equal(std::forward<X>(x), std::forward<Y>(y)); }
}

}
}

+ 6
- 0
src/cpputils/mp/operations.h View File

@@ -0,0 +1,6 @@
#pragma once

#include <cpputils/mp/operations/first.h>
#include <cpputils/mp/operations/second.h>
#include <cpputils/mp/operations/compare.h>
#include <cpputils/mp/operations/logical.h>

+ 4
- 0
src/cpputils/mp/operations/compare.h View File

@@ -0,0 +1,4 @@
#pragma once

#include <cpputils/mp/operations/compare/equal.h>
#include <cpputils/mp/operations/compare/not_equal.h>

+ 73
- 0
src/cpputils/mp/operations/compare/equal.h View File

@@ -0,0 +1,73 @@
#pragma once

#include <cpputils/mp/core/const.h>
#include <cpputils/mp/util/when.h>
#include <cpputils/mp/util/tag_of.h>
#include <cpputils/mp/util/default.h>
#include <cpputils/mp/intern/has_value.h>
#include <cpputils/mp/intern/comparable_equal.h>
#include <cpputils/mp/operations/if.h>
#include <cpputils/mp/operations/value.h>

namespace utl {
namespace mp {

namespace __impl
{
struct equal_t
{
template<typename L, typename R>
constexpr auto operator()(const L& l, const R& r) const;
};
}

constexpr __impl::equal_t equal { };

namespace __impl
{
template <typename L, typename R, typename = void>
struct equal_impl
: equal_impl<L, R, when<true>>
{ };

template <typename L, typename R, bool condition>
struct equal_impl<L, R, when<condition>>
: default_
{
template <typename ...Args>
static constexpr auto apply(Args&& ...)
{ return c_false { }; }
};

template <typename T, typename U>
struct equal_impl<T, U, when<intern::comparable_equal<T, U>::value>>
{
template <typename X, typename Y>
static constexpr auto apply(X&& x, Y&& y)
{ return static_cast<X&&>(x) == static_cast<Y&&>(y); }
};

template <typename C>
struct equal_impl<C, C, when<intern::has_value<C>::value>>
{
template <typename X, typename Y>
static constexpr auto apply(const X&, const Y&)
{
constexpr auto eq = equal(value<X>(), value<Y>());
constexpr bool truth_value = if_ (eq, true, false);
return c_bool<truth_value> { };
}
};

template<typename L, typename R>
constexpr auto equal_t::operator()(const L& l, const R& r) const
{
using l_tag_type = tag_of<L>;
using r_tag_type = tag_of<R>;
using equal_type = equal_impl<l_tag_type, r_tag_type>;
return equal_type::apply(l, r);
}
}

}
}

+ 51
- 0
src/cpputils/mp/operations/compare/greater.h View File

@@ -0,0 +1,51 @@
#pragma once

#include <cpputils/mp/core/const.h>
#include <cpputils/mp/util/when.h>
#include <cpputils/mp/util/tag_of.h>
#include <cpputils/mp/util/default.h>
#include <cpputils/mp/operations/logical/not.h>
#include <cpputils/mp/operations/compare/less.h>

namespace utl {
namespace mp {

namespace __impl
{
struct greater_t
{
template<typename L, typename R>
constexpr auto operator()(const L& l, const R& r) const;
};
}

constexpr __impl::greater_t greater { };

namespace __impl
{
template <typename L, typename R, typename = void>
struct greater_impl
: greater_impl<L, R, when<true>>
{ };

template <typename T, typename U, bool condition>
struct greater_impl<T, U, when<condition>>
: default_
{
template <typename X, typename Y>
static constexpr auto apply(X&& x, Y&& y)
{ return less(static_cast<Y&&>(y), static_cast<X&&>(x)); }
};

template<typename L, typename R>
constexpr auto greater_t::operator()(const L& l, const R& r) const
{
using l_tag_type = tag_of<L>;
using r_tag_type = tag_of<R>;
using greater_impl_type = greater_impl<l_tag_type, r_tag_type>;
return greater_impl_type::apply(l, r);
}
}

}
}

+ 51
- 0
src/cpputils/mp/operations/compare/greater_equal.h View File

@@ -0,0 +1,51 @@
#pragma once

#include <cpputils/mp/core/const.h>
#include <cpputils/mp/util/when.h>
#include <cpputils/mp/util/tag_of.h>
#include <cpputils/mp/util/default.h>
#include <cpputils/mp/operations/logical/not.h>
#include <cpputils/mp/operations/compare/less.h>

namespace utl {
namespace mp {

namespace __impl
{
struct greater_equal_t
{
template<typename L, typename R>
constexpr auto operator()(const L& l, const R& r) const;
};
}

constexpr __impl::greater_equal_t greater_equal { };

namespace __impl
{
template <typename L, typename R, typename = void>
struct greater_equal_impl
: greater_equal_impl<L, R, when<true>>
{ };

template <typename T, typename U, bool condition>
struct greater_equal_impl<T, U, when<condition>>
: default_
{
template <typename X, typename Y>
static constexpr auto apply(X&& x, Y&& y)
{ return not_(less(static_cast<X&&>(x), static_cast<Y&&>(y))); }
};

template<typename L, typename R>
constexpr auto greater_equal_t::operator()(const L& l, const R& r) const
{
using l_tag_type = tag_of<L>;
using r_tag_type = tag_of<R>;
using greater_equal_impl_type = greater_equal_impl<l_tag_type, r_tag_type>;
return greater_equal_impl_type::apply(l, r);
}
}

}
}

+ 73
- 0
src/cpputils/mp/operations/compare/less.h View File

@@ -0,0 +1,73 @@
#pragma once

#include <cpputils/mp/core/const.h>
#include <cpputils/mp/util/when.h>
#include <cpputils/mp/util/tag_of.h>
#include <cpputils/mp/util/default.h>
#include <cpputils/mp/intern/has_value.h>
#include <cpputils/mp/intern/comparable_less.h>
#include <cpputils/mp/operations/if.h>
#include <cpputils/mp/operations/value.h>

namespace utl {
namespace mp {

namespace __impl
{
struct less_t
{
template<typename L, typename R>
constexpr auto operator()(const L& l, const R& r) const;
};
}

constexpr __impl::less_t less { };

namespace __impl
{
template <typename L, typename R, typename = void>
struct less_impl
: less_impl<L, R, when<true>>
{ };

template <typename L, typename R, bool condition>
struct less_impl<L, R, when<condition>>
: default_
{
template <typename ...Args>
static constexpr auto apply(Args&& ...)
{ return c_false { }; }
};

template <typename T, typename U>
struct less_impl<T, U, when<intern::comparable_less<T, U>::value>>
{
template <typename X, typename Y>
static constexpr auto apply(X&& x, Y&& y)
{ return static_cast<X&&>(x) < static_cast<Y&&>(y); }
};

template <typename C>
struct less_impl<C, C, when<intern::has_value<C>::value>>
{
template <typename X, typename Y>
static constexpr auto apply(const X&, const Y&)
{
constexpr auto eq = less(value<X>(), value<Y>());
constexpr bool truth_value = if_ (eq, true, false);
return c_bool<truth_value> { };
}
};

template<typename L, typename R>
constexpr auto less_t::operator()(const L& l, const R& r) const
{
using l_tag_type = tag_of<L>;
using r_tag_type = tag_of<R>;
using less_type = less_impl<l_tag_type, r_tag_type>;
return less_type::apply(l, r);
}
}

}
}

+ 51
- 0
src/cpputils/mp/operations/compare/less_equal.h View File

@@ -0,0 +1,51 @@
#pragma once

#include <cpputils/mp/core/const.h>
#include <cpputils/mp/util/when.h>
#include <cpputils/mp/util/tag_of.h>
#include <cpputils/mp/util/default.h>
#include <cpputils/mp/operations/logical/not.h>
#include <cpputils/mp/operations/compare/less.h>

namespace utl {
namespace mp {

namespace __impl
{
struct less_equal_t
{
template<typename L, typename R>
constexpr auto operator()(const L& l, const R& r) const;
};
}

constexpr __impl::less_equal_t less_equal { };

namespace __impl
{
template <typename L, typename R, typename = void>
struct less_equal_impl
: less_equal_impl<L, R, when<true>>
{ };

template <typename T, typename U, bool condition>
struct less_equal_impl<T, U, when<condition>>
: default_
{
template <typename X, typename Y>
static constexpr auto apply(X&& x, Y&& y)
{ return not_(less(static_cast<Y&&>(y), static_cast<X&&>(x))); }
};

template<typename L, typename R>
constexpr auto less_equal_t::operator()(const L& l, const R& r) const
{
using l_tag_type = tag_of<L>;
using r_tag_type = tag_of<R>;
using less_equal_impl_type = less_equal_impl<l_tag_type, r_tag_type>;
return less_equal_impl_type::apply(l, r);
}
}

}
}

+ 51
- 0
src/cpputils/mp/operations/compare/not_equal.h View File

@@ -0,0 +1,51 @@
#pragma once

#include <cpputils/mp/core/const.h>
#include <cpputils/mp/util/when.h>
#include <cpputils/mp/util/tag_of.h>
#include <cpputils/mp/util/default.h>
#include <cpputils/mp/operations/logical/not.h>
#include <cpputils/mp/operations/compare/not_equal.h>

namespace utl {
namespace mp {

namespace __impl
{
struct not_equal_t
{
template<typename L, typename R>
constexpr auto operator()(const L& l, const R& r) const;
};
}

constexpr __impl::not_equal_t not_equal { };

namespace __impl
{
template <typename L, typename R, typename = void>
struct not_equal_impl
: not_equal_impl<L, R, when<true>>
{ };

template <typename L, typename R, bool condition>
struct not_equal_impl<L, R, when<condition>>
: default_
{
template <typename X, typename Y>
static constexpr auto apply(X&& x, Y&& y)
{ return not(equal(std::forward<X>(x), std::forward<Y>(y))); }
};

template<typename L, typename R>
constexpr auto not_equal_t::operator()(const L& l, const R& r) const
{
using l_tag_type = tag_of<L>;
using r_tag_type = tag_of<R>;
using not_equal_type = not_equal_impl<l_tag_type, r_tag_type>;
return not_equal_type::apply(l, r);
}
}

}
}

+ 59
- 0
src/cpputils/mp/operations/eval.h View File

@@ -0,0 +1,59 @@
#pragma once

#include <utility>
#include <cpputils/mp/util/when.h>
#include <cpputils/mp/util/tag_of.h>
#include <cpputils/mp/util/default.h>

namespace utl {
namespace mp {

namespace __impl
{
struct eval_t
{
template <typename Expr>
constexpr auto operator()(Expr&& expr) const;
};
}

constexpr __impl::eval_t eval { };

namespace __impl
{
template <typename T, typename = void>
struct eval_impl
: eval_impl<T, when<true>>
{ };

template <typename T, bool condition>
struct eval_impl<T, when<condition>>
: default_
{
template <typename Expr>
static constexpr auto eval_helper(Expr&& expr, int)
{ return static_cast<Expr&&>(expr)(); }

template <typename Expr>
static constexpr auto eval_helper(Expr&&, ...)
{
static_assert(wrong<Expr> { },
"eval(expr) requires the expression to be a a nullary Callable");
}

template <typename Expr>
static constexpr decltype(auto) apply(Expr&& expr)
{ return eval_helper(static_cast<Expr&&>(expr), int { }); }
};

template <typename Expr>
constexpr auto eval_t::operator()(Expr&& expr) const
{
using tag_type = tag_of<Expr>;
using eval_impl_type = eval_impl<tag_type>;
return eval_impl_type::apply(std::forward<Expr>(expr));;
}
}

}
}

+ 80
- 0
src/cpputils/mp/operations/eval_if.h View File

@@ -0,0 +1,80 @@
#pragma once

#include <cpputils/mp/util/when.h>
#include <cpputils/mp/util/tag_of.h>
#include <cpputils/mp/util/default.h>
#include <cpputils/mp/intern/has_value.h>
#include <cpputils/mp/operations/if.fwd.h>
#include <cpputils/mp/operations/eval.h>

namespace utl {
namespace mp {

namespace __impl
{
struct eval_if_t
{
template <typename Cond, typename Then, typename Else>
constexpr auto operator()(Cond&& c, Then&& t, Else&& e) const;
};
}

constexpr __impl::eval_if_t eval_if { };

namespace __impl
{
template <typename T, typename = void>
struct eval_if_impl
: eval_if_impl<T, when<true>>
{ };

template <typename T, bool condition>
struct eval_if_impl<T, when<condition>>
: default_
{
template <typename ...Args>
static constexpr auto apply(Args&& ...) = delete;
};

template <typename T>
struct eval_if_impl<T, when<is_arithmetic<T>::value>>
{
template <typename Cond, typename Then, typename Else>
static constexpr auto apply(const Cond& cond, Then&& t, Else&& e)
{
return cond ? eval(std::forward<Then>(t))
: eval(std::forward<Else>(e));
}
};

template <typename T>
struct eval_if_impl<T, when<intern::has_value<T>::value>>
{
template<typename Then, typename Else>
static constexpr auto eval_if_helper(c_true, Then&& t, Else&& e)
{ return eval(std::forward<Then>(t)); }

template<typename Then, typename Else>
static constexpr auto eval_if_helper(c_false, Then&& t, Else&& e)
{ return eval(std::forward<Else>(e)); }

template <typename Cond, typename Then, typename Else>
static constexpr auto apply(const Cond&, Then&& t, Else&& e)
{
constexpr auto cond = value<Cond>();
constexpr bool truth_value = if_(cond, true, false);
return eval_if_helper(c_bool<truth_value> { }, std::forward<Then>(t), std::forward<Else>(e));
}
};

template <typename Cond, typename Then, typename Else>
constexpr auto eval_if_t::operator()(Cond&& c, Then&& t, Else&& e) const
{
using tag_type = tag_of<Cond>;
using eval_if_type = eval_if_impl<tag_type>;
return eval_if_type::apply(std::forward<Cond>(c), std::forward<Then>(t), std::forward<Else>(e));
}
}

}
}

+ 46
- 0
src/cpputils/mp/operations/first.h View File

@@ -0,0 +1,46 @@
#pragma once

#include <cpputils/mp/util/when.h>
#include <cpputils/mp/util/tag_of.h>
#include <cpputils/mp/util/default.h>

namespace utl {
namespace mp {

namespace __impl
{
struct first_t
{
template<typename T>
constexpr auto operator()(T&& t) const;
};
}

constexpr __impl::first_t first { };

namespace __impl
{
template <typename T, typename = void>
struct first_impl
: first_impl<T, when<true>>
{ };

template <typename T, bool condition>
struct first_impl<T, when<condition>>
: default_
{
template <typename ...Args>
static constexpr auto apply(Args&& ...) = delete;
};

template<typename T>
constexpr auto first_t::operator()(T&& t) const
{
using tag_type = tag_of<T>;
using first_type = first_impl<tag_type>;
return first_type::apply(std::forward<T>(t));
}
}

}
}

+ 18
- 0
src/cpputils/mp/operations/if.fwd.h View File

@@ -0,0 +1,18 @@
#pragma once

namespace utl {
namespace mp {

namespace __impl
{
struct if_t
{
template <typename Cond, typename Then, typename Else>
constexpr auto operator()(Cond&& c, Then&& t, Else&& e) const;
};
}

constexpr __impl::if_t if_ { };

}
}

+ 52
- 0
src/cpputils/mp/operations/if.h View File

@@ -0,0 +1,52 @@
#pragma once

#include <cpputils/mp/operations/if.fwd.h>

#include <cpputils/mp/util/when.h>
#include <cpputils/mp/util/tag_of.h>
#include <cpputils/mp/util/default.h>
#include <cpputils/mp/operations/eval_if.h>

namespace utl {
namespace mp {

namespace __impl
{
template <typename T>
struct hold {
T value;
constexpr T&& operator()() &&
{ return static_cast<T&&>(value); }
};

template <typename L, typename = void>
struct if_impl
: if_impl<L, when<true>>
{ };

template <typename L, bool condition>
struct if_impl<L, when<condition>>
: default_
{
template <typename Cond, typename Then, typename Else>
static constexpr auto apply(Cond&& c, Then&& t, Else&& e)
{
return eval_if(
std::forward<Cond>(c),
hold<Then&&> { static_cast<Then&&>(t) },
hold<Else&&> { static_cast<Else&&>(e) }
);
}
};

template <typename Cond, typename Then, typename Else>
constexpr auto if_t::operator()(Cond&& c, Then&& t, Else&& e) const
{
using tag_type = tag_of<Cond>;
using if_type = if_impl<tag_type>;
return if_type::apply(std::forward<Cond>(c), std::forward<Then>(t), std::forward<Else>(e));
}
}

}
}

+ 4
- 0
src/cpputils/mp/operations/logical.h View File

@@ -0,0 +1,4 @@
#pragma once

#include <cpputils/mp/operations/logical/not.h>
#include <cpputils/mp/operations/logical/and.h>

+ 63
- 0
src/cpputils/mp/operations/logical/and.h View File

@@ -0,0 +1,63 @@
#pragma once

#include <cpputils/mp/core/const.h>
#include <cpputils/mp/util/when.h>
#include <cpputils/mp/util/tag_of.h>
#include <cpputils/mp/util/default.h>
#include <cpputils/mp/operations/if.h>

namespace utl {
namespace mp {

namespace __impl
{
struct and_t
{
template<typename X, typename Y>
constexpr auto operator()(X&& x, Y&& y) const;

template<typename X, typename... Y>
constexpr auto operator()(X&& x, Y&&... y) const;
};
}

constexpr __impl::and_t and_ { };

namespace __impl
{
template <typename T, typename = void>
struct and_impl
: and_impl<T, when<true>>
{ };

template <typename T, bool condition>
struct and_impl<T, when<condition>>
: default_
{
template <typename X, typename Y>
static constexpr auto apply(X&& x, Y&& y)
{ return if_(x, static_cast<Y&&>(y), x); }
};

template <typename X, typename Y>
constexpr auto and_t::operator()(X&& x, Y&& y) const
{
using tag_type = tag_of<X>;
using and_impl_type = and_impl<tag_type>;
return and_impl_type::apply(std::forward<X>(x), std::forward<Y>(y));
};
/* TODO
template <typename X, typename ...Y>
constexpr auto and_t::operator()(X&& x, Y&& ...y) const
{
return detail::variadic::foldl1(
*this,
static_cast<X&&>(x),
static_cast<Y&&>(y)...
);
}
*/
}

}
}

+ 55
- 0
src/cpputils/mp/operations/logical/not.h View File

@@ -0,0 +1,55 @@
#pragma once

#include <cpputils/mp/core/const.h>
#include <cpputils/mp/util/when.h>
#include <cpputils/mp/util/tag_of.h>
#include <cpputils/mp/util/default.h>

namespace utl {
namespace mp {

namespace __impl
{
struct not_t
{
template<typename X>
constexpr auto operator()(X&& x) const;
};
}

constexpr __impl::not_t not_ { };

namespace __impl
{
template <typename T, typename = void>
struct not_impl
: not_impl<T, when<true>>
{ };

template <typename T, bool condition>
struct not_impl<T, when<condition>>
: default_
{
template <typename ...Args>
static constexpr auto apply(Args&& ...) = delete;
};

template <typename T>
struct not_impl<T, when<is_arithmetic<T>::value>>
{
template <typename X>
static constexpr auto apply(const X& x)
{ return x ? false : true; }
};

template <typename X>
constexpr auto not_t::operator()(X&& x) const
{
using tag_type = tag_of<X>;
using not_impl_type = not_impl<tag_type>;
return not_impl_type::apply(std::forward<X>(x));
};
}

}
}

+ 63
- 0
src/cpputils/mp/operations/logical/or.h View File

@@ -0,0 +1,63 @@
#pragma once

#include <cpputils/mp/core/const.h>
#include <cpputils/mp/util/when.h>
#include <cpputils/mp/util/tag_of.h>
#include <cpputils/mp/util/default.h>
#include <cpputils/mp/operations/if.h>

namespace utl {
namespace mp {

namespace __impl
{
struct or_t
{
template<typename X, typename Y>
constexpr auto operator()(X&& x, Y&& y) const;

template<typename X, typename... Y>
constexpr auto operator()(X&& x, Y&&... y) const;
};
}

constexpr __impl::or_t or_ { };

namespace __impl
{
template <typename T, typename = void>
struct or_impl
: or_impl<T, when<true>>
{ };

template <typename T, bool condition>
struct or_impl<T, when<condition>>
: default_
{
template <typename X, typename Y>
static constexpr auto apply(X&& x, Y&& y)
{ return if_(x, x, static_cast<Y&&>(y)); }
};

template <typename X, typename Y>
constexpr auto or_t::operator()(X&& x, Y&& y) const
{
using tag_type = tag_of<X>;
using or_impl_type = or_impl<tag_type>;
return or_impl_type::apply(std::forward<X>(x), std::forward<Y>(y));
};
/* TODO
template <typename X, typename ...Y>
constexpr auto or_t::operator()(X&& x, Y&& ...y) const
{
return detail::variadic::foldl1(
*this,
static_cast<X&&>(x),
static_cast<Y&&>(y)...
);
}
*/
}

}
}

+ 46
- 0
src/cpputils/mp/operations/second.h View File

@@ -0,0 +1,46 @@
#pragma once

#include <cpputils/mp/util/when.h>
#include <cpputils/mp/util/tag_of.h>
#include <cpputils/mp/util/default.h>

namespace utl {
namespace mp {

namespace __impl
{
struct second_t
{
template<typename T>
constexpr auto operator()(T&& t) const;
};
}

constexpr __impl::second_t second { };

namespace __impl
{
template <typename T, typename = void>
struct second_impl
: second_impl<T, when<true>>
{ };

template <typename T, bool condition>
struct second_impl<T, when<condition>>
: default_
{
template <typename ...Args>
static constexpr auto apply(Args&& ...) = delete;
};

template<typename T>
constexpr auto second_t::operator()(T&& t) const
{
using tag = tag_of<T>;
using second = second_impl<tag>;
return second::apply(std::forward<T>(t));
}
}

}
}

+ 54
- 0
src/cpputils/mp/operations/value.h View File

@@ -0,0 +1,54 @@
#pragma once

#include <cpputils/mp/util/when.h>
#include <cpputils/mp/util/tag_of.h>
#include <cpputils/mp/util/default.h>

namespace utl {
namespace mp {

namespace __impl
{
template<typename T, typename = void>
struct value_impl;
}

template <typename T>
constexpr auto value()
{
using t_clean_type = clean_type<T>;
using tag_type = tag_of<T>;
using value_impl_type = __impl::value_impl<tag_type>;
return value_impl_type::template apply<t_clean_type>();
}

template <typename T>
constexpr decltype(auto) value(T const&)
{ return value<T>(); }

namespace __impl
{
template <typename T, typename>
struct value_impl
: value_impl<T, when<true>>
{ };

template <typename T, bool condition>
struct value_impl<T, when<condition>>
: default_
{
template <typename ...Args>
static constexpr auto apply(Args&& ...args) = delete;
};

template <typename T>
struct value_impl<tag_const<T>>
{
template <typename C>
static constexpr auto apply()
{ return C::value; }
};
}

}
}

+ 8
- 151
src/cpputils/mp/util.h View File

@@ -1,151 +1,8 @@
#include "core.h"

namespace utl {
namespace mp {

namespace __impl /* forward declaration */
{
/* when */
template<typename...>
struct is_valid_impl;

template<typename...>
struct wrong_impl;

/* default */
template<typename T, typename = void>
struct is_default_impl;

/* tag_of */
template<typename T, typename = void>
struct tag_of_impl;

/* is_a */
template<typename Tag, typename ...T>
struct is_a_impl;

/* make */
template<typename Tag>
struct make_t;
}

/* when */
template<typename... T>
using is_valid = __impl::is_valid_impl<T...>;

template<typename... T>
using wrong = __impl::wrong_impl<T...>;

template<bool condition>
struct when;

template<typename... T>
using when_valid = when<is_valid<T...>::value>;

/* default */
template<typename T>
using is_default = __impl::is_default_impl<T>;

/* tag_of */
template<typename T>
using tag_of = typename __impl::tag_of_impl<T>::type;

/* is_a */
template<typename Tag, typename... T>
constexpr __impl::is_a_impl<Tag, T...> is_a { };

template<typename Tag, typename... T>
constexpr __impl::is_a_impl<Tag, T...> is_an { };

/* make */
template<typename Tag>
constexpr __impl::make_t<Tag> make { };

namespace __impl /* implementation */
{
/* when */
template<typename...>
struct is_valid_impl :
public c_true
{ };

template<typename...>
struct wrong_impl :
public c_false
{ };

/* default */
struct default_ { };

template<typename T, typename>
struct is_default_impl :
public c_false
{ };

template<typename T>
struct is_default_impl<T, decltype((void)static_cast<default_>(std::declval<T>()))> :
public c_true
{ };

/* tag_of */
template<typename T, typename>
struct tag_of_impl :
public tag_of_impl<T, when<true>>
{ };

template<typename T, bool condition>
struct tag_of_impl<T, when<condition>>
{ using type = T; };

template<typename T>
struct tag_of_impl<T, when_valid<typename clean_type<T>::tag>>
{ using type = typename clean_type<T>::tag; };

/* is_a */
template<typename Tag, typename T>
struct is_a_impl<Tag, T> :
public is_same<Tag, tag_of<T>>
{ };

template<typename Tag>
struct is_a_impl<Tag>
{
template<typename T>
constexpr auto operator()(const T&) const noexcept
{ return is_a<Tag, T>; }
};

/* make */
template<typename T, typename = void>
struct make_impl :
public make_impl<T, when<true>>
{ };

template<typename T, bool condition>
struct make_impl<T, when<condition>> :
public default_
{
template<typename... X>
static constexpr auto make_helper(int, X&&... x)
-> decltype(T(std::forward<X>(x)...))
{ return T(std::forward<X>(x)...); }

template<typename... X>
static constexpr auto make_helper(long, X&&... x)
{ static_assert((sizeof...(X), false), "there exists no constructor for the given data type"); }

template <typename... X>
static constexpr auto apply(X&& ...x)
{ return make_helper(int{}, std::forward<X>(x)...); }
};

template<typename T>
struct make_t
{
template<typename... X>
constexpr auto operator()(X&&... x) const noexcept
{ return make_impl<T>::apply(std::forward<X>(x)...); }
};
}
}
}
#pragma once

#include <cpputils/mp/util/default.h>
#include <cpputils/mp/util/is_a.h>
#include <cpputils/mp/util/make.h>
#include <cpputils/mp/util/tag_of.h>
#include <cpputils/mp/util/when.h>
#include <cpputils/mp/util/to.h>

+ 33
- 0
src/cpputils/mp/util/default.h View File

@@ -0,0 +1,33 @@
#pragma once

#include <cpputils/mp/core/const.h>

namespace utl {
namespace mp {

namespace __impl /* forward declaration */
{
template<typename T, typename = void>
struct is_default_impl;
}

template<typename T>
using is_default = __impl::is_default_impl<T>;

namespace __impl /* implementation */
{
struct default_ { };

template<typename T, typename>
struct is_default_impl :
public c_false
{ };

template<typename T>
struct is_default_impl<T, decltype((void)static_cast<default_>(std::declval<T>()))> :
public c_true
{ };
}

}
}

+ 38
- 0
src/cpputils/mp/util/is_a.h View File

@@ -0,0 +1,38 @@
#pragma once

#include <cpputils/mp/util/when.h>
#include <cpputils/mp/util/tag_of.h>

namespace utl {
namespace mp {

namespace __impl /* forward declaration */
{
template<typename Tag, typename ...T>
struct is_a_impl;
}

template<typename Tag, typename... T>
constexpr __impl::is_a_impl<Tag, T...> is_a { };

template<typename Tag, typename... T>
constexpr __impl::is_a_impl<Tag, T...> is_an { };

namespace __impl /* implementation */
{
template<typename Tag, typename T>
struct is_a_impl<Tag, T> :
public is_same<Tag, tag_of<T>>
{ };

template<typename Tag>
struct is_a_impl<Tag>
{
template<typename T>
constexpr auto operator()(const T&) const noexcept
{ return is_a<Tag, T>; }
};
}

}
}

+ 55
- 0
src/cpputils/mp/util/make.h View File

@@ -0,0 +1,55 @@

#pragma once

#include <utility>
#include <cpputils/mp/util/when.h>
#include <cpputils/mp/util/default.h>

namespace utl {
namespace mp {

namespace __impl /* forward declaration */
{
template<typename Tag>
struct make_t;
}

template<typename Tag>
constexpr __impl::make_t<Tag> make { };

namespace __impl /* implementation */
{
template<typename T, typename = void>
struct make_impl :
public make_impl<T, when<true>>
{ };

template<typename T, bool condition>
struct make_impl<T, when<condition>> :
public default_
{
template<typename... X>
static constexpr auto make_helper(int, X&&... x)
-> decltype(T(std::forward<X>(x)...))
{ return T(std::forward<X>(x)...); }

template<typename... X>
static constexpr auto make_helper(long, X&&... x)
{ static_assert((sizeof...(X), false), "there exists no constructor for the given data type"); }

template <typename... X>
static constexpr auto apply(X&& ...x)
{ return make_helper(int{}, std::forward<X>(x)...); }
};

template<typename T>
struct make_t
{
template<typename... X>
constexpr auto operator()(X&&... x) const noexcept
{ return make_impl<T>::apply(std::forward<X>(x)...); }
};
}

}
}

+ 35
- 0
src/cpputils/mp/util/tag_of.h View File

@@ -0,0 +1,35 @@
#pragma once

#include <cpputils/mp/core/modifier.h>
#include <cpputils/mp/util/when.h>

namespace utl {
namespace mp {

namespace __impl /* forward declaration */
{
template<typename T, typename = void>
struct tag_of_impl;
}

template<typename T>
using tag_of = typename __impl::tag_of_impl<clean_type<T>>::type;

namespace __impl /* implementation */
{
template<typename T, typename>
struct tag_of_impl :
public tag_of_impl<T, when<true>>
{ };

template<typename T, bool condition>
struct tag_of_impl<T, when<condition>>
{ using type = T; };

template<typename T>
struct tag_of_impl<T, when_valid<typename clean_type<T>::tag>>
{ using type = typename clean_type<T>::tag; };
}

}
}

src/cpputils/mp/convert.h → src/cpputils/mp/util/to.h View File

@@ -1,39 +1,41 @@
#include "util.h"
#pragma once

#include <cpputils/mp/util/when.h>
#include <cpputils/mp/util/tag_of.h>
#include <cpputils/mp/core/conditionals.h>

namespace utl {
namespace mp {

namespace __impl /* forward declaration */
{
/* to */
template<typename To>
struct to_t;

template <typename From, typename To, typename = void>
struct is_convertible_impl;
struct is_mp_convertible_impl;

template <typename From, typename To, typename = void>
struct is_embedded_impl;
}

/* to */
template<typename To>
constexpr __impl::to_t<To> to { };

template <typename From, typename To>
using is_convertible = __impl::is_convertible_impl<From, To>;
using is_mp_convertible = __impl::is_mp_convertible_impl<From, To>;

template <typename From, typename To>
using is_embedded = __impl::is_embedded_impl<From, To>;

namespace __impl /* implementation */
{
/* to */
struct no_conversion { };

template <bool = true>
struct embedding { };

/* to_impl */
template <typename To, typename From, typename = void>
struct to_impl;

@@ -68,6 +70,15 @@ namespace mp {
{ return std::forward<X&&>(x); }
};

template <typename T>
struct to_impl<T*, decltype(nullptr)> :
public embedding<>
{
static constexpr T* apply(decltype(nullptr))
{ return nullptr; }
};

/* to_t */
template <typename To>
struct to_t
{
@@ -138,24 +149,18 @@ namespace mp {

#undef DEFINE_CHAR_EMBEDDING_IMPL

template <typename T>
struct to_impl<T*, decltype(nullptr)> :
public embedding<>
{
static constexpr T* apply(decltype(nullptr))
{ return nullptr; }
};

/* is_mp_convertible_impl */
template <typename From, typename To, typename>
struct is_convertible_impl :
struct is_mp_convertible_impl :
public std::true_type
{ };

template <typename From, typename To>
struct is_convertible_impl<From, To, decltype((void) static_cast<no_conversion>(std::declval<to_impl<To, From>>()))> :
struct is_mp_convertible_impl<From, To, decltype((void) static_cast<no_conversion>(std::declval<to_impl<To, From>>()))> :
public std::false_type
{ };

/* is_embedded_impl */
template <typename From, typename To, typename>
struct is_embedded_impl :
public std::false_type

+ 32
- 0
src/cpputils/mp/util/when.h View File

@@ -0,0 +1,32 @@
#pragma once

#include <cpputils/mp/core/checker.h>

namespace utl {
namespace mp {

namespace __impl /* forward declaration */
{
template<typename...>
struct wrong_impl;
}

template<bool condition>
struct when;

template<typename... T>
using when_valid = when<is_valid<T...>::value>;

template<typename... T>
using wrong = __impl::wrong_impl<T...>;

namespace __impl /* implementation */
{
template<typename...>
struct wrong_impl :
public c_false
{ };
}

}
}

+ 119
- 0
src/impl/logging/LoggerImpl.cpp.old View File

@@ -0,0 +1,119 @@
#include <list>
#include <iomanip>

#include "cpputils/logger_impl.h"

using namespace logging;

std::string EmptyString;

consumer::consumer(const std::string& n, bool autoRegister) :
_name(n)
{
if (autoRegister)
register_consumer(*this);
}

consumer::~consumer()
{ unregister_consumer(*this); }

void consumer_stream::log(data_ptr_s data)
{
std::lock_guard<std::mutex> lk(_mutex);

using namespace std;
if (!data)
return;
auto& d = *data;
auto t = std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(d.time.time_since_epoch()).count();
auto f = d.file;
if (f)
{
auto tmp = strrchr(f, '/');
if (tmp)
f = tmp + 1;
}
else
f = "unknown";

StreamFormatSaver formatSaver(*_stream);
if (t >= 0) *_stream << "[" << fixed << setfill(' ') << setw(17) << setprecision(6) << t << "] ";
switch(d.level)
{
case level::Debug: *_stream << "DEBUG "; break;
case level::Info: *_stream << "INFO "; break;
case level::Warn: *_stream << "WARN "; break;
case level::Error: *_stream << "ERROR "; break;
}

if (d.sender) *_stream << "0x" << hex << setw(2 * sizeof(void*)) << setfill('0') << d.sender;
else *_stream << " ";
if (d.thread != std::thread::id()) *_stream << "@" << hex << setw(2 * sizeof(void*)) << setfill('0') << d.thread;
else *_stream << " ";
if (!d.name.empty()) *_stream << " '" << d.name << "'";
if (d.line) *_stream << " - " << setw(25) << setfill(' ') << f << ":" << setw(5) << setfill(' ') << dec << d.line;
if (!d.message.empty())
{
*_stream << ": " << d.message;
if (d.message.back() != '\n')
*_stream << std::endl;
}
else
*_stream << std::endl;
}



bool matcher_all::match(const logger& logger) const
{ return true; }

bool matcher_all::match(const consumer& consumer) const
{ return true; }

bool matcher_regex::match(const logger& logger) const
{ return !logger.name().empty() && std::regex_match(logger.name(), _regex) != _invert; }

bool matcher_regex::match(const consumer& consumer) const
{ return !consumer.name().empty() && std::regex_match(consumer.name(), _regex) != _invert; }

bool matcher_default::match(const logger& logger) const
{ return &_defaultLogger == &logger; }




const std::string& logger::name() const
{ return EmptyString; }

bool logger::is_enabled(level level) const
{ return false; }

void logger::log(data_ptr_s data) const
{ /* no op */ }



const std::string& logger_impl::name() const
{ return _name; }

bool logger_impl::is_enabled(level level) const
{
for (auto& rule : _rules)
{
if (rule->is_enabled(level))
return true;
}
return false;
}

void logger_impl::log(data_ptr_s data) const
{
std::lock_guard<std::mutex> lk(_mutex);
for (auto& r : _rules)
r->log(data);
}

namespace logging
{
}

+ 14
- 0
src/impl/logging/consumer/consumer.cpp View File

@@ -0,0 +1,14 @@
#include <cpputils/logging/logger_impl.h>
#include <cpputils/logging/consumer/consumer.h>

using namespace ::utl::logging;

consumer::consumer(const std::string& n, bool autoRegister) :
_name(n)
{
if (autoRegister)
register_consumer(*this);
}

consumer::~consumer()
{ unregister_consumer(*this); }

+ 66
- 0
src/impl/logging/consumer/consumer_stream.cpp View File

@@ -0,0 +1,66 @@
#include <cstring>
#include <cpputils/misc/stream.h>
#include <cpputils/logging/consumer/consumer_stream.h>

using namespace ::utl;
using namespace ::utl::logging;

void consumer_stream::log(data_ptr_s data)
{
std::lock_guard<std::mutex> lk(_mutex);

using namespace std;
if (!data)
return;
auto& d = *data;
auto t = std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(d.time.time_since_epoch()).count();
auto f = d.file;
if (f)
{
auto tmp = strrchr(f, '/');
if (tmp)
f = tmp + 1;
}
else
f = "unknown";

stream_format_saver format_saver(*_stream);
if (t >= 0) *_stream << "[" << fixed << setfill(' ') << setw(17) << setprecision(6) << t << "] ";
switch(d.level)
{
case log_level::debug: *_stream << "DEBUG "; break;
case log_level::info: *_stream << "INFO "; break;
case log_level::warn: *_stream << "WARN "; break;
case log_level::error: *_stream << "ERROR "; break;
}

if (d.sender) *_stream << "0x" << hex << setw(2 * sizeof(void*)) << setfill('0') << d.sender;
else *_stream << " ";
if (d.thread != std::thread::id()) *_stream << "@" << hex << setw(2 * sizeof(void*)) << setfill('0') << d.thread;
else *_stream << " ";
if (!d.name.empty()) *_stream << " '" << d.name << "'";
if (d.line) *_stream << " - " << setw(25) << setfill(' ') << f << ":" << setw(5) << setfill(' ') << dec << d.line;
if (!d.message.empty())
{
*_stream << ": " << d.message;
if (d.message.back() != '\n')
*_stream << std::endl;
}
else
*_stream << std::endl;
}

consumer_stream::consumer_stream(const std::string& name, std::ostream& stream, bool ownsStream, bool autoRegister) :
consumer (name, autoRegister),
_stream (&stream),
_ownsStream (ownsStream)
{ }

consumer_stream::~consumer_stream()
{
if (_ownsStream && _stream)
{
delete _stream;
_stream = nullptr;
}
}

+ 129
- 0
src/impl/logging/global.cpp View File

@@ -0,0 +1,129 @@
#include <map>
#include <list>
#include <chrono>
#include <thread>

#include <cpputils/logging/rule.h>
#include <cpputils/logging/global.h>
#include <cpputils/logging/logger_impl.h>
#include <cpputils/logging/consumer/consumer.h>

namespace utl {
namespace logging {

struct manager
{
private:
logger_impl _default_logger;
std::map<std::string, logger_impl_ptr_u> _logger;
std::list<rule> _rules;
std::set<consumer*> _consumer;

logger_impl& initLogger(logger_impl& logger)
{
for (auto& rule : _rules)
{
if (rule.logger_matcher->match(logger))
logger.registerRule(rule);
}
return logger;
}

public:
inline logger& get_logger(const std::string& name)
{
if (name.empty())
return _default_logger;
auto it = _logger.find(name);
return (it != _logger.end()
? *it->second
: initLogger(*_logger.emplace(name, logger_impl_ptr_u(new logger_impl(name))).first->second));
}

void register_consumer(consumer& consumer)
{
_consumer.insert(&consumer);
for (auto& rule : _rules)
{
if (rule.consumer_matcher->match(consumer))
rule.register_consumer(consumer);
}
}

void unregister_consumer(consumer& consumer)
{
for (auto& rule : _rules)
rule.unregister_consumer(consumer);
}

rule_handle define_rule(matcher_ptr_u logger_matcher, matcher_ptr_u consumer_matcher, log_level min_level, log_level max_level)
{
_rules.emplace_back(std::move(logger_matcher), std::move(consumer_matcher), min_level, max_level);
auto& rule = _rules.back();
for (auto& c : _consumer)
{
if (rule.consumer_matcher->match(*c))
rule.register_consumer(*c);
}
if (rule.logger_matcher->match(_default_logger))
_default_logger.registerRule(rule);
for (auto& l : _logger)
{
if (rule.logger_matcher->match(*l.second))
l.second->registerRule(rule);
}
return &rule;
}

void undefine_rule(rule_handle handle)
{
auto r = static_cast<rule*>(handle);
auto it = _rules.begin();
while (&*it != r && it != _rules.end())
++it;
if (it == _rules.end())
return;
_default_logger.unregisterRule(*it);
for (auto& l : _logger)
l.second->unregisterRule(*it);
_rules.erase(it);
}

inline void reset()
{
_logger.clear();
_rules.clear();
_consumer.clear();
}

manager() :
_default_logger(std::string())
{ }
};

manager& get_manager()
{
static manager value;
return value;
}

logger& get_logger(const std::string& name)
{ return get_manager().get_logger(name); }

void register_consumer(consumer& consumer)
{ return get_manager().register_consumer(consumer); }

void unregister_consumer(consumer& consumer)
{ return get_manager().unregister_consumer(consumer); }

rule_handle define_rule(matcher_ptr_u logger_matcher, matcher_ptr_u consumer_matcher, log_level min_level, log_level max_level)
{ return get_manager().define_rule(std::move(logger_matcher), std::move(consumer_matcher), min_level, max_level); }

void undefine_rule(rule_handle rule)
{ return get_manager().undefine_rule(rule); }

void reset_logging()
{ get_manager().reset(); }

}
}

+ 15
- 0
src/impl/logging/logger.cpp View File

@@ -0,0 +1,15 @@
#include <cpputils/logging/logger.h>

using namespace ::utl::logging;

const std::string& logger::name() const
{
static std::string name;
return name;
}

bool logger::is_enabled(log_level level) const
{ return false; }

void logger::log(data_ptr_s data) const
{ /* no op */ }

+ 23
- 0
src/impl/logging/logger_impl.cpp View File

@@ -0,0 +1,23 @@
#include <cpputils/logging/logger_impl.h>

using namespace ::utl::logging;

const std::string& logger_impl::name() const
{ return _name; }

bool logger_impl::is_enabled(log_level level) const
{
for (auto& rule : _rules)
{
if (rule->is_enabled(level))
return true;
}
return false;
}

void logger_impl::log(data_ptr_s data) const
{
std::lock_guard<std::mutex> lk(_mutex);
for (auto& r : _rules)
r->log(data);
}

+ 41
- 0
src/impl/logging/matcher.cpp View File

@@ -0,0 +1,41 @@
#include <cpputils/logging/matcher.h>

using namespace ::utl::logging;

/* matcher */

bool matcher::match(const logger& logger) const
{ return false; }

bool matcher::match(const consumer& consumer) const
{ return false; }

/* matcher_all */

bool matcher_all::match(const logger& logger) const
{ return true; }

bool matcher_all::match(const consumer& consumer) const
{ return true; }

/* matcher_regex */

bool matcher_regex::match(const logger& logger) const
{ return !logger.name().empty() && std::regex_match(logger.name(), _regex) != _invert; }

bool matcher_regex::match(const consumer& consumer) const
{ return !consumer.name().empty() && std::regex_match(consumer.name(), _regex) != _invert; }

matcher_regex::matcher_regex(const std::string expression, bool invert) :
_regex (expression),
_invert (invert)
{ }

/* matcher_default */

bool matcher_default::match(const logger& logger) const
{ return &_defaultLogger == &logger; }

matcher_default::matcher_default() :
_defaultLogger(get_logger(std::string()))
{ }

+ 1
- 0
test/CMakeLists.txt View File

@@ -8,6 +8,7 @@ If ( __COTIRE_INCLUDED )
EndIf ( )
Target_Link_Libraries (
test_cpputils
cpputils
gtest
gmock
gmock_main


+ 0
- 61
test/EnumConversionTests.cpp View File

@@ -1,61 +0,0 @@
#include <gtest/gtest.h>

namespace enum_conversion_tests
{
#include "../src/cpputils/EnumConversion.h"

enum class TestEnum
{
Test0,
Test1,
Test2,
Test3
};

DefEnumToStringMap(
TestEnum,
{ TestEnum::Test0, "Test0" },
{ TestEnum::Test1, "Test1" },
{ TestEnum::Test2, "Test2" },
{ TestEnum::Test3, "Test3" }
);

DefStringToEnumMap(
TestEnum,
InvariantStringLess,
{ "test0", TestEnum::Test0 },
{ "test1", TestEnum::Test1 },
{ "test2", TestEnum::Test2 },
{ "test3", TestEnum::Test3 }
);
}

using namespace ::testing;
using namespace ::enum_conversion_tests;
using namespace ::enum_conversion_tests::utl;

TEST(EnumConversionTests, toString)
{
EXPECT_EQ(std::string("Test0(0)"), utl::EnumConversion<TestEnum>::toString(TestEnum::Test0, true));
EXPECT_EQ(std::string("Test1"), utl::EnumConversion<TestEnum>::toString(TestEnum::Test1, false));
EXPECT_EQ(std::string("Test2(2)"), utl::EnumConversion<TestEnum>::toString(TestEnum::Test2, true));
EXPECT_EQ(std::string("Test3"), utl::EnumConversion<TestEnum>::toString(TestEnum::Test3, false));
EXPECT_EQ(std::string("123"), utl::EnumConversion<TestEnum>::toString(static_cast<TestEnum>(123), true));
}

TEST(EnumConversionTests, toEnum)
{
TestEnum e;
EXPECT_TRUE (utl::EnumConversion<TestEnum>::tryToEnum("test0", e, false));
EXPECT_EQ (TestEnum::Test0, e);

EXPECT_TRUE (utl::EnumConversion<TestEnum>::tryToEnum("Test1", e, false));
EXPECT_EQ (TestEnum::Test1, e);

EXPECT_FALSE(utl::EnumConversion<TestEnum>::tryToEnum("asd", e, false));

EXPECT_FALSE(utl::EnumConversion<TestEnum>::tryToEnum("1", e, false));

EXPECT_TRUE (utl::EnumConversion<TestEnum>::tryToEnum("2", e, true));
EXPECT_EQ (TestEnum::Test2, e);
}

+ 0
- 76
test/FlagsTests.cpp View File

@@ -1,76 +0,0 @@
#include <gtest/gtest.h>

namespace flags_tests
{
#include "../src/cpputils/Flags.h"
}

using namespace ::testing;
using namespace ::flags_tests::utl;

enum class TestFlag : uint8_t
{
value0,
value1,
value2,
value3,
value4
};

using TestFlags = ShiftedFlags<TestFlag>;

TEST(FlagsTest, ctor)
{
TestFlags f0;
EXPECT_EQ(0, f0());

TestFlags f1({ TestFlag::value1, TestFlag::value3 });
EXPECT_EQ(10, f1());

TestFlags f2(f1);
EXPECT_EQ(10, f2());

TestFlags f3(TestFlag::value3);
EXPECT_EQ(8, f3());
}

TEST(FlagsTest, set)
{
TestFlags f;
EXPECT_FALSE(static_cast<bool>(f));
f.set(TestFlag::value1);
EXPECT_TRUE(static_cast<bool>(f));
EXPECT_TRUE(f[TestFlag::value1]);
}

TEST(FlagsTest, isSet)
{
TestFlags f({ TestFlag::value1, TestFlag::value3 });

EXPECT_FALSE(f[TestFlag::value0]);
EXPECT_TRUE (f[TestFlag::value1]);
EXPECT_FALSE(f[TestFlag::value2]);
EXPECT_TRUE (f[TestFlag::value3]);
EXPECT_FALSE(f[TestFlag::value4]);

EXPECT_FALSE(f.isSet(TestFlag::value0));
EXPECT_TRUE (f.isSet(TestFlag::value1));
EXPECT_FALSE(f.isSet(TestFlag::value2));
EXPECT_TRUE (f.isSet(TestFlag::value3));
EXPECT_FALSE(f.isSet(TestFlag::value4));
}

TEST(FlagsTest, clear)
{
TestFlags f({ TestFlag::value1, TestFlag::value3 });
f.clear(TestFlag::value1);
EXPECT_FALSE(f.isSet(TestFlag::value1));
EXPECT_TRUE (f.isSet(TestFlag::value3));
}

TEST(FlagsTest, reset)
{
TestFlags f({ TestFlag::value1, TestFlag::value3 });
f.reset();
EXPECT_FALSE(static_cast<bool>(f));
}

+ 0
- 120
test/HandleManagerTests.cpp View File

@@ -1,120 +0,0 @@
#include <gtest/gtest.h>
#include "../src/cpputils/StringHelper.h"
#include "../src/cpputils/HandleManager.h"

using namespace utl;

using HandleManagerInt = utl::HandleManager<int>;

TEST(HandleManagerTest, fromString_toString)
{
Handle handle;
EXPECT_FALSE(tryFromString("11-22-3344-5566778", handle));
EXPECT_TRUE (tryFromString("11-22-3344-55667788", handle));
EXPECT_EQ (std::string("11-22-3344-55667788"), toString(handle));
EXPECT_TRUE (tryFromString("1122-3344-55667788", handle));
EXPECT_EQ (std::string("11-22-3344-55667788"), toString(handle));
EXPECT_TRUE (tryFromString("11-223344-55667788", handle));
EXPECT_EQ (std::string("11-22-3344-55667788"), toString(handle));
EXPECT_TRUE (tryFromString("11-22-334455667788", handle));
EXPECT_EQ (std::string("11-22-3344-55667788"), toString(handle));
EXPECT_TRUE (tryFromString("1122334455667788", handle));
EXPECT_EQ (std::string("11-22-3344-55667788"), toString(handle));
}

TEST(HandleManagerTest, insert)
{
HandleManagerInt manager;
auto handle = manager.insert(0, 0, 123);
EXPECT_TRUE(static_cast<bool>(handle));
}

TEST(HandleManagerTest, remove)
{
HandleManagerInt manager;
auto handle = manager.insert(0, 0, 123);
EXPECT_FALSE(manager.remove(156161));
EXPECT_FALSE(manager.remove(1136));
EXPECT_FALSE(manager.remove(627624));
EXPECT_FALSE(manager.remove(0));
EXPECT_TRUE (manager.remove(handle));
}

TEST(HandleManagerTest, clear)
{
HandleManagerInt manager;
auto handle1 = manager.insert(0, 0, 123);
manager.clear();
auto handle2 = manager.insert(0, 0, 555);
EXPECT_EQ(handle1, handle2);
}

TEST(HandleManagerTest, isValid)
{
HandleManagerInt manager;
EXPECT_FALSE(manager.isValid(0));
EXPECT_FALSE(manager.isValid(123));
EXPECT_FALSE(manager.isValid(51627));
EXPECT_FALSE(manager.isValid(1513));
EXPECT_FALSE(manager.isValid(16621));

auto handle = manager.insert(0, 0, 123);
EXPECT_TRUE(manager.isValid(handle));
}

TEST(HandleManagerTest, tryGet)
{
int val;
HandleManagerInt manager;
EXPECT_FALSE(manager.tryGet(123, val));
EXPECT_FALSE(manager.tryGet(5132, val));
EXPECT_FALSE(manager.tryGet(6216, val));
EXPECT_FALSE(manager.tryGet(15616724, val));
EXPECT_FALSE(manager.tryGet(12353, val));

auto handle = manager.insert(1, 2, 555);
EXPECT_TRUE(manager.tryGet(handle, val));
EXPECT_EQ (555, val);
}

TEST(HandleManagerTest, get)
{
HandleManagerInt manager;
EXPECT_ANY_THROW(manager.get(123));
EXPECT_ANY_THROW(manager.get(5132));
EXPECT_ANY_THROW(manager.get(6216));
EXPECT_ANY_THROW(manager.get(15616724));
EXPECT_ANY_THROW(manager.get(12353));

auto handle = manager.insert(1, 2, 555);
EXPECT_EQ(555, manager.get(handle));
}

TEST(HandleManagerTest, update)
{
HandleManagerInt manager;
EXPECT_FALSE(manager.update(123, 555));
EXPECT_FALSE(manager.update(5132, 555));
EXPECT_FALSE(manager.update(6216, 555));
EXPECT_FALSE(manager.update(15616724, 555));
EXPECT_FALSE(manager.update(12353, 555));

auto handle = manager.insert(1, 2, 555);
EXPECT_TRUE(manager.update(handle, 554));
EXPECT_EQ (554, manager.get(handle));
}

TEST(HandleManagerTest, set)
{
HandleManagerInt manager;
auto handle = fromString<utl::Handle>("00-00-0001-00000000");
EXPECT_TRUE (manager.set(handle, 555));
EXPECT_EQ (555, manager.get(handle));

handle = fromString<utl::Handle>("00-00-0001-00000000");
EXPECT_TRUE (manager.set(handle, 554));
EXPECT_EQ (554, manager.get(handle));

EXPECT_FALSE(manager.set(fromString<utl::Handle>("00-00-0002-00000000"), 553));
EXPECT_EQ (554, manager.get(handle));
}

+ 0
- 135
test/LoggingTests.cpp View File

@@ -1,135 +0,0 @@
#include <set>
#include <list>
#include <regex>
#include <mutex>
#include <thread>
#include <memory>
#include <chrono>
#include <iostream>
#include <gtest/gtest.h>
#include <gmock/gmock.h>

namespace logging_tests
{
#include "../src/LoggerImpl.cpp"
}

using namespace ::testing;
using namespace ::logging_tests;
using namespace ::logging_tests::logging;

struct LoggingReset
{
~LoggingReset()
{ ::logging_tests::logging::resetLogging(); }
};

struct ConsumerMock : public Consumer
{
MOCK_METHOD1(log, void (DataPtrS data));

ConsumerMock(const std::string& n) :
Consumer(n, true)
{ }
};

MATCHER_P5(MatchLogData, level, sender, thread, name, message, "")
{
if (!arg)
return false;
auto& d = *arg;
return d.level == level
&& d.sender == sender
&& d.thread == thread
&& d.name == name
&& d.message == message;
}

TEST(LoggingTests, AllMatcher)
{
LoggingReset loggingReset;
StreamConsumer c0("TestConsumer1", std::cout, false, false);
StreamConsumer c1("TestConsumer2", std::cout, false, false);

auto& l0 = getLogger();
auto& l1 = getLogger("TestLogger");

AllMatcher matcher;

EXPECT_TRUE(matcher.match(c0));
EXPECT_TRUE(matcher.match(c1));
EXPECT_TRUE(matcher.match(l0));
EXPECT_TRUE(matcher.match(l1));
}

TEST(LoggingTests, DefaultLoggerMatcher)
{
LoggingReset loggingReset;
StreamConsumer c0("TestConsumer1", std::cout, false, false);
StreamConsumer c1("TestConsumer2", std::cout, false, false);

auto& l0 = getLogger();
auto& l1 = getLogger("TestLogger");

DefaultLoggerMatcher matcher;

EXPECT_FALSE(matcher.match(c0));
EXPECT_FALSE(matcher.match(c1));
EXPECT_TRUE (matcher.match(l0));
EXPECT_FALSE(matcher.match(l1));
}

TEST(LoggingTests, RegexMatcher)
{
LoggingReset loggingReset;
StreamConsumer c0("TestConsumer1", std::cout, false, false);
StreamConsumer c1("TestConsumer2", std::cout, false, false);

auto& l0 = getLogger();
auto& l1 = getLogger("TestLogger");

RegexMatcher matcher0("TestConsumer1");
RegexMatcher matcher1("ASEF", true);

EXPECT_TRUE (matcher0.match(c0));
EXPECT_FALSE(matcher0.match(c1));
EXPECT_FALSE(matcher1.match(l0));
EXPECT_TRUE (matcher1.match(l1));
}

TEST(LoggingTests, log)
{
LoggingReset loggingReset;
StrictMock<ConsumerMock> c0("consumer0");
StrictMock<ConsumerMock> c1("Consumer1");

EXPECT_CALL(c0, log(MatchLogData(
Level::Info,
(void*)12,
std::this_thread::get_id(),
std::string("logger0"),
std::string("test1 info"))));

EXPECT_CALL(c0, log(MatchLogData(
Level::Warn,
(void*)13,
std::this_thread::get_id(),
std::string("logger0"),
std::string("test1 warn"))));

defineRule(MatcherPtrU(new RegexMatcher("logger0")), MatcherPtrU(new RegexMatcher("consumer0")), Level::Info, Level::Warn);

auto& l0 = getLogger("logger0");
auto& l1 = getLogger("logger1");

logMessage(l0, Debug, (void*)11, "test1 ") << "debug";
logMessage(l0, Info, (void*)12, "test1 ") << "info";
logMessage(l0, Warn, (void*)13, "test1 ") << "warn";
logMessage(l0, Error, (void*)14, "test1 ") << "error";

logMessage(l1, Debug, (void*)21, "test2 ") << "debug";
logMessage(l1, Info, (void*)22, "test2 ") << "info";
logMessage(l1, Warn, (void*)23, "test2 ") << "warn";
logMessage(l1, Error, (void*)24, "test2 ") << "error";
}


+ 0
- 22
test/MiscTests.cpp View File

@@ -1,22 +0,0 @@
#include <gtest/gtest.h>

namespace utils_tests
{
#include "../src/cpputils/Misc.h"
}

using namespace ::testing;
using namespace ::utils_tests::utl;

TEST(UtilsTests, bitCount)
{
EXPECT_EQ(0, bitCount(0b0000'0000'0000'0000'0000'0000'0000'0000u));
EXPECT_EQ(1, bitCount(0b0000'0000'0000'0000'0000'0000'0000'1000u));
EXPECT_EQ(2, bitCount(0b0000'0000'0000'0000'0000'1000'0000'1000u));
EXPECT_EQ(3, bitCount(0b0000'0000'0010'0000'0000'1000'0000'1000u));
EXPECT_EQ(4, bitCount(0b0010'0000'0010'0000'0000'1000'0000'1000u));
EXPECT_EQ(5, bitCount(0b0010'0000'0010'0000'0000'1000'1000'1000u));
EXPECT_EQ(6, bitCount(0b0010'0000'0010'0000'0000'1000'1000'1001u));
EXPECT_EQ(7, bitCount(0b0010'0000'0010'0000'0000'1000'1000'1101u));
EXPECT_EQ(8, bitCount(0b0010'0100'0010'0000'0000'1000'1000'1101u));
}

+ 0
- 97
test/StringHelperTests.cpp View File

@@ -1,97 +0,0 @@
#include <memory>
#include <type_traits>
#include <gtest/gtest.h>

namespace string_helper_tests
{
#include "../src/cpputils/StringHelper.h"

enum class TestEnum
{
Test0,
Test1,
Test2,
Test3
};

DefEnumToStringMap(
TestEnum,
{ TestEnum::Test0, "Test0" },
{ TestEnum::Test1, "Test1" },
{ TestEnum::Test2, "Test2" },
{ TestEnum::Test3, "Test3" }
);

DefStringToEnumMap(
TestEnum,
InvariantStringLess,
{ "test0", TestEnum::Test0 },
{ "test1", TestEnum::Test1 },
{ "test2", TestEnum::Test2 },
{ "test3", TestEnum::Test3 }
);

struct TestClass1
{
int i;

std::string toString() const
{ return std::to_string(i); }

bool fromString(const std::string& s)
{ return static_cast<bool>(std::istringstream(s) >> i); }
};

struct TestClass2
{
int i;

void toString(std::ostream& os) const
{ os << i; }

static bool fromString(const std::string& s, TestClass2& v)
{ return static_cast<bool>(std::istringstream(s) >> v.i); }
};
}

using namespace ::testing;
using namespace ::string_helper_tests;
using namespace ::string_helper_tests::utl;

TEST(StringHelperTests, toString)
{
EXPECT_EQ(std::string("4.5"), utl::toString(4.5));
EXPECT_EQ(std::string("test"), utl::toString("test"));
EXPECT_EQ(std::string("fuu"), utl::toString(std::string("fuu")));
EXPECT_EQ(std::string("Test1(1)"), utl::toString(TestEnum::Test1));
EXPECT_EQ(std::string("5"), utl::toString(TestClass1 { 5 }));
EXPECT_EQ(std::string("6"), utl::toString(TestClass2 { 6 }));
}

TEST(StringHelperTests, fromString)
{
double d;
EXPECT_FALSE(utl::tryFromString("abc", d));
EXPECT_TRUE (utl::tryFromString("4.5", d));
EXPECT_TRUE (d >= 4.5 && d <= 4.5);

int i;
EXPECT_FALSE(utl::tryFromString("abc", i));
EXPECT_TRUE (utl::tryFromString("123", i));
EXPECT_EQ (123, i);

TestEnum e;
EXPECT_FALSE(utl::tryFromString("abc", e));
EXPECT_TRUE (utl::tryFromString("test1", e));
EXPECT_EQ (TestEnum::Test1, e);

TestClass1 t1;
EXPECT_FALSE(utl::tryFromString("abc", t1));
EXPECT_TRUE (utl::tryFromString("11", t1));
EXPECT_EQ (11, t1.i);

TestClass2 t2;
EXPECT_FALSE(utl::tryFromString("abc", t2));
EXPECT_TRUE (utl::tryFromString("12", t2));
EXPECT_EQ (12, t2.i);
}

+ 120
- 0
test/container/handle_manager.cpp View File

@@ -0,0 +1,120 @@
#include <gtest/gtest.h>
#include <cpputils/misc/string.h>
#include <cpputils/container/handle_manager.h>

using namespace utl;

using handle_manager_int = utl::handle_manager<int>;

TEST(handle_manager_tests, from_string_to_string)
{
handle h;
EXPECT_FALSE(try_from_string("11-22-3344-5566778", h));
EXPECT_TRUE (try_from_string("11-22-3344-55667788", h));
EXPECT_EQ (std::string("11-22-3344-55667788"), to_string(h));
EXPECT_TRUE (try_from_string("1122-3344-55667788", h));
EXPECT_EQ (std::string("11-22-3344-55667788"), to_string(h));
EXPECT_TRUE (try_from_string("11-223344-55667788", h));
EXPECT_EQ (std::string("11-22-3344-55667788"), to_string(h));
EXPECT_TRUE (try_from_string("11-22-334455667788", h));
EXPECT_EQ (std::string("11-22-3344-55667788"), to_string(h));
EXPECT_TRUE (try_from_string("1122334455667788", h));
EXPECT_EQ (std::string("11-22-3344-55667788"), to_string(h));
}

TEST(handle_manager_tests, insert)
{
handle_manager_int manager;
auto handle = manager.insert(0, 0, 123);
EXPECT_TRUE(static_cast<bool>(handle));
}

TEST(handle_manager_tests, remove)
{
handle_manager_int manager;
auto handle = manager.insert(0, 0, 123);
EXPECT_FALSE(manager.remove(156161));
EXPECT_FALSE(manager.remove(1136));
EXPECT_FALSE(manager.remove(627624));
EXPECT_FALSE(manager.remove(0));
EXPECT_TRUE (manager.remove(handle));
}

TEST(handle_manager_tests, clear)
{
handle_manager_int manager;
auto handle1 = manager.insert(0, 0, 123);
manager.clear();
auto handle2 = manager.insert(0, 0, 555);
EXPECT_EQ(handle1, handle2);
}

TEST(handle_manager_tests, is_valid)
{
handle_manager_int manager;
EXPECT_FALSE(manager.is_valid(0));
EXPECT_FALSE(manager.is_valid(123));
EXPECT_FALSE(manager.is_valid(51627));
EXPECT_FALSE(manager.is_valid(1513));
EXPECT_FALSE(manager.is_valid(16621));

auto handle = manager.insert(0, 0, 123);
EXPECT_TRUE(manager.is_valid(handle));
}

TEST(handle_manager_tests, try_get)
{
int val;
handle_manager_int manager;
EXPECT_FALSE(manager.try_get(123, val));
EXPECT_FALSE(manager.try_get(5132, val));
EXPECT_FALSE(manager.try_get(6216, val));
EXPECT_FALSE(manager.try_get(15616724, val));
EXPECT_FALSE(manager.try_get(12353, val));

auto handle = manager.insert(1, 2, 555);
EXPECT_TRUE(manager.try_get(handle, val));
EXPECT_EQ (555, val);
}

TEST(handle_manager_tests, get)
{
handle_manager_int manager;
EXPECT_ANY_THROW(manager.get(123));
EXPECT_ANY_THROW(manager.get(5132));
EXPECT_ANY_THROW(manager.get(6216));
EXPECT_ANY_THROW(manager.get(15616724));
EXPECT_ANY_THROW(manager.get(12353));

auto handle = manager.insert(1, 2, 555);
EXPECT_EQ(555, manager.get(handle));
}

TEST(handle_manager_tests, update)
{
handle_manager_int manager;
EXPECT_FALSE(manager.update(123, 555));
EXPECT_FALSE(manager.update(5132, 555));
EXPECT_FALSE(manager.update(6216, 555));
EXPECT_FALSE(manager.update(15616724, 555));
EXPECT_FALSE(manager.update(12353, 555));

auto handle = manager.insert(1, 2, 555);
EXPECT_TRUE(manager.update(handle, 554));
EXPECT_EQ (554, manager.get(handle));
}

TEST(handle_manager_tests, set)
{
handle_manager_int manager;
auto handle = from_string<utl::handle>("00-00-0001-00000000");
EXPECT_TRUE (manager.set(handle, 555));
EXPECT_EQ (555, manager.get(handle));

handle = from_string<utl::handle>("00-00-0001-00000000");
EXPECT_TRUE (manager.set(handle, 554));
EXPECT_EQ (554, manager.get(handle));

EXPECT_FALSE(manager.set(from_string<utl::handle>("00-00-0002-00000000"), 553));
EXPECT_EQ (554, manager.get(handle));
}

test/NullableTests.cpp → test/container/nullable.cpp View File

@@ -1,50 +1,44 @@
#include <memory>
#include <type_traits>
#include <gtest/gtest.h>
#include <cpputils/container/nullable.h>

namespace nullable_tests
struct TestData
{
#include "../src/cpputils/Nullable.h"
static int ctorCount;
static int dtorCount;

struct TestData
{
static int ctorCount;
static int dtorCount;
TestData()
{ ++ctorCount; }

TestData()
{ ++ctorCount; }
~TestData()
{ ++dtorCount; }
};

~TestData()
{ ++dtorCount; }
};

struct NonCopyableTestData
{
int value;
struct NonCopyableTestData
{
int value;

NonCopyableTestData(int v) :
value(v)
{ }
NonCopyableTestData(int v) :
value(v)
{ }

NonCopyableTestData(NonCopyableTestData&& other) :
value(0)
{ std::swap(value, other.value); }
NonCopyableTestData(NonCopyableTestData&& other) :
value(0)
{ std::swap(value, other.value); }

NonCopyableTestData(const NonCopyableTestData&) = delete;
};
NonCopyableTestData(const NonCopyableTestData&) = delete;
};

using NullableInt = utl::Nullable<int>;
using NullableIntRef = utl::Nullable<int&>;
using NullableString = utl::Nullable<std::string>;
using NullableTestData = utl::Nullable<TestData>;
using NullableNonCopyableTestData = utl::Nullable<NonCopyableTestData>;
using NullableInt = utl::nullable<int>;
using NullableIntRef = utl::nullable<int&>;
using NullableString = utl::nullable<std::string>;
using NullableTestData = utl::nullable<TestData>;
using NullableNonCopyableTestData = utl::nullable<NonCopyableTestData>;

int TestData::ctorCount = 0;
int TestData::dtorCount = 0;
}
int TestData::ctorCount = 0;
int TestData::dtorCount = 0;

using namespace nullable_tests;
using namespace nullable_tests::utl;
using namespace ::utl;
using namespace ::testing;

TEST(NullableTest, ctor_empty)
{
@@ -102,7 +96,7 @@ TEST(NullableTest, movable_object)
NonCopyableTestData data(5);
NullableNonCopyableTestData tmp;
tmp = std::move(data);
ASSERT_TRUE ( tmp.hasValue() );
ASSERT_TRUE ( tmp.has_value() );
ASSERT_EQ ( 5, tmp.value().value );
ASSERT_EQ ( 0, data.value );
}
@@ -110,18 +104,18 @@ TEST(NullableTest, movable_object)
TEST(NullableTest, hasValue_operatorBool)
{
EXPECT_FALSE(static_cast<bool>(NullableInt()));
EXPECT_FALSE(NullableInt().hasValue());
EXPECT_FALSE(NullableInt().has_value());
EXPECT_TRUE (static_cast<bool>(NullableInt(5)));
EXPECT_TRUE (NullableInt(5).hasValue());
EXPECT_TRUE (NullableInt(5).has_value());
}

TEST(NullableTest, reset)
{
NullableTestData n(TestData{});
EXPECT_TRUE (n.hasValue());
EXPECT_TRUE (n.has_value());
int tmp = TestData::dtorCount;
n.reset();
EXPECT_FALSE(n.hasValue());
EXPECT_FALSE(n.has_value());
EXPECT_EQ (tmp + 1, TestData::dtorCount);
}


+ 124
- 0
test/logging/logging_tests.cpp View File

@@ -0,0 +1,124 @@
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <cpputils/logging/matcher.h>
#include <cpputils/logging/consumer.h>
#include <cpputils/logging/logger_impl.h>

using namespace ::testing;
using namespace ::utl::logging;

struct LoggingReset
{
~LoggingReset()
{ reset_logging(); }
};

struct consumer_mock : public consumer
{
MOCK_METHOD1(log, void (data_ptr_s data));

consumer_mock(const std::string& n) :
consumer(n, true)
{ }
};

MATCHER_P5(MatchLogData, level, sender, thread, name, message, "")
{
if (!arg)
return false;
auto& d = *arg;
return d.level == level
&& d.sender == sender
&& d.thread == thread
&& d.name == name
&& d.message == message;
}

TEST(LoggingTests, matcher_all)
{
LoggingReset loggingReset;
consumer_stream c0("TestConsumer1", std::cout, false, false);
consumer_stream c1("TestConsumer2", std::cout, false, false);

auto& l0 = get_logger();
auto& l1 = get_logger("TestLogger");

matcher_all matcher;

EXPECT_TRUE(matcher.match(c0));
EXPECT_TRUE(matcher.match(c1));
EXPECT_TRUE(matcher.match(l0));
EXPECT_TRUE(matcher.match(l1));
}

TEST(LoggingTests, matcher_default)
{
LoggingReset loggingReset;
consumer_stream c0("TestConsumer1", std::cout, false, false);
consumer_stream c1("TestConsumer2", std::cout, false, false);

auto& l0 = get_logger();
auto& l1 = get_logger("TestLogger");

matcher_default matcher;

EXPECT_FALSE(matcher.match(c0));
EXPECT_FALSE(matcher.match(c1));
EXPECT_TRUE (matcher.match(l0));
EXPECT_FALSE(matcher.match(l1));
}

TEST(LoggingTests, matcher_regex)
{
LoggingReset loggingReset;
consumer_stream c0("TestConsumer1", std::cout, false, false);
consumer_stream c1("TestConsumer2", std::cout, false, false);

auto& l0 = get_logger();
auto& l1 = get_logger("TestLogger");

matcher_regex matcher0("TestConsumer1");
matcher_regex matcher1("ASEF", true);

EXPECT_TRUE (matcher0.match(c0));
EXPECT_FALSE(matcher0.match(c1));
EXPECT_FALSE(matcher1.match(l0));
EXPECT_TRUE (matcher1.match(l1));
}

TEST(LoggingTests, log)
{
LoggingReset loggingReset;
StrictMock<consumer_mock> c0("consumer0");
StrictMock<consumer_mock> c1("Consumer1");

EXPECT_CALL(c0, log(MatchLogData(
log_level::info,
(void*)12,
std::this_thread::get_id(),
std::string("logger0"),
std::string("test1 info"))));

EXPECT_CALL(c0, log(MatchLogData(
log_level::warn,
(void*)13,
std::this_thread::get_id(),
std::string("logger0"),
std::string("test1 warn"))));

define_rule(matcher_ptr_u(new matcher_regex("logger0")), matcher_ptr_u(new matcher_regex("consumer0")), log_level::info, log_level::warn);

auto& l0 = get_logger("logger0");
auto& l1 = get_logger("logger1");

log_message(l0, debug, (void*)11, "test1 ") << "debug";
log_message(l0, info, (void*)12, "test1 ") << "info";
log_message(l0, warn, (void*)13, "test1 ") << "warn";
log_message(l0, error, (void*)14, "test1 ") << "error";

log_message(l1, debug, (void*)21, "test2 ") << "debug";
log_message(l1, info, (void*)22, "test2 ") << "info";
log_message(l1, warn, (void*)23, "test2 ") << "warn";
log_message(l1, error, (void*)24, "test2 ") << "error";
}


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save