diff --git a/README.md b/README.md index b6cf080022172f26dce69c6fff71d0eea00ca543..13c9e78a693475e8ad68c62d578a3e5f74caea3f 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ # rlib [](https://www.codefactor.io/repository/github/recolic/rlib/overview/master) -  Here is recolic's private library... diff --git a/c-with-class.h b/c-with-class.h index da40c96fbf7183a2024d0c32f70e0666f7cdb455..4a45bc53417d1e0f300820e875c1164f0ad8a2a6 100644 --- a/c-with-class.h +++ b/c-with-class.h @@ -14,9 +14,9 @@ #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_DECL_1(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_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_2(class_name, method_name) RCPP_CLASS_MEMBER_DECL(class_name##method_name##_rcpp_t, method_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, ...` diff --git a/functional.hpp b/functional.hpp index 17ca11dd9c7bbc81df90fa5454aa2c603d335627..c14bc9b603a1e89091bb05cabad97dff15669688 100644 --- a/functional.hpp +++ b/functional.hpp @@ -26,9 +26,10 @@ namespace rlib { 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 std::move(ret); + return ret; } }; @@ -55,6 +56,9 @@ namespace rlib { 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> diff --git a/stdio.hpp b/stdio.hpp index fe4f69789e382605ed72cfaab385e75a0f6a9875..fe1eed8678dfe562a951363842ee99658b0ea22f 100644 --- a/stdio.hpp +++ b/stdio.hpp @@ -15,6 +15,7 @@ #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" @@ -24,6 +25,23 @@ #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> @@ -55,16 +73,13 @@ namespace rlib { return std::move(line); } -// print to stdout - template <typename PrintFinalT> - void print(PrintFinalT reqArg); - template <typename Required, typename... Optional> - void print(Required reqArgs, Optional... optiArgs); - template <typename... Optional> - void println(Optional... optiArgs); + // 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> @@ -73,12 +88,13 @@ namespace rlib { 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 { #if RLIB_CXX_STD < 2017 extern bool enable_endl_flush; @@ -103,70 +119,7 @@ namespace rlib { return os; } - template <typename PrintFinalT> - void print(PrintFinalT reqArg) - { - std::cout << reqArg; - } - template <typename Required, typename... Optional> - void print(Required reqArgs, Optional... optiArgs) - { - std::cout << reqArgs << ' '; - print(optiArgs ...); - } - template <typename... Optional> - void println(Optional... optiArgs) - { - print(optiArgs ...); - println(); - } - template <> - inline void println() - { - std::cout << rlib::endl; - } - - template <typename Iterable, typename Printable> - void print_iter(Iterable arg, Printable spliter) - { - for(const auto & i : arg) - std::cout << i << spliter; - } - template <typename Iterable, typename Printable> - void println_iter(Iterable arg, Printable spliter) - { - print_iter(arg, spliter); - std::cout << rlib::endl; - } - template <typename Iterable> - void print_iter(Iterable arg) - { - for(const auto & i : arg) - std::cout << i << ' '; - } - template <typename Iterable> - void println_iter(Iterable arg) - { - print_iter(arg); - std::cout << rlib::endl; - } - - template <typename... Args> - size_t printf(const std::string &fmt, Args... args) - { - std::string to_print = impl::format_string(fmt, args...); - std::cout << to_print; - return to_print.size(); - } - template <typename... Args> - size_t printfln(const std::string &fmt, Args... args) - { - size_t len = rlib::printf(fmt, args...); - std::cout << rlib::endl; - return len + 1; - } - -// With custom os + // With custom os template <typename PrintFinalT> void print(std::ostream &os, PrintFinalT reqArg) { @@ -182,7 +135,7 @@ namespace rlib { void println(std::ostream &os, Optional... optiArgs) { print(os, optiArgs ...); - println(); + println(os); } template <> inline void println(std::ostream &os) @@ -200,35 +153,91 @@ namespace rlib { void println_iter(std::ostream &os, Iterable arg, Printable spliter) { print_iter(os, arg, spliter); - os << rlib::endl; + println(os); } template <typename Iterable> void print_iter(std::ostream &os, Iterable arg) { - for(const auto & i : arg) - os << i << ' '; + print_iter(os, arg, ' '); } template <typename Iterable> void println_iter(std::ostream &os, Iterable arg) { - print_iter(os, arg); - os << rlib::endl; + println_iter(os, arg, ' '); } template <typename... Args> size_t printf(std::ostream &os, const std::string &fmt, Args... args) { - std::string to_print = format_string(fmt, args...); - os << to_print; + 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 = rlib::printf(fmt, args...); - os << rlib::endl; + 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 <> + 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) ...); + } } diff --git a/test/Makefile b/test/Makefile index 4eb71319bfb2bd0c862a9fe626c944d3d8ac2b5b..a81d86444a9921db0ae3e5244fe8c59c8f4a1ea0 100644 --- a/test/Makefile +++ b/test/Makefile @@ -16,10 +16,13 @@ # os rlib/sys/os.hpp # require rlib/require/*.hpp +# Test dependency: +# string ---> common + MODULES=string meta trait stdio sio scope_guard -EXTRA_FLAGS ?= -CXXFLAGS=-I. $(EXTRA_FLAGS) +XTRA_FLAGS ?= +CXXFLAGS=-I. -I../.. $(XTRA_FLAGS) STD ?= 14 FLAGS11=-std=c++11 rlib/libr.a FLAGS14=-std=c++14 rlib/libr.a @@ -37,7 +40,11 @@ endif POSTFIX=$(STD)_$(CXX) -all: string +all: string common + +common: + $(CXX) $(CXXFLAGS) src/common.cc $(CXXFLAGS) -o src/common_$(POSTFIX).out + src/common_$(POSTFIX).out string: $(CXX) $(CXXFLAGS) src/string.cc $(CXXFLAGS) -o src/string_$(POSTFIX).out diff --git a/test/src/call.cc b/test/src/call.cc deleted file mode 100644 index 67c5ab5a319fe62ee7c6178a02b19fd610f9da21..0000000000000000000000000000000000000000 --- a/test/src/call.cc +++ /dev/null @@ -1,17 +0,0 @@ -#include <rlib/traits.hpp> - -using namespace rlib; - -void f(int); - -class c{ -public: - auto operator()(int a){ - return a+1; - } -}; - -int main(){ - static_assert(is_callable<decltype(f)>(), "a"); - static_assert(is_callable<c>(), "b"); -} diff --git a/test/src/cclass.c b/test/src/cclass.c index 1c0e8cee8994956705c669ec6ed561ed4469355a..80c61df3a7719ff0229c393a9e51148ff871829c 100644 --- a/test/src/cclass.c +++ b/test/src/cclass.c @@ -1,36 +1,61 @@ #include <rlib/c-with-class.h> #include <stdio.h> +#include <stdlib.h> + +typedef int element_type; RCPP_CLASS_DECL(vector) -RCPP_CLASS_METHOD_DECL_1(vector, push_back, void, int) -RCPP_CLASS_METHOD_DECL_1(vector, at, int, int) +RCPP_CLASS_METHOD_EXTERN_DECL(vector, push_back, void, element_type) +RCPP_CLASS_METHOD_EXTERN_DECL(vector, at, element_type, int) RCPP_CLASS_BEGIN(vector) -RCPP_CLASS_METHOD_DECL_2(vector, push_back) -RCPP_CLASS_METHOD_DECL_2(vector, at) +RCPP_CLASS_METHOD_DECL(vector, push_back, void, element_type) +RCPP_CLASS_METHOD_DECL(vector, at, element_type, int) +RCPP_CLASS_MEMBER_DECL(element_type *, data) +RCPP_CLASS_MEMBER_DECL(int, m_size) +RCPP_CLASS_MEMBER_DECL(int, m_cap) RCPP_CLASS_END() -RCPP_CLASS_METHOD_IMPL(vector, push_back, void, int data) { - printf("pushing back %d\n", data); +RCPP_CLASS_METHOD_IMPL(vector, push_back, void, element_type data) { + if(this->m_size == this->m_cap) { + this->m_cap += 1; + this->m_cap *= 2; + this->data = realloc(this->data, this->m_cap * sizeof(element_type)); + } + this->data[this->m_size] = data; + ++this->m_size; } -RCPP_CLASS_METHOD_IMPL(vector, at, int, int index) { - int element = index * index; - return element; +RCPP_CLASS_METHOD_IMPL(vector, at, element_type, int index) { + if(index >= this->m_size) { + abort(); + } + return this->data[index]; } RCPP_CLASS_CONSTRUCTOR_IMPL(vector) { RCPP_CLASS_METHOD_REGISTER(vector, push_back) RCPP_CLASS_METHOD_REGISTER(vector, at) - printf("constructor called\n"); + this->m_cap = this->m_size = 0; + this->data = NULL; + printf("Constructor called!\n"); } RCPP_CLASS_DESTRUCTOR_IMPL(vector) { - printf("destructor called\n"); + if(this->data) + free(this->data); + printf("Destructor called!\n"); } + int main(){ RCPP_NEW(vector, vct, NULL); - RCPP_CALL(vct, push_back, 333); - vct.push_back(&vct, 666); + RCPP_CALL(vct, push_back, 3); + RCPP_CALL(vct, push_back, 2); + RCPP_CALL(vct, push_back, 1); + vct.push_back(&vct, 6); + vct.push_back(&vct, 7); + vct.push_back(&vct, 8); - printf("Element at index %d is %d.\n", 5, vct.at(&vct, 5)); - return 123; + for(int cter = 0; cter < vct.m_size; ++cter) { + printf("Element at index %d is %d.\n", cter, RCPP_CALL(vct, at, cter)); + } + return 0; } diff --git a/test/src/common.cc b/test/src/common.cc new file mode 100644 index 0000000000000000000000000000000000000000..e038767f762e006420f3f3cafc2757faba5b19fa --- /dev/null +++ b/test/src/common.cc @@ -0,0 +1,77 @@ +#define CATCH_CONFIG_MAIN +#include <catch.hpp> + +#include <rlib/stdio.hpp> +#include <stdexcept> +#include <sstream> +#include <thread> +#include <chrono> + +void test_f(int); +class test_c { +public: + auto operator()(int a) { + return a; + } +}; + +#if RLIB_CXX_STD >= 2017 +#include <rlib/functional.hpp> +#include <rlib/traits.hpp> +TEST_CASE("functional") { + std::stringstream test_ss; + auto test_func = [&](int i) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + rlib::println(test_ss, "i", i); + return i; + }; + + auto time_cost = rlib::timeof(rlib::repeat(10, test_func, 1)); + REQUIRE(time_cost > 0.7); + REQUIRE_THROWS_AS(rlib::timeof(rlib::repeat(0, test_func, 1)), std::invalid_argument); + + std::string answer; + for(auto cter = 0; cter < 10; ++cter) { + answer += "i 1" RLIB_IMPL_ENDLINE; + } + REQUIRE(test_ss.str() == answer); + + auto result = rlib::repeat(2, test_func, 1)(); + REQUIRE(result == 1); + auto result2 = rlib::repeat_and_return_list(2, test_func, 2)(); + REQUIRE(result2.size() == 2); + REQUIRE(*result2.begin() == 2); +} + +TEST_CASE("traits") { + auto lmbda = []()->bool{return true;}; + REQUIRE(rlib::is_callable<test_c>()); + REQUIRE(rlib::is_callable<decltype(test_f)>()); + REQUIRE(rlib::is_callable<void()>()); + REQUIRE(rlib::is_callable<decltype(lmbda)>()); + REQUIRE(rlib::is_callable<std::function<void(int)>>()); + REQUIRE_FALSE(rlib::is_callable<int>()); + REQUIRE_FALSE(rlib::is_callable<std::ostream>()); +} +#endif // RLIB_CXX_STD > 2017 + +struct rlib_test_printable { + int d = 1; + friend std::ostream& operator<< (std::ostream& stream, const rlib_test_printable & p) { + stream << p.d; + return stream; + } +}; +TEST_CASE("stdio.hpp") { + std::stringstream test_ss; + rlib::print(test_ss, '>'); + rlib::println(test_ss, "a", 'b', 123, 0.25, rlib_test_printable{2}); + REQUIRE(test_ss.str() == ">a b 123 0.25 2" RLIB_IMPL_ENDLINE); + + rlib::printf(test_ss, "{}{}", 1, ""); + rlib::printfln(test_ss, "hello, {}.", "godaddy"); + REQUIRE(rlib::scanln(test_ss) == ">a b 123 0.25 2"); + REQUIRE(rlib::scanln(test_ss) == "1hello, godaddy."); +} + + diff --git a/test/src/functional.cc b/test/src/functional.cc deleted file mode 100644 index 3ffb37d5ba909518a8fb53b1cd4d88a7d0a2ca82..0000000000000000000000000000000000000000 --- a/test/src/functional.cc +++ /dev/null @@ -1,25 +0,0 @@ -#include <rlib/functional.hpp> -#include <rlib/stdio.hpp> - - -int main() { -// auto f = rlib::repeat(4, [](int i){ -// rlib::println("i is", i); -// }, 777); -// f(); - auto m = [](int i){ - rlib::println("i is", i); - }; - std::function<void(int)> b (m); - auto f = rlib::repeat(4, m, 777); -// f(4,m,444); -// auto ff = std::bind(&decltype(f)::operator(), &f, 4, m, 444); - //std::function<void(size_t, decltype(m), int)> goodf(f); - -// auto ff = std::bind(f, 4,m,444); - f(); - - rlib::println("time of f is", rlib::timeof(f)); - -} - diff --git a/test/src/print.cc b/test/src/print.cc deleted file mode 100644 index fd4f0852de1f5fac13cecacde2cedf079f98747a..0000000000000000000000000000000000000000 --- a/test/src/print.cc +++ /dev/null @@ -1,11 +0,0 @@ -#include <rlib/stdio.hpp> -#include <rlib/terminal.hpp> -using namespace rlib; -using namespace rlib::terminal; - -int main() { - auto cter = printfln("{}Hello, {}={}, miao{}.{}", color_t::red, 6.6, 7, "www", clear); - printfln("cter={}.", cter); - println("test"); - return 0; -} diff --git a/test/src/string.cc b/test/src/string.cc index 8a711e0199cfef977a46f3948c9022f6a7d10ea7..82d784689d8b8bfc7ea17054582954603768494a 100644 --- a/test/src/string.cc +++ b/test/src/string.cc @@ -1,6 +1,6 @@ #define CATCH_CONFIG_MAIN -#include "../catch.hpp" +#include <catch.hpp> #include <rlib/string.hpp> #include <stdexcept> diff --git a/traits.hpp b/traits.hpp index 43eda722402cd88f75b535c580fd1836a164ab52..f15fba33d619885e8b81300741a1fc76f6689898 100644 --- a/traits.hpp +++ b/traits.hpp @@ -22,22 +22,16 @@ namespace rlib{ template<typename C> static no test(Check<void (Fallback::*)(), &C::operator()>*); - public: 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 { - using _impl = typename std::conditional<std::is_class<T>::value, impl::is_callable_helper<T>, std::is_function<T>>::type; - static constexpr bool value() noexcept { - return _impl::value; - } - constexpr operator bool() noexcept { - return is_callable<T>::value(); - } + struct is_callable : public std::bool_constant<impl::is_callable_helper<T>::real_value> { }; }