From 5640c382da13e671be5a6b208b37ba9c19795785 Mon Sep 17 00:00:00 2001 From: Recolic Keghart <root@recolic.net> Date: Sun, 29 Dec 2019 01:12:20 +0800 Subject: [PATCH] > Manual commit: adjust build scripts, add rlib:header-only as dependency U201614531 recolic Linux RECOLICPC 5.4.6-arch3-1 #1 SMP PREEMPT Tue, 24 Dec 2019 04:36:53 +0000 x86_64 GNU/Linux 01:12:20 up 6:46, 1 user, load average: 0.78, 0.96, 0.84 f75a49b365c304508914ace65c3ec1846b875c2 --- .gitlab-ci.yml | 12 + nemu/Makefile | 18 +- nemu/include/rlib/.gitignore | 34 + nemu/include/rlib/3rdparty/prettyprint.hpp | 461 +++++++++++++ nemu/include/rlib/3rdparty/prettyprint98.hpp | 410 ++++++++++++ nemu/include/rlib/3rdparty/test.cc | 9 + nemu/include/rlib/LICENSE | 21 + nemu/include/rlib/Makefile | 33 + nemu/include/rlib/README.md | 20 + nemu/include/rlib/buildspec.yaml | 17 + nemu/include/rlib/c-with-class.h | 27 + nemu/include/rlib/class_decorator.hpp | 47 ++ nemu/include/rlib/cmake/CMakeLists.txt | 18 + nemu/include/rlib/cmake/cmake.include | 15 + nemu/include/rlib/cmake/rlib-config.cmake | 17 + nemu/include/rlib/functional.hpp | 125 ++++ nemu/include/rlib/impl/traceable_list.hpp | 225 +++++++ nemu/include/rlib/log.hpp | 188 ++++++ nemu/include/rlib/macro.hpp | 34 + nemu/include/rlib/meta.hpp | 59 ++ nemu/include/rlib/opt.hpp | 126 ++++ nemu/include/rlib/pool.hpp | 129 ++++ nemu/include/rlib/require/cxx11 | 12 + nemu/include/rlib/require/cxx14 | 12 + nemu/include/rlib/require/cxx17 | 13 + nemu/include/rlib/scope_guard.hpp | 100 +++ nemu/include/rlib/stdio.hpp | 243 +++++++ nemu/include/rlib/stream.hpp | 24 + nemu/include/rlib/string.hpp | 410 ++++++++++++ nemu/include/rlib/sys/cc_codegen.py | 43 ++ nemu/include/rlib/sys/cc_list | 71 ++ nemu/include/rlib/sys/compiler_detector | 495 ++++++++++++++ nemu/include/rlib/sys/fd.hpp | 14 + nemu/include/rlib/sys/os.hpp | 98 +++ nemu/include/rlib/sys/rwlock.hpp | 22 + nemu/include/rlib/sys/sio.hpp | 664 +++++++++++++++++++ nemu/include/rlib/sys/time.hpp | 18 + nemu/include/rlib/sys/unix_handy.hpp | 170 +++++ nemu/include/rlib/terminal.hpp | 100 +++ nemu/include/rlib/traits.hpp | 38 ++ nemu/runall.sh | 24 +- 41 files changed, 4601 insertions(+), 15 deletions(-) create mode 100644 .gitlab-ci.yml create mode 100644 nemu/include/rlib/.gitignore create mode 100644 nemu/include/rlib/3rdparty/prettyprint.hpp create mode 100644 nemu/include/rlib/3rdparty/prettyprint98.hpp create mode 100644 nemu/include/rlib/3rdparty/test.cc create mode 100644 nemu/include/rlib/LICENSE create mode 100644 nemu/include/rlib/Makefile create mode 100644 nemu/include/rlib/README.md create mode 100644 nemu/include/rlib/buildspec.yaml create mode 100644 nemu/include/rlib/c-with-class.h create mode 100644 nemu/include/rlib/class_decorator.hpp create mode 100644 nemu/include/rlib/cmake/CMakeLists.txt create mode 100644 nemu/include/rlib/cmake/cmake.include create mode 100644 nemu/include/rlib/cmake/rlib-config.cmake create mode 100644 nemu/include/rlib/functional.hpp create mode 100644 nemu/include/rlib/impl/traceable_list.hpp create mode 100644 nemu/include/rlib/log.hpp create mode 100644 nemu/include/rlib/macro.hpp create mode 100644 nemu/include/rlib/meta.hpp create mode 100644 nemu/include/rlib/opt.hpp create mode 100644 nemu/include/rlib/pool.hpp create mode 100644 nemu/include/rlib/require/cxx11 create mode 100644 nemu/include/rlib/require/cxx14 create mode 100644 nemu/include/rlib/require/cxx17 create mode 100644 nemu/include/rlib/scope_guard.hpp create mode 100644 nemu/include/rlib/stdio.hpp create mode 100644 nemu/include/rlib/stream.hpp create mode 100644 nemu/include/rlib/string.hpp create mode 100755 nemu/include/rlib/sys/cc_codegen.py create mode 100644 nemu/include/rlib/sys/cc_list create mode 100644 nemu/include/rlib/sys/compiler_detector create mode 100644 nemu/include/rlib/sys/fd.hpp create mode 100644 nemu/include/rlib/sys/os.hpp create mode 100644 nemu/include/rlib/sys/rwlock.hpp create mode 100644 nemu/include/rlib/sys/sio.hpp create mode 100644 nemu/include/rlib/sys/time.hpp create mode 100644 nemu/include/rlib/sys/unix_handy.hpp create mode 100644 nemu/include/rlib/terminal.hpp create mode 100644 nemu/include/rlib/traits.hpp mode change 100644 => 100755 nemu/runall.sh diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..3ba3997 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,12 @@ +image: archlinux/base + +stages: + - build + +build: + stage: build + script: + - pacman -Sy && pacman -S --noconfirm bison flex gcc make gettext sdl2 lib32-glibc + - export AM_HOME=$(pwd)/nexus-am/ + - cd nemu && make && show_log=1 ./runall.sh + diff --git a/nemu/Makefile b/nemu/Makefile index 2a7eb67..e058045 100644 --- a/nemu/Makefile +++ b/nemu/Makefile @@ -22,8 +22,13 @@ INCLUDES = $(addprefix -I, $(INC_DIR)) CFLAGS += -O2 -MMD -Wall -ggdb3 $(INCLUDES) -fomit-frame-pointer -std=c++17 CFLAGS += -DDIFF_TEST_QEMU +# Source code generation before any targets. +SUBDIRS = src/monitor/debug/expr_impl +$(SUBDIRS): + $(MAKE) -C $@ + # Files to be compiled -SRCS = $(shell find src/ -name "*.cc") +SRCS = $(shell make -C $(SUBDIRS) generate 1>&2 && find src/ -name "*.cc") OBJS = $(SRCS:src/%.cc=$(OBJ_DIR)/%.o) # Compilation patterns @@ -32,18 +37,12 @@ $(OBJ_DIR)/%.o: src/%.cc @mkdir -p $(dir $@) $(CXX) $(CFLAGS) $(SO_CFLAGS) -c -o $@ $< - # Depencies -include $(OBJS:.o=.d) -# Source code generation before any targets. -SUBDIRS = src/monitor/debug/expr_impl -$(SUBDIRS): - $(MAKE) -C $@ - # Some convinient rules .PHONY: app run clean $(SUBDIRS) -app: $(SUBDIRS) $(BINARY) +app: $(BINARY) override ARGS ?= -l $(BUILD_DIR)/nemu-log.txt override ARGS += -d $(NEMU_HOME)/tools/qemu-diff/build/qemu-so @@ -54,7 +53,7 @@ NEMU_EXEC := $(BINARY) $(ARGS) $(BINARY): $(OBJS) $(call git_commit, "compile") @echo + LD $@ - @$(LD) -O2 -rdynamic $(SO_LDLAGS) -o $@ $^ -lSDL2 -lreadline -ldl -lr + @$(LD) -O2 -rdynamic $(SO_LDLAGS) -o $@ $^ -lSDL2 -lreadline -ldl run: $(BINARY) $(call git_commit, "run") @@ -68,3 +67,4 @@ clean: -rm -rf $(BUILD_DIR) $(MAKE) -C tools/gen-expr clean $(MAKE) -C tools/qemu-diff clean + $(MAKE) -C $(SUBDIRS) clean diff --git a/nemu/include/rlib/.gitignore b/nemu/include/rlib/.gitignore new file mode 100644 index 0000000..4f2c09b --- /dev/null +++ b/nemu/include/rlib/.gitignore @@ -0,0 +1,34 @@ +# 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/ diff --git a/nemu/include/rlib/3rdparty/prettyprint.hpp b/nemu/include/rlib/3rdparty/prettyprint.hpp new file mode 100644 index 0000000..ce2226a --- /dev/null +++ b/nemu/include/rlib/3rdparty/prettyprint.hpp @@ -0,0 +1,461 @@ +// 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> + +#ifndef RLIB_3RD_ENABLE_PRETTYPRINT +namespace rlib { + namespace _3rdparty { +#endif +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); + } +} +#ifndef RLIB_3RD_ENABLE_PRETTYPRINT + } +} // end namespace rlib::3rdparty +#endif // RLIB_3RD_ENABLE_PRETTYPRINT + + + +#endif // H_PRETTY_PRINT diff --git a/nemu/include/rlib/3rdparty/prettyprint98.hpp b/nemu/include/rlib/3rdparty/prettyprint98.hpp new file mode 100644 index 0000000..112600b --- /dev/null +++ b/nemu/include/rlib/3rdparty/prettyprint98.hpp @@ -0,0 +1,410 @@ +// 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 diff --git a/nemu/include/rlib/3rdparty/test.cc b/nemu/include/rlib/3rdparty/test.cc new file mode 100644 index 0000000..89a3519 --- /dev/null +++ b/nemu/include/rlib/3rdparty/test.cc @@ -0,0 +1,9 @@ +#include "prettyprint.hpp" +#include <rlib/stdio.hpp> +#include <list> +using namespace rlib; + +int main() { + std::list ls {1,3,2}; + _3rdparty::std::operator<<(std::cout, ls); +} diff --git a/nemu/include/rlib/LICENSE b/nemu/include/rlib/LICENSE new file mode 100644 index 0000000..b11a017 --- /dev/null +++ b/nemu/include/rlib/LICENSE @@ -0,0 +1,21 @@ +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. diff --git a/nemu/include/rlib/Makefile b/nemu/include/rlib/Makefile new file mode 100644 index 0000000..1587264 --- /dev/null +++ b/nemu/include/rlib/Makefile @@ -0,0 +1,33 @@ +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 + diff --git a/nemu/include/rlib/README.md b/nemu/include/rlib/README.md new file mode 100644 index 0000000..13c9e78 --- /dev/null +++ b/nemu/include/rlib/README.md @@ -0,0 +1,20 @@ +# rlib + +[](https://www.codefactor.io/repository/github/recolic/rlib/overview/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 +``` diff --git a/nemu/include/rlib/buildspec.yaml b/nemu/include/rlib/buildspec.yaml new file mode 100644 index 0000000..a138100 --- /dev/null +++ b/nemu/include/rlib/buildspec.yaml @@ -0,0 +1,17 @@ +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 + diff --git a/nemu/include/rlib/c-with-class.h b/nemu/include/rlib/c-with-class.h new file mode 100644 index 0000000..4a45bc5 --- /dev/null +++ b/nemu/include/rlib/c-with-class.h @@ -0,0 +1,27 @@ +#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 diff --git a/nemu/include/rlib/class_decorator.hpp b/nemu/include/rlib/class_decorator.hpp new file mode 100644 index 0000000..16492af --- /dev/null +++ b/nemu/include/rlib/class_decorator.hpp @@ -0,0 +1,47 @@ +#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 diff --git a/nemu/include/rlib/cmake/CMakeLists.txt b/nemu/include/rlib/cmake/CMakeLists.txt new file mode 100644 index 0000000..a5e8307 --- /dev/null +++ b/nemu/include/rlib/cmake/CMakeLists.txt @@ -0,0 +1,18 @@ +# 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(..) + diff --git a/nemu/include/rlib/cmake/cmake.include b/nemu/include/rlib/cmake/cmake.include new file mode 100644 index 0000000..88b4897 --- /dev/null +++ b/nemu/include/rlib/cmake/cmake.include @@ -0,0 +1,15 @@ +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() + + diff --git a/nemu/include/rlib/cmake/rlib-config.cmake b/nemu/include/rlib/cmake/rlib-config.cmake new file mode 100644 index 0000000..0cc3a3c --- /dev/null +++ b/nemu/include/rlib/cmake/rlib-config.cmake @@ -0,0 +1,17 @@ +# 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() diff --git a/nemu/include/rlib/functional.hpp b/nemu/include/rlib/functional.hpp new file mode 100644 index 0000000..c14bc9b --- /dev/null +++ b/nemu/include/rlib/functional.hpp @@ -0,0 +1,125 @@ +#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 diff --git a/nemu/include/rlib/impl/traceable_list.hpp b/nemu/include/rlib/impl/traceable_list.hpp new file mode 100644 index 0000000..053f4bb --- /dev/null +++ b/nemu/include/rlib/impl/traceable_list.hpp @@ -0,0 +1,225 @@ +#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 = 0x19980427; + 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 != 0x19980427) + 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 diff --git a/nemu/include/rlib/log.hpp b/nemu/include/rlib/log.hpp new file mode 100644 index 0000000..10b6bab --- /dev/null +++ b/nemu/include/rlib/log.hpp @@ -0,0 +1,188 @@ +#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 diff --git a/nemu/include/rlib/macro.hpp b/nemu/include/rlib/macro.hpp new file mode 100644 index 0000000..c411790 --- /dev/null +++ b/nemu/include/rlib/macro.hpp @@ -0,0 +1,34 @@ +#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 diff --git a/nemu/include/rlib/meta.hpp b/nemu/include/rlib/meta.hpp new file mode 100644 index 0000000..e14e460 --- /dev/null +++ b/nemu/include/rlib/meta.hpp @@ -0,0 +1,59 @@ +#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 {}; +} + +#endif diff --git a/nemu/include/rlib/opt.hpp b/nemu/include/rlib/opt.hpp new file mode 100644 index 0000000..7ea0e29 --- /dev/null +++ b/nemu/include/rlib/opt.hpp @@ -0,0 +1,126 @@ +/* +This opt_parser works well for correct cmd args, +but not guaranteed to works well in all condition +(for example, some ill formed argument). + +It's possible to read wrong information rather than +raise an exception on some rare ill formed arguments. +*/ +#ifndef R_OPT_HPP +#define R_OPT_HPP + +#include <rlib/require/cxx14> +#include <rlib/class_decorator.hpp> +#include <rlib/string.hpp> +#include <rlib/scope_guard.hpp> + +#include <string> +#include <vector> +#include <algorithm> +#include <stdexcept> + +namespace rlib { + class opt_parser : private noncopyable + { + public: + opt_parser() = delete; + opt_parser(size_t arglen, char **argv) { + if(argv[0] == nullptr) + throw std::runtime_error("Invalid argv passed to rlib::opt_parser. argv[0] is nullptr."); + arg0 = argv[0]; + for(size_t cter = 1; cter < arglen; ++cter) + args.push_back(std::string(argv[cter])); + } + + rlib::string getSubCommand() { + if(args.empty()) + throw std::runtime_error("No sub-command available."); + auto cmd = std::move(args[0]); + args.erase(args.begin()); + return std::move(cmd); + } + + rlib::string getSubCommand(const std::string &def) { + if(args.empty()) + return def; + auto cmd = std::move(args[0]); + args.erase(args.begin()); + return std::move(cmd); + } + + rlib::string getSelf() { + return arg0; + } + + rlib::string getValueArg(const std::string &argName, bool required = true, const std::string &def = std::string()) + { //If required argument not exist, I'll throw. Else, return "" if arg is not read. + using rlib::literals::operator "" _format; + bool useEqualSym = false; + auto pos = std::find_if(args.cbegin(), args.cend(), [&](auto &ele)->bool{ + if(ele == argName) return true; + if(ele.size() > argName.size() && ele.substr(0, argName.size()+1) == argName + "=") { + useEqualSym = true; + return true; + } + return false; + }); + if(required && pos == args.cend()) + throw std::invalid_argument("Required argument '{}' not provided."_format(argName)); + if(pos == args.cend()) + return std::move(def); + rlib_defer(([&, pos]{if(!useEqualSym) args.erase(pos+1); args.erase(pos);})); + if(useEqualSym) + return pos->substr(argName.size() + 1); + else + { + if(++pos == args.cend()) + throw std::invalid_argument("Argument '{}' must provide value."_format(argName)); + return *pos; + } + } + + rlib::string getValueArg(const std::string &longName, const char *shortName) + { //getValueArg("--long", "-l") may be converted to getValueArg("--long", true). + return getValueArg(longName, shortName, true); + } + + bool getBoolArg(const std::string &argName) + { //Return if it's defined. + auto pos = std::find(args.cbegin(), args.cend(), argName); + if(pos == args.cend()) return false; + args.erase(pos); + return true; + } + + rlib::string getValueArg(const std::string &longName, const std::string &shortName, bool required = true, const std::string &def = std::string()) + { + using rlib::literals::operator "" _format; + std::string valueL = getValueArg(longName, false); + std::string valueS = getValueArg(shortName, false); + + const std::string &value = valueL.empty() ? valueS : valueL; + if(value.empty()) { + if(required) + throw std::invalid_argument("Required argument '{}/{}' not provided."_format(longName, shortName)); + else + return def; + } + return std::move(value); + } + + bool getBoolArg(const std::string &longName, const std::string &shortName) + { + return getBoolArg(longName) || getBoolArg(shortName); + } + + bool allArgDone() const + { + return args.empty(); + } + private: + std::vector<std::string> args; + std::string arg0; + }; +} + +#endif diff --git a/nemu/include/rlib/pool.hpp b/nemu/include/rlib/pool.hpp new file mode 100644 index 0000000..dca2665 --- /dev/null +++ b/nemu/include/rlib/pool.hpp @@ -0,0 +1,129 @@ +#ifndef _RLIB_OBJ_POOL_HPP +#define _RLIB_OBJ_POOL_HPP 1 + +#include <rlib/impl/traceable_list.hpp> +#include <rlib/class_decorator.hpp> +#include <utility> +#include <tuple> +#include <functional> +#include <algorithm> + +#ifdef RLIB_SWITCH_USE_MINGW_THREAD_FIX +#include <mingw.mutex.h> +#include <mingw.thread.h> +#include <mingw.condition_variable.h> +#else +#include <thread> +#include <mutex> +#include <condition_variable> +#endif + +namespace rlib { + /* + * Multi-threaded object_pool. It will block current thread and wait if + * borrow_one() starves, until some other threads release their obj. + */ + template<typename obj_t, typename... _bound_construct_args_t> + class fixed_object_pool : rlib::nonmovable { + protected: + using element_t = obj_t; + using buffer_t = impl::traceable_list<obj_t, bool>; + using this_type = fixed_object_pool<obj_t, _bound_construct_args_t ...>; + public: + explicit fixed_object_pool(size_t max_size, _bound_construct_args_t ... _args) + : max_size(max_size), _bound_args(std::forward<_bound_construct_args_t>(_args) ...) + {} + + void fill_full() { + for (size_t cter = 0; cter < max_size; ++cter) { + new_obj_to_buffer(); + free_list.push_back(&*--buffer.end()); + } + } + + // `new` an object. Return nullptr if pool is full. + obj_t *try_borrow_one() { + std::lock_guard<std::mutex> _l(buffer_mutex); + return do_try_borrow_one(); + } + obj_t *borrow_one() { + auto result = try_borrow_one(); + if(result) + return result; + // Not available. Wait for release_one. + std::unique_lock<std::mutex> lk(buffer_mutex); + + borrow_cv.wait(lk, [this]{return this->new_obj_ready;}); + + result = do_try_borrow_one(); + lk.unlock(); + if(!result) + throw std::logic_error("unknown par error."); + return result; + } + void release_one(obj_t *which) { + { + std::lock_guard<std::mutex> _l(buffer_mutex); + free_list.push_front(which); + typename buffer_t::iterator elem_iter(which); + elem_iter.get_extra_info() = true; // mark as free. + new_obj_ready = true; + } // lock released. + borrow_cv.notify_one(); + } + + void reconstruct_one(obj_t *which) { + reconstruct_impl(which, std::make_index_sequence<sizeof...(_bound_construct_args_t)>()); + } + + protected: + buffer_t buffer; // list<obj_t obj, bool is_free> + private: + std::tuple<_bound_construct_args_t ...> _bound_args; + + size_t max_size; + std::list<obj_t *> free_list; + std::mutex buffer_mutex; + std::condition_variable borrow_cv; + volatile bool new_obj_ready = false; + + // try_borrow_one without lock. + obj_t *do_try_borrow_one() { + // Optimize here if is performance bottleneck (lockless list... etc...) + borrow_again: + if (free_list.size() > 0) { + // Some object is free. Just return one. + obj_t *result = *free_list.begin(); + free_list.pop_front(); + + typename buffer_t::iterator elem_iter(result); + elem_iter.get_extra_info() = false; // mark as busy. + new_obj_ready = false; + return result; + } + if (buffer.size() < max_size) { + new_obj_to_buffer(); + free_list.push_back(&*--buffer.end()); + goto borrow_again; + } + return nullptr; + } + + // fake emplace_back + template<size_t ... index_seq> + inline void new_obj_to_buffer_impl(std::index_sequence<index_seq ...>) { + buffer.emplace_one(buffer.end(), true, std::get<index_seq>(_bound_args) ...); + } + template<size_t ... index_seq> + inline void reconstruct_impl(obj_t *which, std::index_sequence<index_seq ...>) { + which->~obj_t(); + new(which) obj_t(std::get<index_seq>(_bound_args) ...); + } + + inline void new_obj_to_buffer() { + new_obj_to_buffer_impl(std::make_index_sequence<sizeof...(_bound_construct_args_t)>()); + } + }; +} + +#endif diff --git a/nemu/include/rlib/require/cxx11 b/nemu/include/rlib/require/cxx11 new file mode 100644 index 0000000..2565010 --- /dev/null +++ b/nemu/include/rlib/require/cxx11 @@ -0,0 +1,12 @@ +#ifndef R_CXX11_REQUIRED +#define R_CXX11_REQUIRED + +#include <rlib/sys/os.hpp> + +#if RLIB_CXX_STD <= 1997 +#error This file requires compiler and library support \ +for the ISO C++ 2011 standard. This support must be enabled \ +with the -std=c++11 or -std=gnu++11 compiler options. +#endif + +#endif diff --git a/nemu/include/rlib/require/cxx14 b/nemu/include/rlib/require/cxx14 new file mode 100644 index 0000000..17e676c --- /dev/null +++ b/nemu/include/rlib/require/cxx14 @@ -0,0 +1,12 @@ +#ifndef R_CXX14_REQUIRED +#define R_CXX14_REQUIRED + +#include <rlib/sys/os.hpp> + +#if RLIB_CXX_STD <= 2011 +#error This file requires compiler and library support \ +for the ISO C++ 2014 standard. This support must be enabled \ +with the -std=c++14 or -std=gnu++14 compiler options. +#endif + +#endif diff --git a/nemu/include/rlib/require/cxx17 b/nemu/include/rlib/require/cxx17 new file mode 100644 index 0000000..d201616 --- /dev/null +++ b/nemu/include/rlib/require/cxx17 @@ -0,0 +1,13 @@ +#ifndef R_CXX17_REQUIRED +#define R_CXX17_REQUIRED + +#include <rlib/sys/os.hpp> + +#if RLIB_CXX_STD <= 2014 +#error This file requires compiler and library support \ +for the ISO C++ 2017 standard. This support must be enabled \ +with the -std=c++17, -std=gnu++17, -std=c++1z, -std=gnu++1z \ +compiler options. +#endif + +#endif diff --git a/nemu/include/rlib/scope_guard.hpp b/nemu/include/rlib/scope_guard.hpp new file mode 100644 index 0000000..58ea5cf --- /dev/null +++ b/nemu/include/rlib/scope_guard.hpp @@ -0,0 +1,100 @@ +/* Exception safe usage: + * + * reinforce_scope_begin(_gname, [](){do_sth();}) + * do_something(); + * reinforce_scope_end(_gname) + * + */ + +#ifndef R_SCOPE_GUARD +#define R_SCOPE_GUARD + +#include <rlib/require/cxx11> +#include <functional> +#include <rlib/class_decorator.hpp> + +namespace rlib { + class scope_guard : private noncopyable + { + public: + template<class Callable> + scope_guard(Callable && undo_func) : f(std::forward<Callable>(undo_func)) {} + + scope_guard(scope_guard && other) : f(std::move(other.f)) { + other.f = nullptr; + } + + ~scope_guard() { + if(f) f(); // must not throw + } + + void dismiss() noexcept { + f = nullptr; + } + + void force_call() noexcept { + if(f) f(); + dismiss(); + } + + private: + std::function<void()> f; + }; +} + + +#ifndef rlib_defer +#include <rlib/macro.hpp> +#define rlib_defer(callable) ::rlib::scope_guard RLIB_MAKE_UNIQUE_NAME(_guarder_id_) (callable) +#endif + +#define RLIB_reinforce_scope_begin(guarderName, callable) scope_guard guarderName = callable; try{ +#define RLIB_reinforce_scope_end(guarderName) } catch(...) { guarderName.force_call(); throw;} + +/* +scope_guards scope_exit, scope_fail; + +action1(); +scope_exit += []{ cleanup1(); }; +scope_fail += []{ rollback1(); }; + +action2(); +scope_exit += []{ cleanup2(); }; +scope_fail += []{ rollback2(); }; + +do_something(); + +scope_fail.dismiss(); +*/ + +#include <deque> + +namespace rlib { + class scope_guards : private noncopyable + { + public: + template<class Callable> + scope_guards& operator += (Callable && undo_func) { + fbuf.emplace_front(std::forward<Callable>(undo_func)); + return *this; + } + + ~scope_guards() { + force_call(); + } + + void dismiss() noexcept { + fbuf.clear(); + } + + void force_call() noexcept { + for(auto &f : fbuf) f(); + dismiss(); + } + private: + std::deque<std::function<void(void)> > fbuf; + }; +} + + +#endif diff --git a/nemu/include/rlib/stdio.hpp b/nemu/include/rlib/stdio.hpp new file mode 100644 index 0000000..80d6e6b --- /dev/null +++ b/nemu/include/rlib/stdio.hpp @@ -0,0 +1,243 @@ +/* + * + * stdio wrapper for modern c++: python like print/println/printf/printfln + * print_iter println_iter + * Recolic Keghart <root@recolic.net> + * MIT License + * + */ + +#ifndef R_STDIO_HPP +#define R_STDIO_HPP + +#include <rlib/require/cxx11> // Use fold expression if cxx17 is available. +#include <rlib/sys/os.hpp> // Enable inline variable if cxx17 is available. +#include <string> +#include <iostream> +#include <rlib/string.hpp> // format_string +#include <type_traits> + +#if RLIB_OS_ID == OS_WINDOWS +#define RLIB_IMPL_ENDLINE "\r\n" +#elif RLIB_OS_ID == OS_MACOS +#define RLIB_IMPL_ENDLINE "\r" +#else +#define RLIB_IMPL_ENDLINE "\n" +#endif + +namespace rlib { + namespace impl { + template <typename T> + struct print_wrapper { + print_wrapper() = delete; + print_wrapper(const T &dat) + : wrapper(dat) {} + + const T &wrapper; + + friend std::ostream & operator<< (std::ostream &os, print_wrapper<T> p) { + return os << p.wrapper; + } + }; + } +} + +namespace rlib { +// print to custom stream + template <typename PrintFinalT> + void print(std::ostream &os, PrintFinalT reqArg); + template <typename Required, typename... Optional> + void print(std::ostream &os, Required reqArgs, Optional... optiArgs); + template <typename... Optional> + void println(std::ostream &os, Optional... optiArgs); + template <> + void println(std::ostream &os); + + template <typename Iterable, typename Printable> + void print_iter(std::ostream &os, Iterable arg, Printable spliter); + template <typename Iterable, typename Printable> + void println_iter(std::ostream &os, Iterable arg, Printable spliter); + template <typename Iterable> + void print_iter(std::ostream &os, Iterable arg); + template <typename Iterable> + void println_iter(std::ostream &os, Iterable arg); + + template <typename... Args> + size_t printf(std::ostream &os, const std::string &fmt, Args... args); + template <typename... Args> + size_t printfln(std::ostream &os, const std::string &fmt, Args... args); + + inline rlib::string scanln(std::istream &is = std::cin, char delimiter = '\n') noexcept { + std::string line; + std::getline(is, line, delimiter); + return std::move(line); + } + + // default for std::cout + template <typename... Args> + void println(Args... args); + template <> + void println(); + template <typename... Args> + void print(Args... args); + template <typename Iterable, typename Printable> + void print_iter(Iterable arg, Printable spliter); + template <typename Iterable, typename Printable> + void println_iter(Iterable arg, Printable spliter); + template <typename Iterable> + void print_iter(Iterable arg); + template <typename Iterable> + void println_iter(Iterable arg); + template <typename... Args> + size_t printf(const std::string &fmt, Args... args); + template <typename... Args> + size_t printfln(const std::string &fmt, Args... args); + + // implementations below -------------------------------- + + namespace impl { + inline bool &enable_endl_flush() { + static bool instance = true; + return instance; + } + } + + inline bool sync_with_stdio(bool sync = true) noexcept { + return std::ios::sync_with_stdio(sync); + } + inline bool enable_endl_flush(bool enable = true) noexcept { + return impl::enable_endl_flush() = enable; + } + +// Implements. + template < class CharT, class Traits > + inline std::basic_ostream<CharT, Traits>& endl(std::basic_ostream<CharT, Traits>& os) { + os << RLIB_IMPL_ENDLINE; + if(impl::enable_endl_flush()) + os.flush(); + return os; + } + + // With custom os + template <typename PrintFinalT> + void print(std::ostream &os, PrintFinalT reqArg) + { + os << reqArg; + } + template <typename Required, typename... Optional> + void print(std::ostream &os, Required reqArgs, Optional... optiArgs) + { + os << reqArgs << ' '; + print(os, optiArgs ...); + } + template <typename... Optional> + void println(std::ostream &os, Optional... optiArgs) + { + print(os, optiArgs ...); + println(os); + } + template <> + inline void println(std::ostream &os) + { + os << rlib::endl; + } + + template <typename Iterable, typename Printable> + void print_iter(std::ostream &os, Iterable arg, Printable spliter) + { + for(const auto & i : arg) + os << i << spliter; + } + template <typename Iterable, typename Printable> + void println_iter(std::ostream &os, Iterable arg, Printable spliter) + { + print_iter(os, arg, spliter); + println(os); + } + template <typename Iterable> + void print_iter(std::ostream &os, Iterable arg) + { + print_iter(os, arg, ' '); + } + template <typename Iterable> + void println_iter(std::ostream &os, Iterable arg) + { + println_iter(os, arg, ' '); + } + + template <typename... Args> + size_t printf(std::ostream &os, const std::string &fmt, Args... args) + { + std::string to_print = impl::format_string(fmt, args...); + print(os, to_print); + return to_print.size(); + } + template <typename... Args> + size_t printfln(std::ostream &os, const std::string &fmt, Args... args) + { + size_t len = printf(os, fmt, args...); + println(os); + return len + 1; + } + + + + // default for std::cout + template <typename... Args> + void println(Args... args) { + return println(std::cout, std::forward<Args>(args) ...); + } + template <> + inline void println() { + return println(std::cout); + } + template <typename... Args> + void print(Args... args) { + return print(std::cout, std::forward<Args>(args) ...); + } + template <typename Iterable, typename Printable> + void print_iter(Iterable arg, Printable spliter) { + return print_iter(std::cout, std::forward<Iterable>(arg), spliter); + } + template <typename Iterable, typename Printable> + void println_iter(Iterable arg, Printable spliter) { + return println_iter(std::cout, std::forward<Iterable>(arg), spliter); + } + template <typename Iterable> + void print_iter(Iterable arg) { + return print_iter(std::cout, std::forward<Iterable>(arg)); + } + template <typename Iterable> + void println_iter(Iterable arg) { + return println_iter(std::cout, std::forward<Iterable>(arg)); + } + template <typename... Args> + size_t printf(const std::string &fmt, Args... args) { + return printf(std::cout, fmt, std::forward<Args>(args) ...); + } + template <typename... Args> + size_t printfln(const std::string &fmt, Args... args) { + return printfln(std::cout, fmt, std::forward<Args>(args) ...); + } + + + // If the stream is stringstream or ostringstream, + // it will fails to match print(ostream &, args...), + // and match print(args ...). It leads to an error. + // Here's the fallback on such sucking substitution error. + template <typename StreamType, typename... Args> + void println(StreamType &os, Args... args) { + using ostream_or_data = typename std::conditional<std::is_base_of<std::ostream, StreamType>::value, + std::ostream &, impl::print_wrapper<StreamType>>::type; + return println(static_cast<ostream_or_data>(os), std::forward<Args>(args) ...); + } + template <typename StreamType, typename... Args> + void print(StreamType &os, Args... args) { + using ostream_or_data = typename std::conditional<std::is_base_of<std::ostream, StreamType>::value, + std::ostream &, impl::print_wrapper<StreamType>>::type; + return print(static_cast<ostream_or_data>(os), std::forward<Args>(args) ...); + } +} + + +#endif diff --git a/nemu/include/rlib/stream.hpp b/nemu/include/rlib/stream.hpp new file mode 100644 index 0000000..93f77c2 --- /dev/null +++ b/nemu/include/rlib/stream.hpp @@ -0,0 +1,24 @@ +#include <rlib/require/cxx11> +#include <streambuf> +#include <iostream> +#include <rlib/sys/os.hpp> + +namespace rlib { + namespace impl { + class NullStreamBuf : public std::streambuf + { + public: + int overflow(int c) { return c; } + }; + + inline NullStreamBuf & null_streambuf() { + static NullStreamBuf instance; + return instance; + } + } + + inline std::ostream &null_stream() { + static std::ostream instance(impl::null_streambuf()); + return instance; + } +} diff --git a/nemu/include/rlib/string.hpp b/nemu/include/rlib/string.hpp new file mode 100644 index 0000000..9fe7968 --- /dev/null +++ b/nemu/include/rlib/string.hpp @@ -0,0 +1,410 @@ +/* + * + * string.hpp: string process utility. + * Recolic Keghart <root@recolic.net> + * MIT License + * + */ + +#ifndef R_STRING_HPP +#define R_STRING_HPP + +#include <rlib/require/cxx14> +#include <rlib/class_decorator.hpp> +#include <rlib/sys/os.hpp> + +#include <array> +#include <vector> +#include <string> +#include <cstdarg> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <stdexcept> +#include <sstream> +#include <type_traits> + +// Intel C++ compiler has a pending bug for `thread_local inline` variable. +#if RLIB_COMPILER_ID == CC_ICC +#define RLIB_IMPL_SSTREAM_DISABLE_TLS +#endif + +#if RLIB_COMPILER_IS_MINGW +#define RLIB_IMPL_SSTREAM_DISABLE_TLS +#endif + +namespace rlib { + // literals::_format, format_string, string::format + namespace impl { +#ifndef RLIB_IMPL_SSTREAM_DISABLE_TLS + inline std::stringstream &to_string_by_sstream_ss() { + static thread_local std::stringstream instance; + return instance; + } + inline std::stringstream &_format_string_helper_ss() { + static thread_local std::stringstream instance; + return instance; + } +#endif + template <typename VarT> + std::string to_string_by_sstream(VarT &thing) { +#if defined(RLIB_IMPL_SSTREAM_DISABLE_TLS) + // Fix intel C++ bug https://software.intel.com/en-us/forums/intel-c-compiler/topic/784136 + // Also fix mingw bug. But much slower! + std::stringstream ss; +#else + auto &ss = to_string_by_sstream_ss(); + ss.str(std::string()); +#endif + ss << thing; + return ss.str(); + } + + template<typename... Args> + std::string _format_string_helper(const std::string &fmt, Args... args) { +#if defined(RLIB_IMPL_SSTREAM_DISABLE_TLS) + // Fix intel C++ bug https://software.intel.com/en-us/forums/intel-c-compiler/topic/784136 + std::stringstream ss; +#else + auto &ss = _format_string_helper_ss(); // cached stringstream is much quicker. + ss.str(std::string()); +#endif + size_t pos = 0, prev_pos = 0; + std::array<std::string, sizeof...(args)> argsArr{to_string_by_sstream(args) ...}; + size_t current_used_arg = 0; + bool discovered_escape_char = false; + while((pos = fmt.find("{}", pos)) != std::string::npos) { + if(pos != 0 && fmt[pos-1] == '\\') { + // Invalid hit. + discovered_escape_char = true; + pos += 2; + } + else { + std::string cutted_tmp_str = fmt.substr(prev_pos, pos - prev_pos); + if(discovered_escape_char) { + // hand-written string replace. Replace `\{}` to `{}`. + size_t pos = 0; + while((pos = cutted_tmp_str.find("\\{}", pos)) != std::string::npos) { + cutted_tmp_str.erase(pos, 1); + pos += 2; + } + } + if(current_used_arg >= sizeof...(args)) { + // not enough arguments. + throw std::out_of_range("format_string: not enough arguments for format string `" + fmt + + "`. Expecting at least " + std::to_string(current_used_arg+1) + ", got " + + std::to_string(sizeof...(args))); + } + ss << cutted_tmp_str << argsArr.at(current_used_arg); + pos += 2; + prev_pos = pos; + ++current_used_arg; + } + } + if(current_used_arg != sizeof...(args)) { + // too many arguments. + throw std::out_of_range("format_string: too many arguments for format string `" + fmt + + "`. Expecting " + std::to_string(current_used_arg) + ", got " + + std::to_string(sizeof...(args))); + } + ss << fmt.substr(prev_pos); + return ss.str(); + } + template<typename... Args> + inline std::string format_string(const std::string &fmt, Args... args) { + return _format_string_helper(fmt, args...); + } + //template<> + //inline std::string format_string<>(const std::string &fmt) { + // return fmt; + //} + + /* + template<class MetaFmtArr, typename... Args> + constexpr std::string format_string_meta(Args... args) { + return (args + ...); + }*/ + } + + // format_string_c, string::cformat + namespace impl { + inline char *_format_string_c_helper(const char *fmt, ...) + { + int n; + int size = std::strlen(fmt); + char *p, *np; + va_list ap; + + if ((p = (char *)malloc(size)) == NULL) + throw std::runtime_error("malloc returns null."); + + while (1) { + va_start(ap, fmt); + n = vsnprintf(p, size, fmt, ap); + va_end(ap); + + if (n < 0) + throw std::runtime_error("vsnprintf returns " + std::to_string(n)); + if (n < size) + return p; + + size = n + 1; + + if ((np = (char *)realloc (p, size)) == NULL) { + free(p); + throw std::runtime_error("make_message realloc failed."); + } else { + p = np; + } + } + } + template<typename... Args> + std::string format_string_c(const std::string &fmt, Args... args) + { + char *res = _format_string_c_helper(fmt.c_str(), args ...); + std::string s = res; + free(res); + return s; + } + } + + class string : public std::string { + public: + using std::string::string; + string() : std::string() {} + string(const std::string &s) : std::string(s) {} + string(std::string &&s) : std::string(std::forward<std::string>(s)) {} + + private: + template <typename T> struct as_helper {}; + template <typename T> + T as(as_helper<T>) const { + if(empty()) return T(); + return T(*this); + } + const char *as(as_helper<const char *>) const { + return this->c_str(); + } + std::string as(as_helper<std::string>) const { + return std::move(*this); + } + rlib::string as(as_helper<rlib::string>) const { + return std::move(*this); + } + char as(as_helper<char>) const { + if(size() > 1) + throw std::invalid_argument("Can not convert rlib::string to char: size() > 1."); + return size() == 0 ? '\0' : *cbegin(); + } + // unsigned-char conflicts with uint8_t. I'll regard it as uint8_t. ("8".as<unsigned char> == 8) + //unsigned char as(as_helper<unsigned char>) const { + // return static_cast<unsigned char>(as<char>()); + //} + bool as(as_helper<bool>) const { + if(*this == "true") { + return true; + } + else if(*this == "false") { + return false; + } + // Nothing is slower than throw(); Just test more cases... + else if(*this == "1" || *this == "True" || *this == "TRUE") { + return true; + } + else if(*this == "0" || *this == "False" || *this == "FALSE") { + return false; + } + throw std::invalid_argument("Can not convert rlib::string to bool. Not matching any template."); + } + +#define RLIB_IMPL_GEN_AS_NUMERIC(type, std_conv) \ + type as(as_helper<type>) const { \ + if(empty()) return 0; \ + return std::std_conv(*this); \ + } + + RLIB_IMPL_GEN_AS_NUMERIC(int, stoi) + RLIB_IMPL_GEN_AS_NUMERIC(long, stol) + RLIB_IMPL_GEN_AS_NUMERIC(unsigned long, stoul) + RLIB_IMPL_GEN_AS_NUMERIC(unsigned long long, stoull) + RLIB_IMPL_GEN_AS_NUMERIC(long long, stoll) + RLIB_IMPL_GEN_AS_NUMERIC(float, stof) + RLIB_IMPL_GEN_AS_NUMERIC(double, stod) + RLIB_IMPL_GEN_AS_NUMERIC(long double, stold) + +#define RLIB_IMPL_GEN_AS_ALIAS(new_type, old_type) \ + new_type as(as_helper<new_type>) const { \ + return static_cast<new_type>(as<old_type>()); \ + } + + RLIB_IMPL_GEN_AS_ALIAS(unsigned int, unsigned long) + RLIB_IMPL_GEN_AS_ALIAS(unsigned short, unsigned long) + RLIB_IMPL_GEN_AS_ALIAS(uint8_t, unsigned long) + + RLIB_IMPL_GEN_AS_ALIAS(short, int) + RLIB_IMPL_GEN_AS_ALIAS(int8_t, int) + + public: + template <typename T> + T as() const { + return std::forward<T>(as(as_helper<T>())); + } + + std::vector<string> split(const char ÷r = ' ') const { + const string &toSplit = *this; + std::vector<string> buf; + size_t curr = 0, prev = 0; + while((curr = toSplit.find(divider, curr)) != std::string::npos) { + buf.push_back(toSplit.substr(prev, curr - prev)); + ++curr; // skip divider + prev = curr; + } + buf.push_back(toSplit.substr(prev)); + return buf; + } + std::vector<string> split(const std::string ÷r) const { + const string &toSplit = *this; + std::vector<string> buf; + size_t curr = 0, prev = 0; + while((curr = toSplit.find(divider, curr)) != std::string::npos) { + buf.push_back(toSplit.substr(prev, curr - prev)); + curr += divider.size(); // skip divider + prev = curr; + } + buf.push_back(toSplit.substr(prev)); + return buf; + } + template <typename T> + std::vector<T> split_as(const char ÷r = ' ') const { + const string &toSplit = *this; + std::vector<T> buf; + size_t curr = 0, prev = 0; + while((curr = toSplit.find(divider, curr)) != std::string::npos) { + buf.push_back(string(toSplit.substr(prev, curr - prev)).as<T>()); + ++curr; // skip divider + prev = curr; + } + buf.push_back(string(toSplit.substr(prev)).as<T>()); + return std::move(buf); + } + template <typename T> + std::vector<T> split_as(const std::string ÷r) const { + const string &toSplit = *this; + std::vector<T> buf; + size_t curr = 0, prev = 0; + while((curr = toSplit.find(divider, curr)) != std::string::npos) { + buf.push_back(string(toSplit.substr(prev, curr - prev)).as<T>()); + curr += divider.size(); // skip divider + prev = curr; + } + buf.push_back(string(toSplit.substr(prev)).as<T>()); + return std::move(buf); + } + + template <class ForwardIterable> + string &join(const ForwardIterable &buffer) { + join(buffer.cbegin(), buffer.cend()); + return *this; + } + template <class ForwardIterator> + string &join(ForwardIterator begin, ForwardIterator end) { + const string &toJoin = *this; + std::string result; + for(ForwardIterator iter = begin; iter != end; ++iter) { + if(iter != begin) + result += toJoin; + result += *iter; + } + return operator=(std::move(result)); + } + + string &strip() { + strip(" \t\r\n"); + return *this; + } + template <typename CharOrStringOrView> + string &strip(const CharOrStringOrView &stripped) { + size_t len = size(); + size_t begin = find_first_not_of(stripped); + + if(begin == std::string::npos) { + clear(); + return *this; + } + size_t end = find_last_not_of(stripped); + + erase(end + 1, len - end - 1); + erase(0, begin); + return *this; + } + + string &replace(const std::string &from, const std::string &to) { + size_t _; + replace(from, to, _); + return *this; + } + string &replace(const std::string &from, const std::string &to, size_t &out_times) { + if(from.empty()) + return *this; + size_t start_pos = 0; + size_t times = 0; + while((start_pos = find(from, start_pos)) != std::string::npos) + { + ++times; + this->std::string::replace(start_pos, from.length(), to); + start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx' + } + out_times = times; + return *this; + } + string &replace_once(const std::string &from, const std::string &to) { + bool _; + replace_once(from, to, _); + return *this; + } + string &replace_once(const std::string &from, const std::string &to, bool &out_replaced) { + size_t start_pos = find(from); + if(start_pos == std::string::npos) { + out_replaced = false; + } + else { + this->std::string::replace(start_pos, from.length(), to); + out_replaced = true; + } + return *this; + } + + template <typename... Args> + string &format(Args... args) { + return operator=(std::move(impl::format_string(*this, args ...))); + } + template <typename... Args> + string &cformat(Args... args) { + return operator=(std::move(impl::format_string_c(*this, args ...))); + } + }; + + namespace impl { + struct formatter { + formatter(const std::string &fmt) : fmt(fmt) {} + formatter(std::string &&fmt) : fmt(fmt) {} + template <typename... Args> + std::string operator ()(Args... args) { + return std::move(rlib::impl::format_string(fmt, args ...)); + } + + std::string fmt; + }; + } + + namespace literals { + inline impl::formatter operator "" _format (const char *str, size_t) { + return impl::formatter(str); + } + inline rlib::string operator "" _rs (const char *str, size_t len) { + return rlib::string(str, len); + } + } +} + +#endif diff --git a/nemu/include/rlib/sys/cc_codegen.py b/nemu/include/rlib/sys/cc_codegen.py new file mode 100755 index 0000000..35dcc8f --- /dev/null +++ b/nemu/include/rlib/sys/cc_codegen.py @@ -0,0 +1,43 @@ +#!/bin/env python3 + +rlib_cc_magic = 90713 +def getSerialNumber(): + global rlib_cc_magic + rlib_cc_magic += 1 + return rlib_cc_magic + +def genDefList(idarr): + s = '#if' + cter = 1 + for i in idarr: + s += ' defined(' + i + ')' + if cter != len(idarr): + s += ' ||' + cter += 1 + return s + +print('// Generated by cc_codegen.py. Do not edit it by hand.') + +with open("cc_list") as fd: + osarr=fd.read().split('\n') + for i in osarr: + if i == '': + continue + if i[0] == '#': + continue + iarr=i.split(' ') + if len(iarr) < 2: + continue + print('#ifndef RLIB_COMPILER_ID') + print(genDefList(iarr[:-1:])) + print('#define RLIB_COMPILER_ID', 'CC_' + iarr[-1]) + print('#endif') + print('#endif') + print('#define CC_' + iarr[-1], getSerialNumber()) + print('') + +print('#ifndef RLIB_COMPILER_ID') +print('#define RLIB_COMPILER_ID CC_UNKNOWN') +print('#endif') +print('#define CC_UNKNOWN', getSerialNumber()) + diff --git a/nemu/include/rlib/sys/cc_list b/nemu/include/rlib/sys/cc_list new file mode 100644 index 0000000..92d6817 --- /dev/null +++ b/nemu/include/rlib/sys/cc_list @@ -0,0 +1,71 @@ +_ACC_ ACC +__CMB__ ALTIUM_MICROBLAZE +__CHC__ ALTIUM_HARDWARE +__ACK__ AMSTERDAM +__CC_ARM ARMCC +AZTEC_C __AZTEC_C__ AZTEC +__BORLANDC__ __CODEGEARC__ BORLAND +__CC65__ CC65 +__clang__ CLANG +__COMO__ COMEAU +__DECC __DECCXX COMPAQ +__convexc__ CONVEX +__COMPCERT__ COMPCERT +__COVERITY__ COVERITY +_CRAYC CRAY +__DCC__ DIAB +_DICE DICE +__DMC__ DIGITAL_MARS +__SYSC__ DIGNUS +__DJGPP__ DJGPP +__ICC __INTEL_COMPILER ICC +# ICC must be placed before: EDG, GCC +__EDG__ EDG +__PATHCC__ EKOPATH +__FCC_VERSION FUJITSU +__GNUC__ GCC +__ghs__ GREENHILL +__HP_cc HPC +__HP_aCC HPACXX +__IAR_SYSTEMS_ICC__ IARC +__IBMCPP__ __IBMC__ IBMC +__IMAGECRAFT__ IMAGECRAFT +__KCC KAICXX +__CA__ __KEIL__ KEIL_CARM +__C166__ KEIL_C166 +__C51__ __CX51__ KEIL_C51 +__LCC__ LCC +__llvm__ LLVM +__MWERKS__ __CWCC__ METROWERKS +_MSC_VER MSVC +_MRI MICROTEC +__NDPC__ __NDPX__ MICROWAY +__sgi sgi MIPSPRO +MIRACLE MIRACLE +__MRC__ MPW_C MPW_CPLUS MPW +__CC_NORCROFT NORCROFT +__NWCC__ NWCC +__OPEN64__ __OPENCC__ OPEN64 +ORA_PROC ORACLE_PROC +__SUNPRO_C __SUNPRO_CC SOLARIS +__PACIFIC__ PACIFIC +_PACC_VER PLAM +__POCC__ PELLES +__PGI PORTLAND +__RENESAS__ __HITACHI__ RENESAS +SASC __SASC __SASC__ SASC +_SCO_DS SCO_OPENSERVER +SDCC SDCC +__SNC__ SN +__VOSC__ STRATUS_VOS +__SC__ SYMANTEC +__TenDRA__ TENDRA +__TI_COMPILER_VERSION__ _TMS320C6X TEXAS +THINKC3 THINKC4 THINK +__TINYC__ TINYC +__TURBOC__ TURBOC +_UCC UCC +__USLC__ USLC +__VBCC__ VBCC +__WATCOMC__ WATCOM +__ZTC__ ZORTECH diff --git a/nemu/include/rlib/sys/compiler_detector b/nemu/include/rlib/sys/compiler_detector new file mode 100644 index 0000000..99f6dcf --- /dev/null +++ b/nemu/include/rlib/sys/compiler_detector @@ -0,0 +1,495 @@ +// Generated by cc_codegen.py. Do not edit it by hand. +#ifndef RLIB_COMPILER_ID +#if defined(_ACC_) +#define RLIB_COMPILER_ID CC_ACC +#endif +#endif +#define CC_ACC 90714 + +#ifndef RLIB_COMPILER_ID +#if defined(__CMB__) +#define RLIB_COMPILER_ID CC_ALTIUM_MICROBLAZE +#endif +#endif +#define CC_ALTIUM_MICROBLAZE 90715 + +#ifndef RLIB_COMPILER_ID +#if defined(__CHC__) +#define RLIB_COMPILER_ID CC_ALTIUM_HARDWARE +#endif +#endif +#define CC_ALTIUM_HARDWARE 90716 + +#ifndef RLIB_COMPILER_ID +#if defined(__ACK__) +#define RLIB_COMPILER_ID CC_AMSTERDAM +#endif +#endif +#define CC_AMSTERDAM 90717 + +#ifndef RLIB_COMPILER_ID +#if defined(__CC_ARM) +#define RLIB_COMPILER_ID CC_ARMCC +#endif +#endif +#define CC_ARMCC 90718 + +#ifndef RLIB_COMPILER_ID +#if defined(AZTEC_C) || defined(__AZTEC_C__) +#define RLIB_COMPILER_ID CC_AZTEC +#endif +#endif +#define CC_AZTEC 90719 + +#ifndef RLIB_COMPILER_ID +#if defined(__BORLANDC__) || defined(__CODEGEARC__) +#define RLIB_COMPILER_ID CC_BORLAND +#endif +#endif +#define CC_BORLAND 90720 + +#ifndef RLIB_COMPILER_ID +#if defined(__CC65__) +#define RLIB_COMPILER_ID CC_CC65 +#endif +#endif +#define CC_CC65 90721 + +#ifndef RLIB_COMPILER_ID +#if defined(__clang__) +#define RLIB_COMPILER_ID CC_CLANG +#endif +#endif +#define CC_CLANG 90722 + +#ifndef RLIB_COMPILER_ID +#if defined(__COMO__) +#define RLIB_COMPILER_ID CC_COMEAU +#endif +#endif +#define CC_COMEAU 90723 + +#ifndef RLIB_COMPILER_ID +#if defined(__DECC) || defined(__DECCXX) +#define RLIB_COMPILER_ID CC_COMPAQ +#endif +#endif +#define CC_COMPAQ 90724 + +#ifndef RLIB_COMPILER_ID +#if defined(__convexc__) +#define RLIB_COMPILER_ID CC_CONVEX +#endif +#endif +#define CC_CONVEX 90725 + +#ifndef RLIB_COMPILER_ID +#if defined(__COMPCERT__) +#define RLIB_COMPILER_ID CC_COMPCERT +#endif +#endif +#define CC_COMPCERT 90726 + +#ifndef RLIB_COMPILER_ID +#if defined(__COVERITY__) +#define RLIB_COMPILER_ID CC_COVERITY +#endif +#endif +#define CC_COVERITY 90727 + +#ifndef RLIB_COMPILER_ID +#if defined(_CRAYC) +#define RLIB_COMPILER_ID CC_CRAY +#endif +#endif +#define CC_CRAY 90728 + +#ifndef RLIB_COMPILER_ID +#if defined(__DCC__) +#define RLIB_COMPILER_ID CC_DIAB +#endif +#endif +#define CC_DIAB 90729 + +#ifndef RLIB_COMPILER_ID +#if defined(_DICE) +#define RLIB_COMPILER_ID CC_DICE +#endif +#endif +#define CC_DICE 90730 + +#ifndef RLIB_COMPILER_ID +#if defined(__DMC__) +#define RLIB_COMPILER_ID CC_DIGITAL_MARS +#endif +#endif +#define CC_DIGITAL_MARS 90731 + +#ifndef RLIB_COMPILER_ID +#if defined(__SYSC__) +#define RLIB_COMPILER_ID CC_DIGNUS +#endif +#endif +#define CC_DIGNUS 90732 + +#ifndef RLIB_COMPILER_ID +#if defined(__DJGPP__) +#define RLIB_COMPILER_ID CC_DJGPP +#endif +#endif +#define CC_DJGPP 90733 + +#ifndef RLIB_COMPILER_ID +#if defined(__ICC) || defined(__INTEL_COMPILER) +#define RLIB_COMPILER_ID CC_ICC +#endif +#endif +#define CC_ICC 90734 + +#ifndef RLIB_COMPILER_ID +#if defined(__EDG__) +#define RLIB_COMPILER_ID CC_EDG +#endif +#endif +#define CC_EDG 90735 + +#ifndef RLIB_COMPILER_ID +#if defined(__PATHCC__) +#define RLIB_COMPILER_ID CC_EKOPATH +#endif +#endif +#define CC_EKOPATH 90736 + +#ifndef RLIB_COMPILER_ID +#if defined(__FCC_VERSION) +#define RLIB_COMPILER_ID CC_FUJITSU +#endif +#endif +#define CC_FUJITSU 90737 + +#ifndef RLIB_COMPILER_ID +#if defined(__GNUC__) +#define RLIB_COMPILER_ID CC_GCC +#endif +#endif +#define CC_GCC 90738 + +#ifndef RLIB_COMPILER_ID +#if defined(__ghs__) +#define RLIB_COMPILER_ID CC_GREENHILL +#endif +#endif +#define CC_GREENHILL 90739 + +#ifndef RLIB_COMPILER_ID +#if defined(__HP_cc) +#define RLIB_COMPILER_ID CC_HPC +#endif +#endif +#define CC_HPC 90740 + +#ifndef RLIB_COMPILER_ID +#if defined(__HP_aCC) +#define RLIB_COMPILER_ID CC_HPACXX +#endif +#endif +#define CC_HPACXX 90741 + +#ifndef RLIB_COMPILER_ID +#if defined(__IAR_SYSTEMS_ICC__) +#define RLIB_COMPILER_ID CC_IARC +#endif +#endif +#define CC_IARC 90742 + +#ifndef RLIB_COMPILER_ID +#if defined(__IBMCPP__) || defined(__IBMC__) +#define RLIB_COMPILER_ID CC_IBMC +#endif +#endif +#define CC_IBMC 90743 + +#ifndef RLIB_COMPILER_ID +#if defined(__IMAGECRAFT__) +#define RLIB_COMPILER_ID CC_IMAGECRAFT +#endif +#endif +#define CC_IMAGECRAFT 90744 + +#ifndef RLIB_COMPILER_ID +#if defined(__KCC) +#define RLIB_COMPILER_ID CC_KAICXX +#endif +#endif +#define CC_KAICXX 90745 + +#ifndef RLIB_COMPILER_ID +#if defined(__CA__) || defined(__KEIL__) +#define RLIB_COMPILER_ID CC_KEIL_CARM +#endif +#endif +#define CC_KEIL_CARM 90746 + +#ifndef RLIB_COMPILER_ID +#if defined(__C166__) +#define RLIB_COMPILER_ID CC_KEIL_C166 +#endif +#endif +#define CC_KEIL_C166 90747 + +#ifndef RLIB_COMPILER_ID +#if defined(__C51__) || defined(__CX51__) +#define RLIB_COMPILER_ID CC_KEIL_C51 +#endif +#endif +#define CC_KEIL_C51 90748 + +#ifndef RLIB_COMPILER_ID +#if defined(__LCC__) +#define RLIB_COMPILER_ID CC_LCC +#endif +#endif +#define CC_LCC 90749 + +#ifndef RLIB_COMPILER_ID +#if defined(__llvm__) +#define RLIB_COMPILER_ID CC_LLVM +#endif +#endif +#define CC_LLVM 90750 + +#ifndef RLIB_COMPILER_ID +#if defined(__MWERKS__) || defined(__CWCC__) +#define RLIB_COMPILER_ID CC_METROWERKS +#endif +#endif +#define CC_METROWERKS 90751 + +#ifndef RLIB_COMPILER_ID +#if defined(_MSC_VER) +#define RLIB_COMPILER_ID CC_MSVC +#endif +#endif +#define CC_MSVC 90752 + +#ifndef RLIB_COMPILER_ID +#if defined(_MRI) +#define RLIB_COMPILER_ID CC_MICROTEC +#endif +#endif +#define CC_MICROTEC 90753 + +#ifndef RLIB_COMPILER_ID +#if defined(__NDPC__) || defined(__NDPX__) +#define RLIB_COMPILER_ID CC_MICROWAY +#endif +#endif +#define CC_MICROWAY 90754 + +#ifndef RLIB_COMPILER_ID +#if defined(__sgi) || defined(sgi) +#define RLIB_COMPILER_ID CC_MIPSPRO +#endif +#endif +#define CC_MIPSPRO 90755 + +#ifndef RLIB_COMPILER_ID +#if defined(MIRACLE) +#define RLIB_COMPILER_ID CC_MIRACLE +#endif +#endif +#define CC_MIRACLE 90756 + +#ifndef RLIB_COMPILER_ID +#if defined(__MRC__) || defined(MPW_C) || defined(MPW_CPLUS) +#define RLIB_COMPILER_ID CC_MPW +#endif +#endif +#define CC_MPW 90757 + +#ifndef RLIB_COMPILER_ID +#if defined(__CC_NORCROFT) +#define RLIB_COMPILER_ID CC_NORCROFT +#endif +#endif +#define CC_NORCROFT 90758 + +#ifndef RLIB_COMPILER_ID +#if defined(__NWCC__) +#define RLIB_COMPILER_ID CC_NWCC +#endif +#endif +#define CC_NWCC 90759 + +#ifndef RLIB_COMPILER_ID +#if defined(__OPEN64__) || defined(__OPENCC__) +#define RLIB_COMPILER_ID CC_OPEN64 +#endif +#endif +#define CC_OPEN64 90760 + +#ifndef RLIB_COMPILER_ID +#if defined(ORA_PROC) +#define RLIB_COMPILER_ID CC_ORACLE_PROC +#endif +#endif +#define CC_ORACLE_PROC 90761 + +#ifndef RLIB_COMPILER_ID +#if defined(__SUNPRO_C) || defined(__SUNPRO_CC) +#define RLIB_COMPILER_ID CC_SOLARIS +#endif +#endif +#define CC_SOLARIS 90762 + +#ifndef RLIB_COMPILER_ID +#if defined(__PACIFIC__) +#define RLIB_COMPILER_ID CC_PACIFIC +#endif +#endif +#define CC_PACIFIC 90763 + +#ifndef RLIB_COMPILER_ID +#if defined(_PACC_VER) +#define RLIB_COMPILER_ID CC_PLAM +#endif +#endif +#define CC_PLAM 90764 + +#ifndef RLIB_COMPILER_ID +#if defined(__POCC__) +#define RLIB_COMPILER_ID CC_PELLES +#endif +#endif +#define CC_PELLES 90765 + +#ifndef RLIB_COMPILER_ID +#if defined(__PGI) +#define RLIB_COMPILER_ID CC_PORTLAND +#endif +#endif +#define CC_PORTLAND 90766 + +#ifndef RLIB_COMPILER_ID +#if defined(__RENESAS__) || defined(__HITACHI__) +#define RLIB_COMPILER_ID CC_RENESAS +#endif +#endif +#define CC_RENESAS 90767 + +#ifndef RLIB_COMPILER_ID +#if defined(SASC) || defined(__SASC) || defined(__SASC__) +#define RLIB_COMPILER_ID CC_SASC +#endif +#endif +#define CC_SASC 90768 + +#ifndef RLIB_COMPILER_ID +#if defined(_SCO_DS) +#define RLIB_COMPILER_ID CC_SCO_OPENSERVER +#endif +#endif +#define CC_SCO_OPENSERVER 90769 + +#ifndef RLIB_COMPILER_ID +#if defined(SDCC) +#define RLIB_COMPILER_ID CC_SDCC +#endif +#endif +#define CC_SDCC 90770 + +#ifndef RLIB_COMPILER_ID +#if defined(__SNC__) +#define RLIB_COMPILER_ID CC_SN +#endif +#endif +#define CC_SN 90771 + +#ifndef RLIB_COMPILER_ID +#if defined(__VOSC__) +#define RLIB_COMPILER_ID CC_STRATUS_VOS +#endif +#endif +#define CC_STRATUS_VOS 90772 + +#ifndef RLIB_COMPILER_ID +#if defined(__SC__) +#define RLIB_COMPILER_ID CC_SYMANTEC +#endif +#endif +#define CC_SYMANTEC 90773 + +#ifndef RLIB_COMPILER_ID +#if defined(__TenDRA__) +#define RLIB_COMPILER_ID CC_TENDRA +#endif +#endif +#define CC_TENDRA 90774 + +#ifndef RLIB_COMPILER_ID +#if defined(__TI_COMPILER_VERSION__) || defined(_TMS320C6X) +#define RLIB_COMPILER_ID CC_TEXAS +#endif +#endif +#define CC_TEXAS 90775 + +#ifndef RLIB_COMPILER_ID +#if defined(THINKC3) || defined(THINKC4) +#define RLIB_COMPILER_ID CC_THINK +#endif +#endif +#define CC_THINK 90776 + +#ifndef RLIB_COMPILER_ID +#if defined(__TINYC__) +#define RLIB_COMPILER_ID CC_TINYC +#endif +#endif +#define CC_TINYC 90777 + +#ifndef RLIB_COMPILER_ID +#if defined(__TURBOC__) +#define RLIB_COMPILER_ID CC_TURBOC +#endif +#endif +#define CC_TURBOC 90778 + +#ifndef RLIB_COMPILER_ID +#if defined(_UCC) +#define RLIB_COMPILER_ID CC_UCC +#endif +#endif +#define CC_UCC 90779 + +#ifndef RLIB_COMPILER_ID +#if defined(__USLC__) +#define RLIB_COMPILER_ID CC_USLC +#endif +#endif +#define CC_USLC 90780 + +#ifndef RLIB_COMPILER_ID +#if defined(__VBCC__) +#define RLIB_COMPILER_ID CC_VBCC +#endif +#endif +#define CC_VBCC 90781 + +#ifndef RLIB_COMPILER_ID +#if defined(__WATCOMC__) +#define RLIB_COMPILER_ID CC_WATCOM +#endif +#endif +#define CC_WATCOM 90782 + +#ifndef RLIB_COMPILER_ID +#if defined(__ZTC__) +#define RLIB_COMPILER_ID CC_ZORTECH +#endif +#endif +#define CC_ZORTECH 90783 + +#ifndef RLIB_COMPILER_ID +#define RLIB_COMPILER_ID CC_UNKNOWN +#endif +#define CC_UNKNOWN 90784 diff --git a/nemu/include/rlib/sys/fd.hpp b/nemu/include/rlib/sys/fd.hpp new file mode 100644 index 0000000..26ea0f1 --- /dev/null +++ b/nemu/include/rlib/sys/fd.hpp @@ -0,0 +1,14 @@ +#ifndef RLIB_FD_HPP_ +#define RLIB_FD_HPP_ + +#include <rlib/sys/os.hpp> +#if RLIB_OS_ID == OS_WINDOWS +#include <Windows.h> +using fd_t = HANDLE; +using sockfd_t = SOCKET; +#else +using fd_t = int; +using sockfd_t = int; +#endif + +#endif diff --git a/nemu/include/rlib/sys/os.hpp b/nemu/include/rlib/sys/os.hpp new file mode 100644 index 0000000..1843522 --- /dev/null +++ b/nemu/include/rlib/sys/os.hpp @@ -0,0 +1,98 @@ +#ifndef R_OS_HPP +#define R_OS_HPP + +#ifndef RLIB_OS_ID +#if defined(_Windows) || defined(__WIN32__) || defined(_WIN64) || defined(WIN32) +# define RLIB_OS_ID OS_WINDOWS +#elif defined(__linux__) || defined(__linux) +# define RLIB_OS_ID OS_LINUX +#elif defined(__APPLE__) +# include "TargetConditionals.h" +# if TARGET_IPHONE_SIMULATOR +# define RLIB_OS_ID OS_IOS +# elif TARGET_OS_IPHONE +# define RLIB_OS_ID OS_IOS +# elif TARGET_OS_MAC +# define RLIB_OS_ID OS_MACOS +# else +# define RLIB_OS_ID OS_UNKNOWN +# endif +#elif defined(__OS_ANDROID__) +# define RLIB_OS_ID OS_ANDROID +#elif defined(__unix__) || defined(__unix) +# define RLIB_OS_ID OS_UNIX +#else +# define RLIB_OS_ID OS_UNKNOWN +#endif +#endif + +#define RLIB_OS_ID_MAGIC 980427 +#define OS_WINDOWS (RLIB_OS_ID_MAGIC + 1) +#define OS_LINUX (RLIB_OS_ID_MAGIC + 2) +#define OS_MACOS (RLIB_OS_ID_MAGIC + 3) +#define OS_BSD (RLIB_OS_ID_MAGIC + 4) +#define OS_IOS (RLIB_OS_ID_MAGIC + 5) +#define OS_ANDROID (RLIB_OS_ID_MAGIC + 6) +#define OS_UNIX (RLIB_OS_ID_MAGIC + 7) +#define OS_UNKNOWN (RLIB_OS_ID_MAGIC + 8) + +#include "compiler_detector" +// Define RLIB_COMPILER_ID and RLIB_COMPILER_VER + +#if defined(__MINGW32__) || defined(__MINGW64__) +#define RLIB_COMPILER_IS_MINGW 1 +#else +#define RLIB_COMPILER_IS_MINGW 0 +#endif + +// shorthand for __cplusplus macro. +#ifndef RLIB_CXX_STD +# if RLIB_COMPILER_ID == CC_MSVC +# if defined(__cplusplus) +# if __cplusplus == 199711L +# pragma message (": warning MSVC_Wrong__cplusplus: Your MSVC is possibly set __cplusplus to wrong value. Please upgrade to VS2017 15.7 Preview 3 and recompile with /Zc:__cplusplus. Or I'll assume you support C++17 and set RLIB_CXX_STD to 2017. (refer to https://blogs.msdn.microsoft.com/vcblog/2018/04/09/msvc-now-correctly-reports-__cplusplus/)") +# define RLIB_CXX_STD 2017 +# else +# define RLIB_CXX_STD (__cplusplus / 100L) +# endif +# endif +# else +# if defined(__cplusplus) +# define RLIB_CXX_STD (__cplusplus / 100L) +# endif +# endif +#endif + +#if RLIB_CXX_STD >= 2011 +namespace rlib { + class os_info + { + public: + enum class os_t {UNKNOWN = OS_UNKNOWN, WINDOWS = OS_WINDOWS, LINUX = OS_LINUX, MACOS = OS_MACOS, BSD = OS_BSD, IOS = OS_IOS, ANDROID = OS_ANDROID, UNIX = OS_UNIX}; + enum class compiler_t {UNKNOWN = CC_UNKNOWN, GCC = CC_GCC, CLANG = CC_CLANG, MSVC = CC_MSVC, ICC = CC_ICC, BORLAND = CC_BORLAND, IARC = CC_IARC, SOLARIS = CC_SOLARIS/*, ZAPCC = CC_ZAPCC*/}; + //C = CC_Compiler which not supports cxx1x yet is not listed here. 201708. + + static constexpr os_t os = + #if defined(RLIB_OS_ID) + (os_t)RLIB_OS_ID; + #else + os_t::UNKNOWN; + #endif + static constexpr compiler_t compiler = + #if defined(RLIB_COMPILER_ID) + (compiler_t)RLIB_COMPILER_ID; + #else + compiler_t::UNKNOWN; + #endif + static constexpr auto compiler_version = + #if defined(RLIB_COMPILER_VER) + RLIB_COMPILER_VER; + #else + 0; + #endif + }; +} + +#endif + +#endif diff --git a/nemu/include/rlib/sys/rwlock.hpp b/nemu/include/rlib/sys/rwlock.hpp new file mode 100644 index 0000000..9a5be7b --- /dev/null +++ b/nemu/include/rlib/sys/rwlock.hpp @@ -0,0 +1,22 @@ +#ifndef R_SWLOCK_HPP +#define R_SWLOCK_HPP + +#include <pthread.h> +namespace rlib { + [[deprecated]] class RWLock + { + public: + RWLock() : isFree(true) {pthread_rwlock_init(&m_lock, NULL);} + ~RWLock() {pthread_rwlock_destroy(&m_lock);} + void acquireShared() {pthread_rwlock_rdlock(&m_lock);isFree = false;} + void acquireExclusive() {pthread_rwlock_wrlock(&m_lock);isFree = false;} + void release() {pthread_rwlock_unlock(&m_lock);isFree = true;} + // bool tryAcquireShared() {return pthread_rwlock_tryrdlock(&m_lock) == 0;} + // bool tryAcquireExclusive() {return pthread_rwlock_trywrlock(&m_lock) == 0;} + private: + pthread_rwlock_t m_lock; + bool isFree; + }; +} + +#endif diff --git a/nemu/include/rlib/sys/sio.hpp b/nemu/include/rlib/sys/sio.hpp new file mode 100644 index 0000000..bd49b58 --- /dev/null +++ b/nemu/include/rlib/sys/sio.hpp @@ -0,0 +1,664 @@ +#ifndef R_SIO_HPP +#define R_SIO_HPP + +#include <rlib/sys/os.hpp> + +#if RLIB_OS_ID == OS_WINDOWS +#include <winsock2.h> +#include <windows.h> +#include <ws2tcpip.h> +#else +#include <sys/types.h> +#include <sys/socket.h> +#include <netdb.h> +#include <fcntl.h> +#include <arpa/inet.h> +#endif + +// Include winsock2.h before windows.h +#include <cerrno> +#include <cstdlib> +#include <unistd.h> +#include <string> +#include <stdexcept> + +#include <rlib/sys/fd.hpp> +#include <rlib/sys/os.hpp> +#include <rlib/string.hpp> +#include <rlib/scope_guard.hpp> + + +namespace rlib { + // Both POSIX and Win32 + using rlib::literals::operator "" _format; + static inline sockfd_t quick_accept(sockfd_t sock) { + auto res = accept(sock, NULL, NULL); + if(res == -1) + throw std::runtime_error("accept failed. errno = {}"_format(strerror(errno))); + return res; + } + static inline std::pair<std::string, uint16_t> get_peer_name(sockfd_t sock) { + struct sockaddr_storage addr; + socklen_t addrlen = sizeof(addr); + auto res = getpeername(sock, (struct sockaddr *)&addr, &addrlen); + if(res == -1) + throw std::runtime_error("getpeername failed. errno = {}"_format(strerror(errno))); + std::string ipstr; + uint16_t port = 0; + if(addr.ss_family == AF_INET) { + struct sockaddr_in *s = (struct sockaddr_in *)&addr; + char str[INET_ADDRSTRLEN]; + auto res = inet_ntop(AF_INET, &s->sin_addr, str, INET_ADDRSTRLEN); + if(res == NULL) + throw std::runtime_error("inet_ntop failed. errno = {}"_format(strerror(errno))); + port = ntohs(s->sin_port); + ipstr = str; + } + else { + struct sockaddr_in6 *s = (struct sockaddr_in6 *)&addr; + char str[INET6_ADDRSTRLEN]; + auto res = inet_ntop(AF_INET6, &s->sin6_addr, str, INET6_ADDRSTRLEN); + if(res == NULL) + throw std::runtime_error("inet_ntop failed. errno = {}"_format(strerror(errno))); + port = ntohs(s->sin6_port); + ipstr = std::string() + '[' + str + ']'; + } + return {ipstr, port}; + + + } + +#if RLIB_OS_ID != OS_WINDOWS + namespace impl { + inline void MakeNonBlocking(fd_t fd) { + int flags, s; + + flags = fcntl (fd, F_GETFL, 0); + if (flags == -1) { + perror ("fcntl"); + exit(-1); + } + + flags |= O_NONBLOCK; + s = fcntl (fd, F_SETFL, flags); + if (s == -1) { + perror ("fcntl"); + exit(-1); + } + } + } +#endif + +#if RLIB_OS_ID == OS_WINDOWS + template <bool doNotWSAStartup = false> + static inline sockfd_t quick_listen(const std::string &addr, uint16_t port, bool use_udp = false) { + WSADATA wsaData; + sockfd_t listenfd = INVALID_SOCKET; + if(!doNotWSAStartup) { + int iResult = WSAStartup(MAKEWORD(2,2), &wsaData); + if (iResult != 0) throw std::runtime_error("WSAStartup failed with error: {}\n"_format(iResult)); + } + + addrinfo *psaddr; + addrinfo hints { 0 }; + hints.ai_family = AF_UNSPEC; + if(use_udp) { + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + } + else { + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + } + hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */ + auto _ = getaddrinfo(addr.c_str(), std::to_string(port).c_str(), &hints, &psaddr); + if(_ != 0) { + WSACleanup(); + throw std::runtime_error("Failed to getaddrinfo. returnval={}, check `man getaddrinfo`'s return value."_format(_)); + } + + bool success = false; + for (addrinfo *rp = psaddr; rp != NULL; rp = rp->ai_next) { + listenfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (listenfd == INVALID_SOCKET) + continue; + int reuse = 1; + if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(int)) < 0) throw std::runtime_error("setsockopt(SO_REUSEADDR) failed"); + if (bind(listenfd, rp->ai_addr, rp->ai_addrlen) != SOCKET_ERROR) { + success = true; + break; /* Success */ + } + closesocket(listenfd); + } + if(!success) throw std::runtime_error("Failed to bind to any of these addr."); + + if(!use_udp) { + // UDP don't need to listen. + if(SOCKET_ERROR == ::listen(listenfd, 16)) throw std::runtime_error("listen failed. {}"_format(strerror(errno))); + } + + freeaddrinfo(psaddr); + return listenfd; + } + + template <bool doNotWSAStartup = false> + static inline sockfd_t quick_connect(const std::string &addr, uint16_t port, bool use_udp = false) { + WSADATA wsaData; + sockfd_t sockfd = INVALID_SOCKET; + if(!doNotWSAStartup) { + int iResult = WSAStartup(MAKEWORD(2,2), &wsaData); + if (iResult != 0) throw std::runtime_error("WSAStartup failed with error: {}\n"_format(iResult)); + } + + addrinfo *paddr; + addrinfo hints { 0 }; + + hints.ai_family = AF_UNSPEC; + if(use_udp) { + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + } + else { + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + } + + auto _ = getaddrinfo(addr.c_str(), std::to_string(port).c_str(), &hints, &paddr); + if(_ != 0) { + WSACleanup(); + throw std::runtime_error("getaddrinfo failed. Check network connection to {}:{}; returnval={}, check `man getaddrinfo`'s return value."_format(addr.c_str(), port, _)); + } + rlib_defer([p=paddr]{WSACleanup();freeaddrinfo(p);}); + + bool success = false; + for (addrinfo *rp = paddr; rp != NULL; rp = rp->ai_next) { + sockfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (sockfd == INVALID_SOCKET) + continue; + int reuse = 1; + if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(int)) < 0) throw std::runtime_error("setsockopt(SO_REUSEADDR) failed"); + if (connect(sockfd, rp->ai_addr, rp->ai_addrlen) != SOCKET_ERROR) { + success = true; + break; /* Success */ + } + closesocket(sockfd); + } + if(!success) throw std::runtime_error("Failed to connect to any of these addr."); + + freeaddrinfo(paddr); + return sockfd; + } + +#else + // POSIX version + static inline fd_t quick_listen(const std::string &addr, uint16_t port, bool use_udp = false) { + addrinfo *psaddr; + addrinfo hints{0}; + fd_t listenfd; + + hints.ai_family = AF_UNSPEC; + if(use_udp) { + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + } + else { + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + } + hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */ + auto _ = getaddrinfo(addr.c_str(), std::to_string(port).c_str(), &hints, &psaddr); + if (_ != 0) throw std::runtime_error("Failed to getaddrinfo. returnval={}, check `man getaddrinfo`'s return value."_format(_)); + + bool success = false; + for (addrinfo *rp = psaddr; rp != nullptr; rp = rp->ai_next) { + listenfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (listenfd == -1) + continue; + int reuse = 1; + if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (const char *) &reuse, sizeof(int)) < 0) + throw std::runtime_error("setsockopt(SO_REUSEADDR) failed"); + if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEPORT, (const char *) &reuse, sizeof(int)) < 0) + throw std::runtime_error("setsockopt(SO_REUSEPORT) failed"); + if (bind(listenfd, rp->ai_addr, rp->ai_addrlen) == 0) { + success = true; + break; + } + close(listenfd); + } + if (!success) throw std::runtime_error("Failed to bind {}:{}."_format(addr, port)); + + if(!use_udp) { + // UDP don't need to listen. + if (-1 == ::listen(listenfd, 16)) throw std::runtime_error("listen failed. {}"_format(strerror(errno))); + } + + rlib_defer([psaddr] { freeaddrinfo(psaddr); }); + return listenfd; + } + + static inline fd_t quick_connect(const std::string &addr, uint16_t port, bool use_udp = false) { + addrinfo *paddr; + addrinfo hints{0}; + fd_t sockfd; + + hints.ai_family = AF_UNSPEC; + if(use_udp) { + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + } + else { + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + } + + auto _ = getaddrinfo(addr.c_str(), std::to_string(port).c_str(), &hints, &paddr); + if (_ != 0) + throw std::runtime_error("getaddrinfo failed. Check network connection to {}:{}; returnval={}, check `man getaddrinfo`'s return value."_format( + addr.c_str(), port, _)); + rlib_defer([paddr] { freeaddrinfo(paddr); }); + + bool success = false; + for (addrinfo *rp = paddr; rp != NULL; rp = rp->ai_next) { + sockfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (sockfd == -1) + continue; + int reuse = 1; + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char *) &reuse, sizeof(int)) < 0) + throw std::runtime_error("setsockopt(SO_REUSEADDR) failed"); + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, (const char *) &reuse, sizeof(int)) < 0) + throw std::runtime_error("setsockopt(SO_REUSEPORT) failed"); + if (connect(sockfd, rp->ai_addr, rp->ai_addrlen) == 0) { + success = true; + break; /* Success */ + } + close(sockfd); + } + if (!success) throw std::runtime_error("Failed to connect to any of these addr."); + + return sockfd; + } +#endif + +#if RLIB_OS_ID != OS_WINDOWS + // POSIX-only fdIO + class fdIO + { + public: + static ssize_t readn(fd_t fd, void *vptr, size_t n) noexcept //Return -1 on error, read bytes on success, blocks until nbytes done. + { + size_t nleft; + ssize_t nread; + char *ptr; + + ptr = (char *)vptr; + nleft = n; + while (nleft > 0) { + if ( (nread = read(fd, ptr, nleft)) < 0) { + if (errno == EINTR) + nread = 0; /* and call read() again */ + else + return (-1); + } else if (nread == 0) + return (-1); /* EOF */ + + nleft -= nread; + ptr += nread; + } + return (n); /* return success */ + } + static ssize_t writen(fd_t fd, const void *vptr, size_t n) noexcept //Return -1 on error, read bytes on success, blocks until nbytes done. + { + size_t nleft; + ssize_t nwritten; + const char *ptr; + + ptr = (const char *)vptr; + nleft = n; + while (nleft > 0) { + if ( (nwritten = write(fd, ptr, nleft)) <= 0) { + if (nwritten < 0 && errno == EINTR) + nwritten = 0; /* and call write() again */ + else + return (-1); /* error */ + } + + nleft -= nwritten; + ptr += nwritten; + } + return (n); + } + static ssize_t readall(fd_t fd, void **pvptr, size_t initSize) noexcept //Return -1 on error, read bytes on success. pvptr must be a malloc/calloced buffer, I'll malloc one if *pvptr is NULL. + { + size_t current = initSize ? initSize : 1024; + void *vptr = *pvptr; + if(vptr == NULL) + vptr = malloc(current); + void *currvptr = vptr; + + { + ssize_t ret = read(fd, currvptr, current / 2); + if(ret == -1) return -1; + if(ret < current / 2) + { + *pvptr = vptr; + return ret; + } + currvptr = (char *)vptr + current / 2; + } + + while(true) + { + ssize_t ret = read(fd, currvptr, current / 2); + if(ret == -1) return -1; + if(ret < current) + { + *pvptr = vptr; + return ret + current / 2; + } + + current *= 2; + void *vptrBackup = vptr; + if((vptr = realloc(vptr, current)) == NULL) { + free(vptrBackup); + errno = EMSGSIZE; + return -1; + } + currvptr = (char *)vptr + current / 2; + } + } + static void readn_ex(fd_t fd, void *vptr, size_t n) //never return error. + { + auto ret = readn(fd, vptr, n); + if(ret == -1) throw std::runtime_error("readn failed. errno = {}"_format(strerror(errno))); + } + static void writen_ex(fd_t fd, const void *vptr, size_t n) + { + auto ret = writen(fd, vptr, n); + if(ret == -1) throw std::runtime_error("writen failed. errno = {}"_format(strerror(errno))); + } + static ssize_t readall_ex(fd_t fd, void **pvptr, size_t initSize) //never return -1 + { + auto ret = readall(fd, pvptr, initSize); + if(ret == -1) throw std::runtime_error("readall failed. errno = {}"_format(strerror(errno))); + return ret; + } + static std::string quick_readn(fd_t fd, size_t n) { + std::string res(n, '0'); + readn_ex(fd, (void *)res.data(), n); + return res; + } + static std::string quick_readall(fd_t fd) { + void *ptr; + auto size = readall_ex(fd, &ptr, 0); + return std::string((char *)ptr, size); + } + static void quick_write(fd_t fd, const std::string &data) { + writen_ex(fd, data.data(), data.size()); + } + }; +#endif + + // Win32 sockIO + class sockIO + { +#if RLIB_OS_ID == OS_WINDOWS + private: + static int WSASafeGetLastError() + { + int i; + WSASetLastError(i = WSAGetLastError()); + return i; + } + public: + static ssize_t recvn(sockfd_t fd, void *vptr, size_t n, int flags) noexcept //Return -1 on error, read bytes on success, blocks until nbytes done. + { + size_t nleft; + ssize_t nread; + char *ptr; + + ptr = (char *)vptr; + nleft = n; + while (nleft > 0) { + if ( (nread = recv(fd, ptr, nleft, flags)) == SOCKET_ERROR) { + if (WSASafeGetLastError() == WSAEINTR) + nread = 0; /* and call read() again */ + else + return (-1); + } else if (nread == 0) + return (-1); /* EOF */ + + nleft -= nread; + ptr += nread; + } + return (n); /* return >= 0 */ + } + static ssize_t sendn(sockfd_t fd, const void *vptr, size_t n, int flags) noexcept //Return -1 on error, read bytes on success, blocks until nbytes done. + { + size_t nleft; + ssize_t nwritten; + const char *ptr; + + ptr = (const char *)vptr; + nleft = n; + while (nleft > 0) { + if ( (nwritten = send(fd, ptr, nleft, flags)) <= 0) { + if (nwritten == SOCKET_ERROR && WSASafeGetLastError() == WSAEINTR) + nwritten = 0; /* and call write() again */ + else + return (-1); /* error */ + } + + nleft -= nwritten; + ptr += nwritten; + } + return (n); + } + static ssize_t recvall(sockfd_t fd, void **pvptr, size_t initSize, int flags) noexcept //Return -1 on error, read bytes on success. pvptr must be a malloc/calloced buffer, I'll malloc one if *pvptr is NULL. + { + size_t current = initSize ? initSize : 1024; + void *vptr = *pvptr; + if(vptr == NULL) + vptr = malloc(current); + void *currvptr = vptr; + + { + _retry_1: + ssize_t ret = recv(fd, (char *)currvptr, current / 2, flags); + if(ret == SOCKET_ERROR) { + if(WSASafeGetLastError() == WSAEINTR) + goto _retry_1; + return SOCKET_ERROR; + } + if(ret < current / 2) + { + *pvptr = vptr; + return ret; + } + currvptr = (char *)vptr + current / 2; + } + + while(true) + { + ssize_t ret = recv(fd, (char *)currvptr, current / 2, flags); + if(ret == SOCKET_ERROR) { + if(WSASafeGetLastError() == WSAEINTR) + continue; //retry + return SOCKET_ERROR; + } + if(ret < current) + { + *pvptr = vptr; + return ret + current / 2; + } + + current *= 2; + void *vptrBackup = vptr; + if((vptr = realloc(vptr, current)) == NULL) { + free(vptrBackup); + WSASetLastError(WSAEMSGSIZE); + return SOCKET_ERROR; + } + currvptr = (char *)vptr + current / 2; + } + } +#else + // POSIX sockIO + public: + static ssize_t recvn(sockfd_t fd, void *vptr, size_t n, int flags) noexcept //Return -1 on error, read bytes on success, blocks until nbytes done. + { + size_t nleft; + ssize_t nread; + char *ptr; + + ptr = (char *)vptr; + nleft = n; + while (nleft > 0) { + if ( (nread = recv(fd, ptr, nleft, flags)) < 0) { + if (errno == EINTR) + nread = 0; /* and call read() again */ + else + return (-1); + } else if (nread == 0) + return -1; /* EOF */ + + nleft -= nread; + ptr += nread; + } + return (n); /* return success */ + } + static ssize_t sendn(sockfd_t fd, const void *vptr, size_t n, int flags) noexcept //Return -1 on error, read bytes on success, blocks until nbytes done. + { + size_t nleft; + ssize_t nwritten; + const char *ptr; + + ptr = (const char *)vptr; + nleft = n; + while (nleft > 0) { + if ( (nwritten = send(fd, ptr, nleft, flags)) <= 0) { + if (nwritten < 0 && errno == EINTR) + nwritten = 0; /* and call write() again */ + else + return (-1); /* error */ + } + + nleft -= nwritten; + ptr += nwritten; + } + return (n); + } + static ssize_t recvall(sockfd_t fd, void **pvptr, size_t initSize, int flags) noexcept //Return -1 on error, read bytes on success. pvptr must be a malloc/calloced buffer, I'll malloc one if *pvptr is NULL. + { + size_t current = initSize ? initSize : 1024; + void *vptr = *pvptr; + if(vptr == NULL) + vptr = malloc(current); + void *currvptr = vptr; + + { + ssize_t ret = recv(fd, currvptr, current / 2, flags); + if(ret == -1) return -1; + if(ret < current / 2) + { + *pvptr = vptr; + return ret; + } + currvptr = (char *)vptr + current / 2; + } + + while(true) + { + ssize_t ret = recv(fd, currvptr, current / 2, flags); + if(ret == -1) return -1; + if(ret < current) + { + *pvptr = vptr; + return ret + current / 2; + } + + current *= 2; + void *vptrBackup = vptr; + if((vptr = realloc(vptr, current)) == NULL) { + free(vptrBackup); + errno = EMSGSIZE; + return -1; + } + currvptr = (char *)vptr + current / 2; + } + } +#endif + +#ifndef MSG_NOSIGNAL + private: + static constexpr int MSG_NOSIGNAL = 0; +#endif + // both POSIX and Win32 + public: + static void recvn_ex(sockfd_t fd, void *vptr, size_t n, int flags) //return read bytes. + { + auto ret = recvn(fd, vptr, n, flags); + if(ret == -1) throw std::runtime_error("recvn failed. {}"_format(strerror(errno))); + } + static void sendn_ex(sockfd_t fd, const void *vptr, size_t n, int flags) + { + auto ret = sendn(fd, vptr, n, flags); + if(ret == -1) throw std::runtime_error("sendn failed. {}"_format(strerror(errno))); + } + static ssize_t recvall_ex(sockfd_t fd, void **pvptr, size_t initSize, int flags) //never return -1 + { + auto ret = recvall(fd, pvptr, initSize, flags); + if(ret == -1) throw std::runtime_error("recvall failed. {}"_format(strerror(errno))); + return ret; + } + + static std::string quick_recvn(sockfd_t fd, size_t n) { + std::string res(n, '0'); + recvn_ex(fd, (void *)res.data(), n, MSG_NOSIGNAL); + return res; + } + static std::string quick_recvall(sockfd_t fd) { + void *ptr = NULL; + auto size = recvall_ex(fd, &ptr, 0, MSG_NOSIGNAL); + auto result = std::string((char *)ptr, size); + free(ptr); + return result; + } + static void quick_send(sockfd_t fd, const std::string &data) { + sendn_ex(fd, data.data(), data.size(), MSG_NOSIGNAL); + } + + // practical message with head + private: +#pragma pack(push, 1) + struct packed_msg_head { + uint32_t magic = 0x19980427; + uint64_t len; + }; +#pragma pack(pop) + static_assert(sizeof(packed_msg_head) == sizeof(uint32_t) + sizeof(uint64_t), "Compiler doesn't compile the struct `packed_msg_head` as packed."); + public: + static std::string recv_msg(sockfd_t fd) { + packed_msg_head head; + recvn_ex(fd, &head, sizeof(head), MSG_NOSIGNAL); + if(head.magic != 0x19980427) + throw std::runtime_error("Invalid magic received."); + if(head.len > 1024ull*1024*1024*2) + throw std::runtime_error("Message len is greater than 2GiB. Refuse to alloc space."); + std::string dat(head.len, '\0'); + recvn_ex(fd, (void *)dat.data(), head.len, MSG_NOSIGNAL); + return dat; + } + static void send_msg(sockfd_t fd, const std::string &dat) { + packed_msg_head head; + head.len = dat.size(); + sendn_ex(fd, &head, sizeof(head), MSG_NOSIGNAL); + sendn_ex(fd, dat.data(), head.len, MSG_NOSIGNAL); + } + + }; + + +} // namespace rlib + + +#endif diff --git a/nemu/include/rlib/sys/time.hpp b/nemu/include/rlib/sys/time.hpp new file mode 100644 index 0000000..81538b3 --- /dev/null +++ b/nemu/include/rlib/sys/time.hpp @@ -0,0 +1,18 @@ +#ifndef RLIB_TIME_HPP_ +#define RLIB_TIME_HPP_ + +#include <chrono> +#include <ctime> +#include <iomanip> +namespace rlib { + static inline std::string get_current_time_str() noexcept { + std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); + std::time_t now_c = std::chrono::system_clock::to_time_t(now - std::chrono::hours(24)); + static char mbstr[128]; + if (std::strftime(mbstr, sizeof(mbstr), "%c", std::localtime(&now_c))) { + return mbstr; + } + throw std::overflow_error("on get_current_time: mbstr buffer is too small."); + } +} +#endif diff --git a/nemu/include/rlib/sys/unix_handy.hpp b/nemu/include/rlib/sys/unix_handy.hpp new file mode 100644 index 0000000..ffc63bc --- /dev/null +++ b/nemu/include/rlib/sys/unix_handy.hpp @@ -0,0 +1,170 @@ +#ifndef RLIB_UNIX_HANDY_HPP_ +#define RLIB_UNIX_HANDY_HPP_ + +#include <unistd.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <netdb.h> +#include <rlib/scope_guard.hpp> +#include <rlib/string.hpp> + +#include <rlib/sys/os.hpp> +#if RLIB_OS_ID == OS_WINDOWS +#error rlib/sys/unix_handy.hpp is not for Windows. +#endif + +// Deprecated. Use sys/sio.hpp +#if 1+1 == 4 +namespace rlib { + namespace impl { + using rlib::literals::operator""_format; + static inline fd unix_quick_listen(const std::string &addr, uint16_t port, bool use_udp = false) { + addrinfo *psaddr; + addrinfo hints{0}; + fd listenfd; + + hints.ai_family = AF_UNSPEC; + if(use_udp) { + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + } + else { + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + } + hints.ai_flags = AI_PASSIVE; /* For listen */ + auto _ = getaddrinfo(addr.c_str(), std::to_string(port).c_str(), &hints, &psaddr); + if (_ != 0) throw std::runtime_error("Failed to getaddrinfo. returnval={}, check `man getaddrinfo`'s return value."_format(_)); + + bool success = false; + for (addrinfo *rp = psaddr; rp != nullptr; rp = rp->ai_next) { + listenfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (listenfd == -1) + continue; + int reuse = 1; + if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (const char *) &reuse, sizeof(int)) < 0) + throw std::runtime_error("setsockopt(SO_REUSEADDR) failed"); + if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEPORT, (const char *) &reuse, sizeof(int)) < 0) + throw std::runtime_error("setsockopt(SO_REUSEPORT) failed"); + if (bind(listenfd, rp->ai_addr, rp->ai_addrlen) == 0) { + success = true; + break; + } + close(listenfd); + } + if (!success) throw std::runtime_error("Failed to bind {}:{}."_format(addr, port)); + + if (-1 == ::listen(listenfd, 16)) throw std::runtime_error("listen failed."); + + rlib_defer([psaddr] { freeaddrinfo(psaddr); }); + return listenfd; + } + + static inline fd unix_quick_connect(const std::string &addr, uint16_t port, bool use_udp = false) { + addrinfo *paddr; + addrinfo hints{0}; + fd sockfd; + + hints.ai_family = AF_UNSPEC; + if(use_udp) { + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + } + else { + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + } + auto _ = getaddrinfo(addr.c_str(), std::to_string(port).c_str(), &hints, &paddr); + if (_ != 0) + throw std::runtime_error("getaddrinfo failed. Check network connection to {}:{}; returnval={}, check `man getaddrinfo`'s return value."_format( + addr.c_str(), port, _)); + rlib_defer([paddr] { freeaddrinfo(paddr); }); + + bool success = false; + for (addrinfo *rp = paddr; rp != NULL; rp = rp->ai_next) { + sockfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (sockfd == -1) + continue; + int reuse = 1; + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char *) &reuse, sizeof(int)) < 0) + throw std::runtime_error("setsockopt(SO_REUSEADDR) failed"); + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, (const char *) &reuse, sizeof(int)) < 0) + throw std::runtime_error("setsockopt(SO_REUSEPORT) failed"); + if (connect(sockfd, rp->ai_addr, rp->ai_addrlen) == 0) { + success = true; + break; /* Success */ + } + close(sockfd); + } + if (!success) throw std::runtime_error("Failed to connect to any of these addr."); + + return sockfd; + } + } + using impl::unix_quick_connect; + using impl::unix_quick_listen; +} +#endif + + +// Unfinished. I'm not sure if I must implement it. +#if 1+1 == 3 +#include <fstream> +#include <iostream> +#if RLIB_COMPILER_ID == CC_GCC +#include <ext/stdio_filebuf.h> +namespace rlib { + inline std::istream & fd_to_istream(fd handle) { + if(handle == STDIN_FILENO) return std::cin; + __gnu_cxx::stdio_filebuf<char> filebuf(handle, std::ios::in); + return std::istream(&filebuf); + } + inline std::ostream & fd_to_ostream(fd handle) { + if(handle == STDOUT_FILENO) return std::cout; + if(handle == STDERR_FILENO) return std::cerr; + __gnu_cxx::stdio_filebuf<char> filebuf(handle, std::ios::out); + return std::ostream(&filebuf); + } + inline std::iostream & fd_to_iostream(fd handle) { + __gnu_cxx::stdio_filebuf<char> filebuf(handle, std::ios::in | std::ios::out); + return std::iostream(&filebuf); + } +} // rlib +#elif RLIB_COMPILER_ID == CC_MSVC +namespace rlib { + inline std::istream & fd_to_istream(fd handle) { + if(handle == STDIN_FILENO) return std::cin; + ifstream fs(::_fdopen(handle, "r")); + return fs; + } + inline std::ostream & fd_to_ostream(fd handle) { + if(handle == STDOUT_FILENO) return std::cout; + if(handle == STDERR_FILENO) return std::cerr; + ofstream fs(::_fdopen(handle, "w")); + return fs; + } + inline std::iostream & fd_to_iostream(fd handle) { + fstream fs(::_fdopen(handle, "rw")); + return fs; + } +} // rlib +#else +namespace rlib { + constexpr inline std::istream & fd_to_istream(fd handle) { + if(handle == STDIN_FILENO) return std::cin; + throw std::invalid_argument("fd != 0 to istream is not implemented except gcc/msvc."); + } + constexpr inline std::ostream & fd_to_ostream(fd handle) { + if(handle == STDOUT_FILENO) return std::cout; + if(handle == STDERR_FILENO) return std::cerr; + throw std::invalid_argument("fd != 1/2 to ostream is not implemented except gcc/msvc."); + } + constexpr inline std::iostream & fd_to_iostream(fd handle) { + throw std::invalid_argument("fd to iostream is not implemented except gcc/msvc."); + } + +} // rlib +#endif // if compiler +#endif // if 1+1==3 + +#endif // header guarder diff --git a/nemu/include/rlib/terminal.hpp b/nemu/include/rlib/terminal.hpp new file mode 100644 index 0000000..472c122 --- /dev/null +++ b/nemu/include/rlib/terminal.hpp @@ -0,0 +1,100 @@ +/* + * + * terminal.hpp: unix terminal font/color wrapper for modern c++ + * by Recolic Keghart <root@recolic.net> + * MIT License + * + * */ + +#ifndef R_STD_COLOR_HPP +#define R_STD_COLOR_HPP + +#include <rlib/require/cxx11> +#include <rlib/sys/os.hpp> + +#include <iostream> +#include <string> +#include <stdexcept> +#include <exception> +using std::string; +using std::basic_ostream; + +namespace rlib::terminal { + enum class color_t {color_unset = 10, black = 0, red, green, brown, blue, magenta, cyan, lightgray}; + enum class font_t {font_unset = 0, bold = 1, underline = 4, dark = 2, background = 7, striked = 9}; //Edit line53 if (int)font_t may >= 10 !! + class clear_t {} clear; + + class fontInfo + { + public: + fontInfo(color_t text_color) : textColor(text_color) {} + fontInfo(font_t font_type) : fontType(font_type) {} + fontInfo(color_t text_color, font_t font_type) : textColor(text_color), fontType(font_type) {} + fontInfo(const clear_t &) : clear(true) {} + fontInfo() = default; + string toString() const + { + if(rlib::os_info::os == rlib::os_info::os_t::WINDOWS) + return std::move(std::string()); + else + return std::move(clear ? std::string("\033[0m") : (color_to_string() + font_to_string())); + } + private: + color_t textColor = color_t::color_unset; + font_t fontType = font_t::font_unset; + bool clear = false; + private: + constexpr static int color_to_int(const color_t &_ct) + { + return static_cast<int>(_ct); + } + constexpr static int font_to_int(const font_t &_ft) + { + return static_cast<int>(_ft); + } + constexpr static char color_to_char(const color_t &_ct) + { + return _ct == color_t::color_unset ? '\0' : '0' + color_to_int(_ct); //Return '\0' if unset. + } + constexpr static char font_to_char(const font_t &_ft) + { + return _ft == font_t::font_unset ? '\0' :'0' + font_to_int(_ft); + } + string color_to_string() const + { + if(textColor == color_t::color_unset) + return std::move(std::string()); + char toret[] = "\033[3?m"; + toret[3] = color_to_char(textColor); + return std::move(std::string(toret)); + } + string font_to_string() const + { + if(fontType == font_t::font_unset) + return std::move(std::string()); + char toret[] = "\033[?m"; + toret[2] = font_to_char(fontType); + return std::move(std::string(toret)); + } + }; + + struct _rosi_font {_rosi_font(const fontInfo &_ref_fi) : _ref_fi(_ref_fi) {} const fontInfo &_ref_fi;}; + inline _rosi_font setfont(const fontInfo &__fi) {return _rosi_font(__fi);} + + template<typename _CharT, typename _Traits> + inline basic_ostream<_CharT, _Traits>& + operator<<(basic_ostream<_CharT, _Traits>& __os, const fontInfo &__f) + { + __os << __f.toString(); + return __os; + } + + template<typename _CharT, typename _Traits> + inline basic_ostream<_CharT, _Traits>& + operator<<(basic_ostream<_CharT, _Traits>& __os, _rosi_font __rosi_f) + { + const fontInfo &__f = __rosi_f._ref_fi; + return operator<<<_CharT, _Traits>(__os, __f); + } +} +#endif diff --git a/nemu/include/rlib/traits.hpp b/nemu/include/rlib/traits.hpp new file mode 100644 index 0000000..f15fba3 --- /dev/null +++ b/nemu/include/rlib/traits.hpp @@ -0,0 +1,38 @@ +#ifndef RLIB_TRAITS_HPP +#define RLIB_TRAITS_HPP + +#include <type_traits> + +namespace rlib{ + namespace impl { + template<typename T> + struct is_callable_helper { + private: + typedef char(&yes)[1]; + typedef char(&no)[2]; + + struct Fallback { void operator()(); }; + struct Derived : T, Fallback { }; + + template<typename U, U> struct Check; + + template<typename> + static yes test(...); + + template<typename C> + static no test(Check<void (Fallback::*)(), &C::operator()>*); + + static constexpr bool value = sizeof(test<Derived>(0)) == sizeof(yes); + public: + static constexpr bool real_value = std::conditional<std::is_class<T>::value, impl::is_callable_helper<T>, std::is_function<T>>::type::value; + }; + } //impl +} //rlib + +namespace rlib { + template<typename T> + struct is_callable : public std::bool_constant<impl::is_callable_helper<T>::real_value> { + }; +} + +#endif diff --git a/nemu/runall.sh b/nemu/runall.sh old mode 100644 new mode 100755 index a8d5b28..60c4a90 --- a/nemu/runall.sh +++ b/nemu/runall.sh @@ -1,26 +1,33 @@ #!/bin/bash nemu=build/nemu +[[ $show_log = 1 ]] && g_logfile=/tmp/nemu.test.log || g_logfile=/dev/null echo "compiling NEMU..." -if make &> /dev/null; then +if make &> "$g_logfile"; then echo "NEMU compile OK" else - echo "testcases compile error... exit..." - exit + echo "NEMU compile error... exit..." + cat "$g_logfile" + exit 1 fi echo "compiling testcases..." -if make -C $AM_HOME/tests/cputest ARCH=x86-nemu &> /dev/null; then +if make -C $AM_HOME/tests/cputest ARCH=x86-nemu &> "$g_logfile"; then echo "testcases compile OK" + cat "$g_logfile" else echo "testcases compile error... exit..." - exit + cat "$g_logfile" + exit 1 fi +[[ $show_log = 1 ]] && rm $g_logfile files=`ls $AM_HOME/tests/cputest/build/*-x86-nemu.bin` ori_log="build/nemu-log.txt" +has_fail=0 + for file in $files; do base=`basename $file | sed -e 's/-x86-nemu.bin//'` printf "[%14s] " $base @@ -29,12 +36,17 @@ for file in $files; do if (grep 'nemu: HIT GOOD TRAP' $logfile > /dev/null) then echo -e "\033[1;32mPASS!\033[0m" - rm $logfile else echo -e "\033[1;31mFAIL!\033[0m see $logfile for more information" + has_fail=1 if (test -e $ori_log) then echo -e "\n\n===== the original log.txt =====\n" >> $logfile cat $ori_log >> $logfile fi + grep 'HIT GOOD TRAP' $logfile > /dev/null || head -n 512 $logfile >> $g_logfile fi + rm -f $logfile done + +[[ $has_fail = 1 ]] && cat $g_logfile +exit $has_fail -- GitLab