Skip to content
Snippets Groups Projects
Commit 51f4fc5b authored by Recolic Keghart's avatar Recolic Keghart
Browse files

embed rlib

parent d05fefbb
No related branches found
No related tags found
No related merge requests found
Showing
with 1872 additions and 2 deletions
......@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.5)
project(UDPForwarder)
set(CMAKE_CXX_STANDARD 17)
find_package(rlib)
# find_package(rlib) # included in ./src/lib
find_package(Threads)
set(CMAKE_CXX_FLAGS_DEBUG "-g -DMALLOC_CHECK_=2")
......@@ -30,12 +30,12 @@ if(APPLE)
endif()
include_directories(./src)
include_directories(./src/lib)
# TODO
set(SRC src/main.cc)
add_executable(udp-forwarder ${SRC})
target_link_libraries(udp-forwarder r)
target_link_libraries(udp-forwarder Threads::Threads)
# target_link_libraries(udp-forwarder -static-libgcc -static-libstdc++)
......
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
.vscode/
.idea/
*.gi
tmp/
#ifndef RLIB_FS_STATUS_PRETTYPRINT
#define RLIB_FS_STATUS_PRETTYPRINT
#include <filesystem>
#include <iomanip>
#include <ostream>
#include <string>
#include <rlib/require/cxx17>
namespace rlib::prettyprint {
namespace impl {
inline std::string ftypeToString(const std::filesystem::file_type &t) {
switch(t) {
case std::filesystem::file_type::regular: return "regular file";
case std::filesystem::file_type::directory: return "directory";
case std::filesystem::file_type::symlink: return "symlink";
case std::filesystem::file_type::block: return "block file";
case std::filesystem::file_type::character: return "character file";
case std::filesystem::file_type::fifo: return "fifo";
case std::filesystem::file_type::socket: return "socket";
case std::filesystem::file_type::unknown: return "unknown";
case std::filesystem::file_type::none: return "none";
case std::filesystem::file_type::not_found: return "not_found";
}
return "";
}
inline std::string fsizeToString(const size_t fsize) {
if(fsize < 1024)
return std::to_string(fsize);
const auto KiB = (double)fsize / 1024.;
if(KiB < 1024) return std::to_string(KiB) + "Ki";
const auto MiB = KiB / 1024.;
if(MiB < 1024) return std::to_string(MiB) + "Mi";
const auto GiB = MiB / 1024.;
if(GiB < 1024) return std::to_string(GiB) + "Gi";
const auto TiB = GiB / 1024.;
if(TiB < 1024) return std::to_string(TiB) + "Ti";
const auto PiB = TiB / 1024.;
return std::to_string(PiB) + "Pi";
}
template <typename T>
std::string try_show_file_size(const T &arg) {
try {
return fsizeToString(std::filesystem::file_size(arg));
}
catch(...) {
return "-";
}
}
}
template<typename CharT, typename Traits>
std::basic_ostream<CharT, Traits>&
operator<< (std::basic_ostream<CharT, Traits> &os, const std::filesystem::perms& p) {
return os
<< ((p & std::filesystem::perms::owner_read) != std::filesystem::perms::none ? "r" : "-")
<< ((p & std::filesystem::perms::owner_write) != std::filesystem::perms::none ? "w" : "-")
<< ((p & std::filesystem::perms::owner_exec) != std::filesystem::perms::none ? "x" : "-")
<< ((p & std::filesystem::perms::group_read) != std::filesystem::perms::none ? "r" : "-")
<< ((p & std::filesystem::perms::group_write) != std::filesystem::perms::none ? "w" : "-")
<< ((p & std::filesystem::perms::group_exec) != std::filesystem::perms::none ? "x" : "-")
<< ((p & std::filesystem::perms::others_read) != std::filesystem::perms::none ? "r" : "-")
<< ((p & std::filesystem::perms::others_write) != std::filesystem::perms::none ? "w" : "-")
<< ((p & std::filesystem::perms::others_exec) != std::filesystem::perms::none ? "x" : "-")
;
}
template<typename CharT, typename Traits>
std::basic_ostream<CharT, Traits>&
operator<< (std::basic_ostream<CharT, Traits> &os, const std::filesystem::file_type& t) {
return os << impl::ftypeToString(t);
}
template<typename CharT, typename Traits>
std::basic_ostream<CharT, Traits>&
operator<< (std::basic_ostream<CharT, Traits> &os, const std::filesystem::directory_entry& entry) {
#if RLIB_CXX_STD >= 2020
auto lastWriteInSysClock = std::chrono::clock_cast<std::chrono::system_clock>(entry.last_write_time());
#else
#error A BUG NOT RESOLVED NOW. DO NOT USE THIS LIB.
auto lastWriteInSysClock = entry.last_write_time();
#endif
auto lastWrite = std::chrono::system_clock::to_time_t(lastWriteInSysClock);
return os << entry.status().permissions() << ' ' << impl::try_show_file_size(entry) << ' ' << std::put_time(std::localtime(&lastWrite), "%F %T") << ' ' << entry.status().type();
}
} // end namespace rlib::prettyprint
#endif
// Copyright Louis Delacroix 2010 - 2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// A pretty printing library for C++
//
// Usage:
// Include this header, and operator<< will "just work".
#ifndef H_PRETTY_PRINT
#define H_PRETTY_PRINT
// Recolic add
#if _GLIBCXX_OSTREAM
#include <rlib/sys/os.hpp>
#if RLIB_COMPILER_ID == CC_CLANG
#error In clang, you must include prettyprint.hpp before STD ostream or rlib/stdio.hpp.
#endif
#endif
#include <cstddef>
#include <iterator>
#include <memory>
#include <ostream>
#include <set>
#include <tuple>
#include <type_traits>
#include <unordered_set>
#include <utility>
#include <valarray>
namespace rlib {
namespace _3rdparty {
// 3rd party code begin
namespace pretty_print
{
namespace detail
{
// SFINAE type trait to detect whether T::const_iterator exists.
struct sfinae_base
{
using yes = char;
using no = yes[2];
};
template <typename T>
struct has_const_iterator : private sfinae_base
{
private:
template <typename C> static yes & test(typename C::const_iterator*);
template <typename C> static no & test(...);
public:
static const bool value = sizeof(test<T>(nullptr)) == sizeof(yes);
using type = T;
};
template <typename T>
struct has_begin_end : private sfinae_base
{
private:
template <typename C>
static yes & f(typename std::enable_if<
std::is_same<decltype(static_cast<typename C::const_iterator(C::*)() const>(&C::begin)),
typename C::const_iterator(C::*)() const>::value>::type *);
template <typename C> static no & f(...);
template <typename C>
static yes & g(typename std::enable_if<
std::is_same<decltype(static_cast<typename C::const_iterator(C::*)() const>(&C::end)),
typename C::const_iterator(C::*)() const>::value, void>::type*);
template <typename C> static no & g(...);
public:
static bool const beg_value = sizeof(f<T>(nullptr)) == sizeof(yes);
static bool const end_value = sizeof(g<T>(nullptr)) == sizeof(yes);
};
} // namespace detail
// Holds the delimiter values for a specific character type
template <typename TChar>
struct delimiters_values
{
using char_type = TChar;
const char_type * prefix;
const char_type * delimiter;
const char_type * postfix;
};
// Defines the delimiter values for a specific container and character type
template <typename T, typename TChar>
struct delimiters
{
using type = delimiters_values<TChar>;
static const type values;
};
// Functor to print containers. You can use this directly if you want
// to specificy a non-default delimiters type. The printing logic can
// be customized by specializing the nested template.
template <typename T,
typename TChar = char,
typename TCharTraits = ::std::char_traits<TChar>,
typename TDelimiters = delimiters<T, TChar>>
struct print_container_helper
{
using delimiters_type = TDelimiters;
using ostream_type = std::basic_ostream<TChar, TCharTraits>;
template <typename U>
struct printer
{
static void print_body(const U & c, ostream_type & stream)
{
using std::begin;
using std::end;
auto it = begin(c);
const auto the_end = end(c);
if (it != the_end)
{
for ( ; ; )
{
stream << *it;
if (++it == the_end) break;
if (delimiters_type::values.delimiter != NULL)
stream << delimiters_type::values.delimiter;
}
}
}
};
print_container_helper(const T & container)
: container_(container)
{ }
inline void operator()(ostream_type & stream) const
{
if (delimiters_type::values.prefix != NULL)
stream << delimiters_type::values.prefix;
printer<T>::print_body(container_, stream);
if (delimiters_type::values.postfix != NULL)
stream << delimiters_type::values.postfix;
}
private:
const T & container_;
};
// Specialization for pairs
template <typename T, typename TChar, typename TCharTraits, typename TDelimiters>
template <typename T1, typename T2>
struct print_container_helper<T, TChar, TCharTraits, TDelimiters>::printer<std::pair<T1, T2>>
{
using ostream_type = typename print_container_helper<T, TChar, TCharTraits, TDelimiters>::ostream_type;
static void print_body(const std::pair<T1, T2> & c, ostream_type & stream)
{
stream << c.first;
if (print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter != NULL)
stream << print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter;
stream << c.second;
}
};
// Specialization for tuples
template <typename T, typename TChar, typename TCharTraits, typename TDelimiters>
template <typename ...Args>
struct print_container_helper<T, TChar, TCharTraits, TDelimiters>::printer<std::tuple<Args...>>
{
using ostream_type = typename print_container_helper<T, TChar, TCharTraits, TDelimiters>::ostream_type;
using element_type = std::tuple<Args...>;
template <std::size_t I> struct Int { };
static void print_body(const element_type & c, ostream_type & stream)
{
tuple_print(c, stream, Int<0>());
}
static void tuple_print(const element_type &, ostream_type &, Int<sizeof...(Args)>)
{
}
static void tuple_print(const element_type & c, ostream_type & stream,
typename std::conditional<sizeof...(Args) != 0, Int<0>, std::nullptr_t>::type)
{
stream << std::get<0>(c);
tuple_print(c, stream, Int<1>());
}
template <std::size_t N>
static void tuple_print(const element_type & c, ostream_type & stream, Int<N>)
{
if (print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter != NULL)
stream << print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter;
stream << std::get<N>(c);
tuple_print(c, stream, Int<N + 1>());
}
};
// Prints a print_container_helper to the specified stream.
template<typename T, typename TChar, typename TCharTraits, typename TDelimiters>
inline std::basic_ostream<TChar, TCharTraits> & operator<<(
std::basic_ostream<TChar, TCharTraits> & stream,
const print_container_helper<T, TChar, TCharTraits, TDelimiters> & helper)
{
helper(stream);
return stream;
}
// Basic is_container template; specialize to derive from std::true_type for all desired container types
template <typename T>
struct is_container : public std::integral_constant<bool,
detail::has_const_iterator<T>::value &&
detail::has_begin_end<T>::beg_value &&
detail::has_begin_end<T>::end_value> { };
template <typename T, std::size_t N>
struct is_container<T[N]> : std::true_type { };
template <std::size_t N>
struct is_container<char[N]> : std::false_type { };
template <typename T>
struct is_container<std::valarray<T>> : std::true_type { };
template <typename T1, typename T2>
struct is_container<std::pair<T1, T2>> : std::true_type { };
template <typename ...Args>
struct is_container<std::tuple<Args...>> : std::true_type { };
// Default delimiters
template <typename T> struct delimiters<T, char> { static const delimiters_values<char> values; };
template <typename T> const delimiters_values<char> delimiters<T, char>::values = { "[", ", ", "]" };
template <typename T> struct delimiters<T, wchar_t> { static const delimiters_values<wchar_t> values; };
template <typename T> const delimiters_values<wchar_t> delimiters<T, wchar_t>::values = { L"[", L", ", L"]" };
// Delimiters for (multi)set and unordered_(multi)set
template <typename T, typename TComp, typename TAllocator>
struct delimiters< ::std::set<T, TComp, TAllocator>, char> { static const delimiters_values<char> values; };
template <typename T, typename TComp, typename TAllocator>
const delimiters_values<char> delimiters< ::std::set<T, TComp, TAllocator>, char>::values = { "{", ", ", "}" };
template <typename T, typename TComp, typename TAllocator>
struct delimiters< ::std::set<T, TComp, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; };
template <typename T, typename TComp, typename TAllocator>
const delimiters_values<wchar_t> delimiters< ::std::set<T, TComp, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
template <typename T, typename TComp, typename TAllocator>
struct delimiters< ::std::multiset<T, TComp, TAllocator>, char> { static const delimiters_values<char> values; };
template <typename T, typename TComp, typename TAllocator>
const delimiters_values<char> delimiters< ::std::multiset<T, TComp, TAllocator>, char>::values = { "{", ", ", "}" };
template <typename T, typename TComp, typename TAllocator>
struct delimiters< ::std::multiset<T, TComp, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; };
template <typename T, typename TComp, typename TAllocator>
const delimiters_values<wchar_t> delimiters< ::std::multiset<T, TComp, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
template <typename T, typename THash, typename TEqual, typename TAllocator>
struct delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, char> { static const delimiters_values<char> values; };
template <typename T, typename THash, typename TEqual, typename TAllocator>
const delimiters_values<char> delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, char>::values = { "{", ", ", "}" };
template <typename T, typename THash, typename TEqual, typename TAllocator>
struct delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; };
template <typename T, typename THash, typename TEqual, typename TAllocator>
const delimiters_values<wchar_t> delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
template <typename T, typename THash, typename TEqual, typename TAllocator>
struct delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, char> { static const delimiters_values<char> values; };
template <typename T, typename THash, typename TEqual, typename TAllocator>
const delimiters_values<char> delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, char>::values = { "{", ", ", "}" };
template <typename T, typename THash, typename TEqual, typename TAllocator>
struct delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; };
template <typename T, typename THash, typename TEqual, typename TAllocator>
const delimiters_values<wchar_t> delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
// Delimiters for pair and tuple
template <typename T1, typename T2> struct delimiters<std::pair<T1, T2>, char> { static const delimiters_values<char> values; };
template <typename T1, typename T2> const delimiters_values<char> delimiters<std::pair<T1, T2>, char>::values = { "(", ", ", ")" };
template <typename T1, typename T2> struct delimiters< ::std::pair<T1, T2>, wchar_t> { static const delimiters_values<wchar_t> values; };
template <typename T1, typename T2> const delimiters_values<wchar_t> delimiters< ::std::pair<T1, T2>, wchar_t>::values = { L"(", L", ", L")" };
template <typename ...Args> struct delimiters<std::tuple<Args...>, char> { static const delimiters_values<char> values; };
template <typename ...Args> const delimiters_values<char> delimiters<std::tuple<Args...>, char>::values = { "(", ", ", ")" };
template <typename ...Args> struct delimiters< ::std::tuple<Args...>, wchar_t> { static const delimiters_values<wchar_t> values; };
template <typename ...Args> const delimiters_values<wchar_t> delimiters< ::std::tuple<Args...>, wchar_t>::values = { L"(", L", ", L")" };
// Type-erasing helper class for easy use of custom delimiters.
// Requires TCharTraits = std::char_traits<TChar> and TChar = char or wchar_t, and MyDelims needs to be defined for TChar.
// Usage: "cout << pretty_print::custom_delims<MyDelims>(x)".
struct custom_delims_base
{
virtual ~custom_delims_base() { }
virtual std::ostream & stream(::std::ostream &) = 0;
virtual std::wostream & stream(::std::wostream &) = 0;
};
template <typename T, typename Delims>
struct custom_delims_wrapper : custom_delims_base
{
custom_delims_wrapper(const T & t_) : t(t_) { }
std::ostream & stream(std::ostream & s)
{
return s << print_container_helper<T, char, std::char_traits<char>, Delims>(t);
}
std::wostream & stream(std::wostream & s)
{
return s << print_container_helper<T, wchar_t, std::char_traits<wchar_t>, Delims>(t);
}
private:
const T & t;
};
template <typename Delims>
struct custom_delims
{
template <typename Container>
custom_delims(const Container & c) : base(new custom_delims_wrapper<Container, Delims>(c)) { }
std::unique_ptr<custom_delims_base> base;
};
template <typename TChar, typename TCharTraits, typename Delims>
inline std::basic_ostream<TChar, TCharTraits> & operator<<(std::basic_ostream<TChar, TCharTraits> & s, const custom_delims<Delims> & p)
{
return p.base->stream(s);
}
// A wrapper for a C-style array given as pointer-plus-size.
// Usage: std::cout << pretty_print_array(arr, n) << std::endl;
template<typename T>
struct array_wrapper_n
{
typedef const T * const_iterator;
typedef T value_type;
array_wrapper_n(const T * const a, size_t n) : _array(a), _n(n) { }
inline const_iterator begin() const { return _array; }
inline const_iterator end() const { return _array + _n; }
private:
const T * const _array;
size_t _n;
};
// A wrapper for hash-table based containers that offer local iterators to each bucket.
// Usage: std::cout << bucket_print(m, 4) << std::endl; (Prints bucket 5 of container m.)
template <typename T>
struct bucket_print_wrapper
{
typedef typename T::const_local_iterator const_iterator;
typedef typename T::size_type size_type;
const_iterator begin() const
{
return m_map.cbegin(n);
}
const_iterator end() const
{
return m_map.cend(n);
}
bucket_print_wrapper(const T & m, size_type bucket) : m_map(m), n(bucket) { }
private:
const T & m_map;
const size_type n;
};
} // namespace pretty_print
// Global accessor functions for the convenience wrappers
template<typename T>
inline pretty_print::array_wrapper_n<T> pretty_print_array(const T * const a, size_t n)
{
return pretty_print::array_wrapper_n<T>(a, n);
}
template <typename T> pretty_print::bucket_print_wrapper<T>
bucket_print(const T & m, typename T::size_type n)
{
return pretty_print::bucket_print_wrapper<T>(m, n);
}
// Main magic entry point: An overload snuck into namespace std.
// Can we do better?
namespace std
{
// Prints a container to the stream using default delimiters
template<typename T, typename TChar, typename TCharTraits>
inline typename ::std::enable_if< pretty_print::is_container<T>::value,
::std::basic_ostream<TChar, TCharTraits> &>::type
operator<<(::std::basic_ostream<TChar, TCharTraits> & stream, const T & container)
{
return stream << pretty_print::print_container_helper<T, TChar, TCharTraits>(container);
}
}
// 3rd party code end.
}
} // end namespace rlib::3rdparty
namespace rlib {
namespace prettyprint = ::rlib::_3rdparty::std;
}
#endif // H_PRETTY_PRINT
// Copyright Louis Delacroix 2010 - 2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef H_PRETTY_PRINT
#define H_PRETTY_PRINT
#include <ostream>
#include <utility>
#include <iterator>
#include <set>
#ifndef NO_TR1
# include <tr1/tuple>
# include <tr1/unordered_set>
#endif
namespace pretty_print
{
template <bool, typename S, typename T> struct conditional { };
template <typename S, typename T> struct conditional<true, S, T> { typedef S type; };
template <typename S, typename T> struct conditional<false, S, T> { typedef T type; };
template <bool, typename T> struct enable_if { };
template <typename T> struct enable_if<true, T> { typedef T type; };
// SFINAE type trait to detect whether T::const_iterator exists.
template<typename T>
struct has_const_iterator
{
private:
typedef char yes;
typedef struct { char array[2]; } no;
template<typename C> static yes test(typename C::const_iterator*);
template<typename C> static no test(...);
public:
static const bool value = sizeof(test<T>(0)) == sizeof(yes);
typedef T type;
};
// SFINAE type trait to detect whether "T::const_iterator T::begin/end() const" exist.
template <typename T>
struct has_begin_end
{
struct Dummy { typedef void const_iterator; };
typedef typename conditional<has_const_iterator<T>::value, T, Dummy>::type TType;
typedef typename TType::const_iterator iter;
struct Fallback { iter begin() const; iter end() const; };
struct Derived : TType, Fallback { };
template<typename C, C> struct ChT;
template<typename C> static char (&f(ChT<iter (Fallback::*)() const, &C::begin>*))[1];
template<typename C> static char (&f(...))[2];
template<typename C> static char (&g(ChT<iter (Fallback::*)() const, &C::end>*))[1];
template<typename C> static char (&g(...))[2];
static bool const beg_value = sizeof(f<Derived>(0)) == 2;
static bool const end_value = sizeof(g<Derived>(0)) == 2;
};
// Basic is_container template; specialize to have value "true" for all desired container types
template<typename T> struct is_container { static const bool value = has_const_iterator<T>::value && has_begin_end<T>::beg_value && has_begin_end<T>::end_value; };
template<typename T, std::size_t N> struct is_container<T[N]> { static const bool value = true; };
template<std::size_t N> struct is_container<char[N]> { static const bool value = false; };
// Holds the delimiter values for a specific character type
template<typename TChar>
struct delimiters_values
{
typedef TChar char_type;
const TChar * prefix;
const TChar * delimiter;
const TChar * postfix;
};
// Defines the delimiter values for a specific container and character type
template<typename T, typename TChar>
struct delimiters
{
typedef delimiters_values<TChar> type;
static const type values;
};
// Default delimiters
template<typename T> struct delimiters<T, char> { static const delimiters_values<char> values; };
template<typename T> const delimiters_values<char> delimiters<T, char>::values = { "[", ", ", "]" };
template<typename T> struct delimiters<T, wchar_t> { static const delimiters_values<wchar_t> values; };
template<typename T> const delimiters_values<wchar_t> delimiters<T, wchar_t>::values = { L"[", L", ", L"]" };
// Delimiters for (multi)set and unordered_(multi)set
template<typename T, typename TComp, typename TAllocator>
struct delimiters< ::std::set<T, TComp, TAllocator>, char> { static const delimiters_values<char> values; };
template<typename T, typename TComp, typename TAllocator>
const delimiters_values<char> delimiters< ::std::set<T, TComp, TAllocator>, char>::values = { "{", ", ", "}" };
template<typename T, typename TComp, typename TAllocator>
struct delimiters< ::std::set<T, TComp, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; };
template<typename T, typename TComp, typename TAllocator>
const delimiters_values<wchar_t> delimiters< ::std::set<T, TComp, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
template<typename T, typename TComp, typename TAllocator>
struct delimiters< ::std::multiset<T, TComp, TAllocator>, char> { static const delimiters_values<char> values; };
template<typename T, typename TComp, typename TAllocator>
const delimiters_values<char> delimiters< ::std::multiset<T, TComp, TAllocator>, char>::values = { "{", ", ", "}" };
template<typename T, typename TComp, typename TAllocator>
struct delimiters< ::std::multiset<T, TComp, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; };
template<typename T, typename TComp, typename TAllocator>
const delimiters_values<wchar_t> delimiters< ::std::multiset<T, TComp, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
#ifndef NO_TR1
template<typename T, typename THash, typename TEqual, typename TAllocator>
struct delimiters< ::std::tr1::unordered_set<T, THash, TEqual, TAllocator>, char> { static const delimiters_values<char> values; };
template<typename T, typename THash, typename TEqual, typename TAllocator>
const delimiters_values<char> delimiters< ::std::tr1::unordered_set<T, THash, TEqual, TAllocator>, char>::values = { "{", ", ", "}" };
template<typename T, typename THash, typename TEqual, typename TAllocator>
struct delimiters< ::std::tr1::unordered_set<T, THash, TEqual, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; };
template<typename T, typename THash, typename TEqual, typename TAllocator>
const delimiters_values<wchar_t> delimiters< ::std::tr1::unordered_set<T, THash, TEqual, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
template<typename T, typename THash, typename TEqual, typename TAllocator>
struct delimiters< ::std::tr1::unordered_multiset<T, THash, TEqual, TAllocator>, char> { static const delimiters_values<char> values; };
template<typename T, typename THash, typename TEqual, typename TAllocator>
const delimiters_values<char> delimiters< ::std::tr1::unordered_multiset<T, THash, TEqual, TAllocator>, char>::values = { "{", ", ", "}" };
template<typename T, typename THash, typename TEqual, typename TAllocator>
struct delimiters< ::std::tr1::unordered_multiset<T, THash, TEqual, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; };
template<typename T, typename THash, typename TEqual, typename TAllocator>
const delimiters_values<wchar_t> delimiters< ::std::tr1::unordered_multiset<T, THash, TEqual, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
#endif
// Delimiters for pair (reused for tuple, see below)
template<typename T1, typename T2> struct delimiters< ::std::pair<T1, T2>, char> { static const delimiters_values<char> values; };
template<typename T1, typename T2> const delimiters_values<char> delimiters< ::std::pair<T1, T2>, char>::values = { "(", ", ", ")" };
template<typename T1, typename T2> struct delimiters< ::std::pair<T1, T2>, wchar_t> { static const delimiters_values<wchar_t> values; };
template<typename T1, typename T2> const delimiters_values<wchar_t> delimiters< ::std::pair<T1, T2>, wchar_t>::values = { L"(", L", ", L")" };
// Iterator microtrait class to handle C arrays uniformly
template <typename T> struct get_iterator { typedef typename T::const_iterator iter; };
template <typename T, std::size_t N> struct get_iterator<T[N]> { typedef const T * iter; };
template <typename T> typename enable_if<has_const_iterator<T>::value, typename T::const_iterator>::type begin(const T & c) { return c.begin(); }
template <typename T> typename enable_if<has_const_iterator<T>::value, typename T::const_iterator>::type end(const T & c) { return c.end(); }
template <typename T, size_t N> const T * begin(const T(&x)[N]) { return &x[0]; }
template <typename T, size_t N> const T * end (const T(&x)[N]) { return &x[0] + N; }
// Functor to print containers. You can use this directly if you want to specificy a non-default delimiters type.
template<typename T, typename TChar = char, typename TCharTraits = ::std::char_traits<TChar>, typename TDelimiters = delimiters<T, TChar> >
struct print_container_helper
{
typedef TChar char_type;
typedef TDelimiters delimiters_type;
typedef std::basic_ostream<TChar, TCharTraits> ostream_type;
typedef typename get_iterator<T>::iter TIter;
print_container_helper(const T & container)
: _container(container)
{
}
inline void operator()(ostream_type & stream) const
{
if (delimiters_type::values.prefix != NULL)
stream << delimiters_type::values.prefix;
if (begin(_container) != end(_container))
for (TIter it = begin(_container), it_end = end(_container); ; )
{
stream << *it;
if (++it == it_end) break;
if (delimiters_type::values.delimiter != NULL)
stream << delimiters_type::values.delimiter;
}
if (delimiters_type::values.postfix != NULL)
stream << delimiters_type::values.postfix;
}
private:
const T & _container;
};
// Type-erasing helper class for easy use of custom delimiters.
// Requires TCharTraits = std::char_traits<TChar> and TChar = char or wchar_t, and MyDelims needs to be defined for TChar.
// Usage: "cout << pretty_print::custom_delims<MyDelims>(x)".
struct custom_delims_base
{
virtual ~custom_delims_base() { }
virtual ::std::ostream & stream(::std::ostream &) = 0;
virtual ::std::wostream & stream(::std::wostream &) = 0;
};
template<typename T, typename Delims>
struct custom_delims_wrapper : public custom_delims_base
{
custom_delims_wrapper(const T & t_) : t(t_) { }
::std::ostream & stream(::std::ostream & s)
{
return s << ::pretty_print::print_container_helper<T, char, ::std::char_traits<char>, Delims>(t);
}
::std::wostream & stream(::std::wostream & s)
{
return s << ::pretty_print::print_container_helper<T, wchar_t, ::std::char_traits<wchar_t>, Delims>(t);
}
private:
const T & t;
};
template<typename Delims>
struct custom_delims
{
template<typename Container> custom_delims(const Container & c) : base(new custom_delims_wrapper<Container, Delims>(c)) { }
~custom_delims() { delete base; }
custom_delims_base * base;
};
} // namespace pretty_print
template<typename TChar, typename TCharTraits, typename Delims>
inline std::basic_ostream<TChar, TCharTraits> & operator<<(std::basic_ostream<TChar, TCharTraits> & s, const pretty_print::custom_delims<Delims> & p)
{
return p.base->stream(s);
}
// Template aliases for char and wchar_t delimiters
// Enable these if you have compiler support
//
// Implement as "template<T, C, A> const sdelims::type sdelims<std::set<T,C,A>>::values = { ... }."
//template<typename T> using pp_sdelims = pretty_print::delimiters<T, char>;
//template<typename T> using pp_wsdelims = pretty_print::delimiters<T, wchar_t>;
namespace std
{
// Prints a print_container_helper to the specified stream.
template<typename T, typename TChar, typename TCharTraits, typename TDelimiters>
inline basic_ostream<TChar, TCharTraits> & operator<<(basic_ostream<TChar, TCharTraits> & stream,
const ::pretty_print::print_container_helper<T, TChar, TCharTraits, TDelimiters> & helper)
{
helper(stream);
return stream;
}
// Prints a container to the stream using default delimiters
template<typename T, typename TChar, typename TCharTraits>
inline typename ::pretty_print::enable_if< ::pretty_print::is_container<T>::value, basic_ostream<TChar, TCharTraits>&>::type
operator<<(basic_ostream<TChar, TCharTraits> & stream, const T & container)
{
return stream << ::pretty_print::print_container_helper<T, TChar, TCharTraits>(container);
}
// Prints a pair to the stream using delimiters from delimiters<std::pair<T1, T2>>.
template<typename T1, typename T2, typename TChar, typename TCharTraits>
inline basic_ostream<TChar, TCharTraits> & operator<<(basic_ostream<TChar, TCharTraits> & stream, const pair<T1, T2> & value)
{
if (::pretty_print::delimiters<pair<T1, T2>, TChar>::values.prefix != NULL)
stream << ::pretty_print::delimiters<pair<T1, T2>, TChar>::values.prefix;
stream << value.first;
if (::pretty_print::delimiters<pair<T1, T2>, TChar>::values.delimiter != NULL)
stream << ::pretty_print::delimiters<pair<T1, T2>, TChar>::values.delimiter;
stream << value.second;
if (::pretty_print::delimiters<pair<T1, T2>, TChar>::values.postfix != NULL)
stream << ::pretty_print::delimiters<pair<T1, T2>, TChar>::values.postfix;
return stream;
}
} // namespace std
#ifndef NO_TR1
// Prints a tuple to the stream using delimiters from delimiters<std::pair<tuple_dummy_t, tuple_dummy_t>>.
namespace pretty_print
{
struct tuple_dummy_t { }; // Just if you want special delimiters for tuples.
typedef std::pair<tuple_dummy_t, tuple_dummy_t> tuple_dummy_pair;
template<typename Tuple, size_t N, typename TChar, typename TCharTraits>
struct pretty_tuple_helper
{
static inline void print(::std::basic_ostream<TChar, TCharTraits> & stream, const Tuple & value)
{
pretty_tuple_helper<Tuple, N - 1, TChar, TCharTraits>::print(stream, value);
if (delimiters<tuple_dummy_pair, TChar>::values.delimiter != NULL)
stream << delimiters<tuple_dummy_pair, TChar>::values.delimiter;
stream << std::tr1::get<N - 1>(value);
}
};
template<typename Tuple, typename TChar, typename TCharTraits>
struct pretty_tuple_helper<Tuple, 1, TChar, TCharTraits>
{
static inline void print(::std::basic_ostream<TChar, TCharTraits> & stream, const Tuple & value)
{
stream << ::std::tr1::get<0>(value);
}
};
} // namespace pretty_print
/* The following macros allow us to write "template <TUPLE_PARAMAS> std::tuple<TUPLE_ARGS>"
* uniformly in C++0x compilers and in MS Visual Studio 2010.
* Credits to STL: http://channel9.msdn.com/Shows/Going+Deep/C9-Lectures-Stephan-T-Lavavej-Advanced-STL-6-of-n
*/
#define TUPLE_PARAMS \
typename T0, typename T1, typename T2, typename T3, typename T4, \
typename T5, typename T6, typename T7, typename T8, typename T9
#define TUPLE_ARGS T0, T1, T2, T3, T4, T5, T6, T7, T8, T9
namespace std
{
template<typename TChar, typename TCharTraits, TUPLE_PARAMS>
inline basic_ostream<TChar, TCharTraits> & operator<<(basic_ostream<TChar, TCharTraits> & stream, const tr1::tuple<TUPLE_ARGS> & value)
{
if (::pretty_print::delimiters< ::pretty_print::tuple_dummy_pair, TChar>::values.prefix != NULL)
stream << ::pretty_print::delimiters< ::pretty_print::tuple_dummy_pair, TChar>::values.prefix;
::pretty_print::pretty_tuple_helper<const tr1::tuple<TUPLE_ARGS> &, tr1::tuple_size<tr1::tuple<TUPLE_ARGS> >::value, TChar, TCharTraits>::print(stream, value);
if (::pretty_print::delimiters< ::pretty_print::tuple_dummy_pair, TChar>::values.postfix != NULL)
stream << ::pretty_print::delimiters< ::pretty_print::tuple_dummy_pair, TChar>::values.postfix;
return stream;
}
} // namespace std
#endif // NO_TR1
// A wrapper for raw C-style arrays. Usage: int arr[] = { 1, 2, 4, 8, 16 }; std::cout << wrap_array(arr) << ...
namespace pretty_print
{
template<typename T>
struct array_wrapper_n
{
typedef const T * const_iterator;
typedef T value_type;
array_wrapper_n(const T * const a, size_t n) : _array(a), _n(n) { }
inline const_iterator begin() const { return _array; }
inline const_iterator end() const { return _array + _n; }
private:
const T * const _array;
size_t _n;
};
} // namespace pretty_print
template<typename T>
inline pretty_print::array_wrapper_n<T> pretty_print_array(const T * const a, size_t n)
{
return pretty_print::array_wrapper_n<T>(a, n);
}
#endif
#include "prettyprint.hpp"
#include <rlib/stdio.hpp>
#include <list>
using namespace rlib::prettyprint;
int main() {
std::list<int> ls {1,3,2};
std::cout << ls;
}
MIT License
Copyright (c) 2017-2018 Recolic Keghart <root@recolic.net>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
CXX ?= g++
CC ?= gcc
AR ?= ar
CXXFLAGS = -O3 -std=c++14 -fPIC
CFLAGS =
ARFLAGS = rcs
PREFIX ?= /usr
def:
@echo Run make install
install_header:
[ ! -d $(PREFIX)/include/rlib ] || rm -rf $(PREFIX)/include/rlib
cp -r . $(PREFIX)/include/rlib
rm -rf $(PREFIX)/include/rlib/test $(PREFIX)/include/rlib/.git
install_cmake:
[ ! -d $(PREFIX)/lib/cmake/rlib ] || rm -rf $(PREFIX)/lib/cmake/rlib
[ ! -d $(PREFIX)/lib/cmake ] || cp -r cmake $(PREFIX)/lib/cmake/rlib
install: install_header install_cmake
uninstall:
rm -rf $(PREFIX)/include/rlib $(PREFIX)/lib/cmake/rlib
clean:
.PHONY: test
test:
cd test && ./test.sh
# rlib
[![CodeFactor](https://www.codefactor.io/repository/github/recolic/rlib/badge/master)](https://www.codefactor.io/repository/github/recolic/rlib/overview/master)
![AWS CodeBuild](https://codebuild.us-west-1.amazonaws.com/badges?uuid=eyJlbmNyeXB0ZWREYXRhIjoiVUEvK3oxVFAzMlZuZkJlSFE1L1VWSU9IWDBmK0ZpRGZ2clArTDE2UTk4QUZNS1RLUEp2K0lVaVBmNmZjWHNpOXZpRktlOU5RV3k0TjNWcHFKVmVwelJFPSIsIml2UGFyYW1ldGVyU3BlYyI6IllnZUwzWndPSEN4NTFPeGoiLCJtYXRlcmlhbFNldFNlcmlhbCI6MX0%3D&branch=master)
Here is recolic's private library...
# TODO
```c++
RETEST rlib::noncopyable
rlib::stdio fd control is still a problem.
rlib::meta::print_constexpr
rlib::meta::array
rlib::meta::array::to_tuple
rlib::meta::string
#DONE#rlib::logger
```
version: 0.2
phases:
install:
run-as: root
commands:
- make install
pre_build:
commands:
- g++ --version
- clang++ --version
- icpc --version
build:
commands:
- make
- make test
// This header is compatible for ONLY C, requires C99 (double slash comment).
#ifndef RLIB_CWITHCLASS_H_
#define RLIB_CWITHCLASS_H_
//TODO: clean namespace.
//TODO: use macro to type class_name only once.
//#error c_with_class not completed yet
#ifdef __cplusplus
#error You should not use c-with-class.h in real C++.
#endif
#define RCPP_NEW(type,name,constructor_arg) struct type name __attribute__((cleanup(type##_rcpp_destructor)));type##_rcpp_constructor(&name,constructor_arg)
#define RCPP_CALL(i_objectname,i_funcname, ...) i_objectname.i_funcname(&i_objectname, ##__VA_ARGS__) //ONLY static public function can be called directly!!!
#define RCPP_PCALL(p_objectname,i_funcname, ...) p_objectname->i_funcname(p_objectname, ##__VA_ARGS__)
#define RCPP_CLASS_DECL(class_name) struct class_name;
#define RCPP_CLASS_METHOD_EXTERN_DECL(class_name, method_name, return_type, ...) typedef return_type (* class_name##method_name##_rcpp_t)(struct class_name *this, ##__VA_ARGS__); //VAARGS is `int arg1, float arg2, ...`
#define RCPP_CLASS_BEGIN(class_name) struct class_name {
#define RCPP_CLASS_METHOD_DECL(class_name, method_name, ...) RCPP_CLASS_MEMBER_DECL(class_name##method_name##_rcpp_t, method_name)
#define RCPP_CLASS_MEMBER_DECL(type, name) type name;
#define RCPP_CLASS_END() };
#define RCPP_CLASS_METHOD_IMPL(class_name, method_name, return_type, ...) return_type class_name##method_name##_rcpp_impl(struct class_name *this, ##__VA_ARGS__) //VAARGS is `int arg1, float arg2, ...`
#define RCPP_CLASS_CONSTRUCTOR_IMPL(class_name) void class_name##_rcpp_constructor(struct class_name *this, void *arg) //TODO: Register all methods.
#define RCPP_CLASS_METHOD_REGISTER(class_name, method_name) this->method_name = &class_name##method_name##_rcpp_impl;
#define RCPP_CLASS_DESTRUCTOR_IMPL(class_name) void class_name##_rcpp_destructor(struct class_name *this)
#endif
#ifndef RLIB_CLASS_DECO_HPP_
#define RLIB_CLASS_DECO_HPP_
#include <rlib/require/cxx11>
namespace rlib {
namespace _noncp_ {
class noncopyable
{
public:
noncopyable() = default;
~noncopyable() = default;
noncopyable(const noncopyable &) = delete;
noncopyable &operator=(const noncopyable &) = delete;
};
}
typedef _noncp_::noncopyable noncopyable;
}
namespace rlib {
namespace _nonmv_ {
class nonmovable : private noncopyable
{
public:
nonmovable() = default;
~nonmovable() = default;
nonmovable(const nonmovable &&) = delete;
nonmovable &operator=(const nonmovable &&) = delete;
};
}
typedef _nonmv_::nonmovable nonmovable;
}
namespace rlib {
namespace _nonconstructible_ {
class nonconstructible : private rlib::nonmovable
{
public:
nonconstructible() = delete;
~nonconstructible() = delete;
};
}
typedef _nonconstructible_::nonconstructible nonconstructible;
typedef nonconstructible static_class;
}
#endif
\ No newline at end of file
# Use this file if you want to include rlib as a subdirectory
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
# using clang
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
set(rlib_CXX_FLAGS "-Wno-terminate")
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
add_definitions(-DRLIB_MINGW_DISABLE_TLS)
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# using Visual Studio C++
endif()
if(MSYS OR MINGW)
add_definitions(-DRLIB_MINGW_DISABLE_TLS)
endif()
include_directories(..)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
# using clang
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
set(rlib_CXX_FLAGS "-Wno-terminate")
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
add_definitions(-DRLIB_MINGW_DISABLE_TLS)
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# using Visual Studio C++
endif()
if(MSYS OR MINGW)
add_definitions(-DRLIB_MINGW_DISABLE_TLS)
endif()
# use this file if you want to install rlib
set(rlib_INCLUDE_DIRS ${PREFIX}/include)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
# using clang
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
set(rlib_CXX_FLAGS "-Wno-terminate")
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
add_definitions(-DRLIB_MINGW_DISABLE_TLS)
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# using Visual Studio C++
endif()
if(MINGW)
add_definitions(-DRLIB_MINGW_DISABLE_TLS)
endif()
#ifndef RLIB_FUNCTIONAL_HPP_
#define RLIB_FUNCTIONAL_HPP_
#include <rlib/require/cxx17>
#include <rlib/class_decorator.hpp>
#include <rlib/sys/os.hpp>
#include <type_traits>
#include <list>
#include <functional>
#include <chrono>
namespace rlib {
namespace impl {
template <typename Func, typename... Args>
struct repeated_func {
using return_type = typename std::invoke_result<Func, Args ...>::type;
auto operator ()(size_t count, Func f, Args ... args) {
for(size_t cter = 0; cter < count - 1; ++cter)
f(std::forward<Args>(args) ...);
return f(std::forward<Args>(args) ...);
}
};
template <typename Func, typename... Args>
struct repeated_func_return_list {
using return_type = typename std::invoke_result<Func, Args ...>::type;
auto operator ()(size_t count, Func f, Args ... args) {
std::list<return_type> ret;
if(count == 0) return ret;
for(size_t cter = 0; cter < count; ++cter)
ret.push_back(std::move(f(std::forward<Args>(args) ...)));
return ret;
}
};
}
}
namespace rlib {
template <class Func, typename... Args>
constexpr static inline double timeof(Func && f, Args && ... args)
{
auto begin = std::chrono::high_resolution_clock::now();
f(std::forward<Args>(args) ...);
auto end = std::chrono::high_resolution_clock::now();
return ::std::chrono::duration<double>(end - begin).count();
}
template <class Func, typename... Args>
constexpr static inline auto repeat(size_t count, Func && f, Args && ... args)
{
// Unnecessary asserts for debugging.
using return_type = typename std::invoke_result<Func, Args ...>::type;
using return_type2 = typename std::invoke_result<typename impl::repeated_func<Func, Args ...>, size_t, Func, Args ...>::type;
using return_type3 = decltype(impl::repeated_func<Func, Args ...>()(count, f, args ...));
static_assert(std::is_same<return_type, return_type2>::value);
static_assert(std::is_same<return_type, return_type3>::value);
if(count == 0)
throw std::invalid_argument("Can not repeat for zero times.");
return std::bind(impl::repeated_func<Func, Args ...>(), count, std::forward<Func>(f), std::forward<Args>(args) ...);
}
template <class Func, typename... Args>
constexpr static inline auto repeat_and_return_list(size_t count, Func f, Args... args)
{
return std::bind(impl::repeated_func_return_list<Func, Args ...>(), count, std::forward<Func>(f), std::forward<Args>(args) ...);
}
}
namespace std {
#if RLIB_CXX_STD >= 2017
class execution;
#endif
}
// functools here.
#if 0 // not finished
#include <algorithm>
namespace rlib {
template <Iterable buffer_t>
class wrappedIterable : public buffer_t {
public:
using buffer_t::buffer_t;
using buffer_type = buffer_t;
using value_type = buffer_t::value_type;
using this_type = wrappedIterable<buffer_t>;
wrappedIterable(const buffer_t &b) : buffer_t(b) {}
wrappedIterable(buffer_t &&b) : buffer_t(std::forward<buffer_t>(b)) {}
#if RLIB_CXX_STD >= 2017
// std::foreach wrapper
this_type &map(std::execution &&policy, std::function<value_type(const value_type &)> mapper_func) {
std::for_each(std::forward<std::execution>(policy), begin, end, [&mapper_func](value_type &v){v = mapper_func(v);});
}
this_type &map(std::execution &&policy, std::function<void(value_type &)> mapper_func) {
std::for_each(std::forward<std::execution>(policy), begin, end, mapper_func);
}
#endif
// std::foreach wrapper
this_type &map(std::function<value_type(const value_type &)> mapper_func) {
std::for_each(begin, end, [&mapper_func](value_type &v){v = mapper_func(v);});
return *this;
}
this_type &map(std::function<void(value_type &)> mapper_func) {
std::for_each(begin, end, mapper_func);
return *this;
}
this_type &filter(std::function<bool(const value_type &)> filter_func) {
std::remove_if(begin, end, [&filter_func](const value_type &v) -> bool {return !filter_func(v);});
return *this;
}
this_type &flat_map(std::function<buffer_type<value_type>(const value_type &)>) {
}
};
}
#endif
#endif
#ifndef _RLIB_IMPL_TRACEABLE_LIST_HPP
#define _RLIB_IMPL_TRACEABLE_LIST_HPP 1
#include <list>
#include <stdexcept>
#include <utility>
namespace rlib {
namespace impl {
// A double linked list with ability to get iterator from data_t*. Designed for *_object_pool.
// Only implement few necessary functionalibities.
template<typename T, typename extra_info_t>
class traceable_list {
struct node {
/*
* You may not manage data ownness here. Or you must carefully check if (node*)&data works.
*/
T data; // Able to get iterator from T*
node *prev;
node *next;
extra_info_t extra_info; // bool flag. specially designed for object_pool.
uint32_t magic = 0x19990823;
template <typename... TConstructArgs>
node(node *prev, node *next, const extra_info_t &extra_info, TConstructArgs... args)
: data(std::forward<TConstructArgs>(args) ...), prev(prev), next(next), extra_info(extra_info)
{}
};
public:
class iterator : std::bidirectional_iterator_tag {
friend class traceable_list;
public:
using pointer = T *;
using reference = T &;
explicit iterator(node *ptr) : ptr(ptr) {}
explicit iterator(T *data_pointer) : ptr(reinterpret_cast<node *>(data_pointer)) {
if (ptr->magic != 0x19990823)
throw std::invalid_argument(
"magic_num verification failed. invalid data_pointer passed or ruined memory?");
}
T &operator*() {
// If this is an iterator to empty_list.begin(), then nullptr->data throws.
return ptr->data;
}
T *operator->() {
// If this is an iterator to empty_list.begin(), then nullptr->data throws.
return &ptr->data;
}
extra_info_t &get_extra_info() {
return ptr->extra_info;
}
const T &operator*() const {
// If this is an iterator to empty_list.begin(), then nullptr->data throws.
return ptr->data;
}
const T *operator->() const {
// If this is an iterator to empty_list.begin(), then nullptr->data throws.
return &ptr->data;
}
const extra_info_t &get_extra_info() const {
return ptr->extra_info;
}
iterator &operator++() {
ptr = ptr->next;
return *this;
}
const iterator operator++(int) {
iterator backup(ptr);
operator++();
return std::move(backup);
}
iterator &operator--() {
if (!ptr && _impl_tail)
ptr = _impl_tail;
else
ptr = ptr->prev;
return *this;
}
const iterator operator--(int) {
iterator backup(ptr);
operator--();
return std::move(backup);
}
bool operator==(const iterator &another) const {
return ptr == another.ptr;
}
bool operator!=(const iterator &another) const {
return !operator==(another);
}
private:
node *ptr;
iterator(node *ptr, node *tail) : ptr(ptr), _impl_tail(tail) {}
node *_impl_tail = nullptr; // If this iter is created by begin() or end(), it must set this ptr to support end().operator--(), to indicate that this iterator is not invalid.
};
~traceable_list() {
for (auto iter = begin(); iter != end();) {
auto to_release = iter++;
delete to_release.ptr;
}
}
iterator begin() {
return iterator(head, tail);
}
iterator end() {
return iterator((node *) nullptr, tail);
}
template <typename... ConstructArgs>
void emplace_one(const iterator &where, const extra_info_t &extra_info, ConstructArgs... constructArgs) {
auto new_node = new node(nullptr, where.ptr, extra_info, std::forward<ConstructArgs>(constructArgs) ...);
++m_size;
if (!head) {
tail = head = new_node;
return;
};
auto ptr = where.ptr;
if (!ptr) {
// is end();
tail->next = new_node;
new_node->prev = tail;
tail = new_node;
return;
}
auto left = ptr->prev, right = ptr;
new_node->prev = right->prev;
if (left) left->next = new_node;
right->prev = new_node;
if (head == ptr)
head = new_node;
}
void push_one(const iterator &where, T &&data, const extra_info_t &extra_info) {
emplace_one(where, extra_info, std::forward<T>(data));
}
void push_one(const iterator &where, const T &data, const extra_info_t &extra_info) {
T _data(data);
push_one(where, std::move(_data), extra_info);
}
void push_back(T &&data, const extra_info_t &extra_info) {
push_one(end(), std::forward<T>(data), extra_info);
}
void push_back(const T &data, const extra_info_t &extra_info) {
push_one(end(), std::forward<T>(data), extra_info);
}
void push_front(T &&data, const extra_info_t &extra_info) {
push_one(begin(), std::forward<T>(data), extra_info);
}
void push_front(const T &data, const extra_info_t &extra_info) {
push_one(begin(), std::forward<T>(data), extra_info);
}
void pop_one(const iterator &which) {
if (!head)
throw std::invalid_argument("nothing to pop.");
auto ptr = which.ptr;
if (!ptr) {
// end()
throw std::invalid_argument("you may not pop end().");
}
auto left = ptr->prev, right = ptr->next;
if (left) left->next = right;
if (right) right->prev = left;
if (head == ptr)
head = right;
if (tail == ptr)
tail = left;
--m_size;
delete which.ptr;
}
void pop_front() {
pop_one(begin());
}
void pop_back() {
pop_one(--end());
}
void pop_some(const iterator &from, const iterator &to) {
for (auto iter = from; iter != to;) {
auto to_pop = iter++;
pop_one(to_pop);
}
}
size_t size() {
return m_size;
}
private:
node *head = nullptr;
node *tail = nullptr;
size_t m_size = 0;
};
}
}
#endif // _RLIB_IMPL_TRACEABLE_LIST_HPP
#ifndef RLIB_LOG_HPP_
#define RLIB_LOG_HPP_ 1
#include <string>
#include <fstream>
#include <list>
#include <climits>
#include <rlib/sys/os.hpp>
#include <rlib/stdio.hpp>
#include <rlib/sys/time.hpp>
#include <rlib/class_decorator.hpp>
// currently disable this error-prone shit.
#define RLIB_IMPL_ENABLE_LOGGER_FROM_FD 0
#ifndef RLIB_IMPL_ENABLE_LOGGER_FROM_FD
#include <rlib/sys/fd.hpp>
#if RLIB_OS_ID != OS_UNKNOWN
# if RLIB_COMPILER_ID == CC_GCC
# include <ext/stdio_filebuf.h>
# define RLIB_IMPL_ENABLE_LOGGER_FROM_FD 1
# elif RLIB_COMPILER_ID == CC_MSVC
# define RLIB_IMPL_ENABLE_LOGGER_FROM_FD 1
# endif
#endif
#endif
#ifdef ERROR
#pragma message (": warning MSVC_Macro_pollution: You MUST NOT define the macro `ERROR`. I've undefined it here.")
#undef ERROR
#endif
namespace rlib {
using namespace rlib::literals;
// Allow extension.
enum class log_level_t : int { FATAL = 1, ERROR, WARNING, INFO, VERBOSE, DEBUG };
namespace impl {
inline int &max_predefined_log_level() {
static int instance = (int)log_level_t::DEBUG;
return instance;
}
}
/*
How to update log_level_t:
Extend `enum log_level_t ...`
Modify libr.cc:`max_predefined_log_level ...`
Add an RLIB_IMPL_MACRO_LOG_ADD_SHORTHAND
Append logger::predefined_log_level_name
*/
class logger : rlib::noncopyable {
public:
logger() = delete;
logger(std::ostream &stream) : pstream(&stream) {}
logger(const std::string &file_name) : pstream(new std::ofstream(file_name, std::ios::out)),
must_delete_stream_as_ofstream(true) {
if(!dynamic_cast<std::ofstream &>(*pstream))
throw std::runtime_error("Failed to open file {}."_format(file_name));
}
logger(logger &&another) : pstream(another.pstream),
custom_log_level_names(std::move(another.custom_log_level_names)),
log_level(another.log_level),
must_delete_stream_as_ofstream(another.must_delete_stream_as_ofstream),
enable_flush(another.enable_flush)
{another.must_delete_stream_as_ofstream = false;}
~logger() {
if(must_delete_stream_as_ofstream)
delete dynamic_cast<std::ofstream *>(pstream);
}
logger &operator=(logger &&another) {
pstream = another.pstream;
enable_flush = another.enable_flush;
must_delete_stream_as_ofstream = another.must_delete_stream_as_ofstream;
log_level = another.log_level;
custom_log_level_names = std::move(another.custom_log_level_names);
another.must_delete_stream_as_ofstream = false;
return *this;
}
#if RLIB_IMPL_ENABLE_LOGGER_FROM_FD == 1
#if RLIB_OS_ID != OS_UNKNOWN
logger(fd file_descriptor_or_handle)
# if RLIB_COMPILER_ID == CC_GCC
: _gcc_filebuf(file_descriptor_or_handle, std::ios::out), _gcc_real_stream(&_gcc_filebuf),
stream(_gcc_real_stream) {}
# elif RLIB_COMPILER_ID == CC_MSVC
: _msvc_real_stream(::_fdopen(file_descriptor_or_handle, "w")),
stream(_msvc_real_stream) {}
# endif
#endif
#endif
void set_log_level(log_level_t max_level) {
this->log_level = max_level;
}
void set_flush(bool enable_flush) noexcept {
this->enable_flush = enable_flush;
}
template <typename ... Args>
void log(log_level_t level, const std::string &info, Args ... extra_args) const {
if(is_predefined_log_level(level) && level > this->log_level)
return;
(*pstream) << "[{}|{}] {}"_format(get_current_time_str(), log_level_name(level), impl::format_string(info, std::forward<Args>(extra_args) ...)) << RLIB_IMPL_ENDLINE;
if(enable_flush)
pstream->flush();
}
// Warning: this method is not thread-safe.
log_level_t register_log_level(const std::string &name) {
if(impl::max_predefined_log_level() == INT_MAX)
throw std::overflow_error("At most {}(INT_MAX) log_level is allowed."_format(INT_MAX));
++ impl::max_predefined_log_level();
log_level_t new_level = (log_level_t)impl::max_predefined_log_level();
custom_log_level_names.push_back({new_level, name});
return new_level;
}
#define RLIB_IMPL_MACRO_LOG_ADD_SHORTHAND(_name, _enum_name) template <typename ... Args> void _name(const std::string &info, Args ... extra) const { \
log(log_level_t::_enum_name, info, std::forward<Args>(extra) ...); }
RLIB_IMPL_MACRO_LOG_ADD_SHORTHAND(fatal, FATAL)
RLIB_IMPL_MACRO_LOG_ADD_SHORTHAND(error, ERROR)
RLIB_IMPL_MACRO_LOG_ADD_SHORTHAND(warning, WARNING)
RLIB_IMPL_MACRO_LOG_ADD_SHORTHAND(info, INFO)
RLIB_IMPL_MACRO_LOG_ADD_SHORTHAND(verbose, VERBOSE)
RLIB_IMPL_MACRO_LOG_ADD_SHORTHAND(debug, DEBUG)
#undef RLIB_IMPL_MACRO_LOG_ADD_SHORTHAND
private:
static constexpr const char * predefined_log_level_name(log_level_t level) noexcept {
switch(level) {
case log_level_t::FATAL:
return "FATAL";
case log_level_t::ERROR:
return "ERROR";
case log_level_t::WARNING:
return "WARNING";
case log_level_t::INFO:
return "INFO";
case log_level_t::VERBOSE:
return "VERBOSE";
case log_level_t::DEBUG:
return "DEBUG";
default:
return "";
}
}
static constexpr bool is_predefined_log_level(log_level_t level) noexcept {
return predefined_log_level_name(level)[0] != '\0';
}
std::string log_level_name(log_level_t level) const noexcept {
std::string name = predefined_log_level_name(level);
if(!name.empty())
return name;
for(const auto &level_and_name : custom_log_level_names) {
if(level == level_and_name.first) {
name = level_and_name.second;
break;
}
}
if(!name.empty())
return name;
name = "LEVEL-";
name += std::to_string((int)level);
return name;
}
std::ostream *pstream;
std::list<std::pair<log_level_t, std::string> > custom_log_level_names;
log_level_t log_level = log_level_t::INFO; // `Ignore` deadline.
bool must_delete_stream_as_ofstream = false;
bool enable_flush = true;
#if RLIB_IMPL_ENABLE_LOGGER_FROM_FD == 1
# if RLIB_COMPILER_ID == CC_GCC
__gnu_cxx::stdio_filebuf<char> _gcc_filebuf;
std::ostream _gcc_real_stream;
# elif RLIB_COMPILER_ID == CC_MSVC
std::ofstream _msvc_real_stream;
# endif
#endif
};
}
#endif
// This header is compatible for both C and C++, requires C99 (double slash comment).
#ifndef R_MACRO_HPP
#define R_MACRO_HPP
#ifdef RLIB_EMPTY_MACRO
#undef RLIB_EMPTY_MACRO
#endif
#define RLIB_EMPTY_MACRO
#ifndef RLIB_MACRO_DECAY
#define RLIB_MACRO_DECAY(m) (m)
#endif
#ifndef _RLIB_MACRO_ENSTRING
#define _RLIB_MACRO_ENSTRING(_s) #_s
#endif
#ifndef RLIB_MACRO_TO_CSTR
#define RLIB_MACRO_TO_CSTR(m) _RLIB_MACRO_ENSTRING(m)
#endif
//#ifndef RLIB_MACRO_EQL
//#define RLIB_MACRO_EQL(a, b) (RLIB_MACRO_TO_CSTR(a) == RLIB_MACRO_TO_CSTR(b))
//#endif
#ifndef RLIB_MACRO_CAT
#define RLIB_MACRO_CAT(a, b) _RLIB_MACRO_CAT_I(a, b)
#define _RLIB_MACRO_CAT_I(a, b) _RLIB_MACRO_CAT_II(~, a ## b)
#define _RLIB_MACRO_CAT_II(p, res) res
#endif
#ifndef RLIB_MAKE_UNIQUE_NAME
#define RLIB_MAKE_UNIQUE_NAME(base) RLIB_MACRO_CAT(base, __COUNTER__)
#endif
#endif
#ifndef RLIB_MEelement_typeA_HPP_
#define RLIB_MEelement_typeA_HPP_
#include <rlib/sys/os.hpp>
#include <cstddef> // size_t
#include <tuple>
namespace rlib {
#if RLIB_CXX_STD >= 2017
namespace impl {
template <auto first_ele, auto... _>
struct array_first_ele_type_impl { using type = decltype(first_ele); };
}
template <auto... arr>
struct meta_array {
using this_type = typename ::rlib::meta_array<arr ...>;
using element_type = typename ::rlib::impl::array_first_ele_type_impl<arr...>::type;
template <size_t index>
struct at_last {
static constexpr auto value() noexcept {
return at_last_impl<index, arr ...>::value();
}
constexpr operator element_type() {
return at_last<index>::value();
}
};
template <size_t index>
struct at {
static constexpr auto value() {
return at_last<sizeof...(arr) - index - 1>::value();
}
constexpr operator element_type() {
return at<index>::value();
}
};
static constexpr auto to_tuple() {
return std::make_tuple(arr ...);
}
private:
template <size_t index, auto first_ele, auto... _arr>
struct at_last_impl {
static constexpr auto value() {
if constexpr(sizeof...(_arr) == index)
return first_ele;
else
return at_last_impl<index, _arr ...>::value();
}
};
};
#endif
template <size_t... forwardedArgs> struct argForwarder {};
namespace impl {
template <typename T, std::size_t _>
using get_T = T;
template <typename T, std::size_t... _>
auto make_N_tuple_impl_f(std::index_sequence<_ ...>) {
using make_N_tuple_impl = std::tuple<get_T<T, _> ...>;
return make_N_tuple_impl();
}
} // end namespace rlib::impl
template <typename T, std::size_t N>
using N_tuple_t = decltype(impl::make_N_tuple_impl_f<T>(std::make_integer_sequence<std::size_t, N>()));
} // end namespace rlib
#endif
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment