From 309c180400675053e911057a2fc9ecdcc59b7257 Mon Sep 17 00:00:00 2001 From: Keith Williams Date: Tue, 2 Jan 2024 17:43:09 +0000 Subject: [PATCH 1/4] fix build: android/termux/clang-17.0 --- include/crow/json.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/crow/json.h b/include/crow/json.h index 3359a9cc0..d0a2138c0 100644 --- a/include/crow/json.h +++ b/include/crow/json.h @@ -1675,7 +1675,7 @@ namespace crow } else { -#if defined(__APPLE__) || defined(__MACH__) || defined(__FreeBSD__) +#if defined(__APPLE__) || defined(__MACH__) || defined(__FreeBSD__) || defined(__ANDROID__) o = std::unique_ptr(new object(value)); #else (*o) = value; From 9c03767a4b50b8dfc41b80ce32d04523cb25c490 Mon Sep 17 00:00:00 2001 From: Keith Williams Date: Wed, 3 Jan 2024 08:21:45 +0000 Subject: [PATCH 2/4] Android build links with liblog in places --- tests/CMakeLists.txt | 4 ++++ tests/ssl/CMakeLists.txt | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b895a79a6..41c9b2aa8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -11,6 +11,10 @@ add_executable(unittest ${TEST_SRCS}) target_link_libraries(unittest Crow::Crow) add_warnings_optimizations(unittest) +if("${CMAKE_SYSTEM_NAME}" STREQUAL "Android") + target_link_libraries(unittest log) +endif() + if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") set_target_properties(unittest PROPERTIES COMPILE_FLAGS "--coverage -fprofile-arcs -ftest-coverage") target_link_libraries(unittest gcov) diff --git a/tests/ssl/CMakeLists.txt b/tests/ssl/CMakeLists.txt index 07c6c5e36..5c240ad78 100644 --- a/tests/ssl/CMakeLists.txt +++ b/tests/ssl/CMakeLists.txt @@ -11,6 +11,10 @@ add_executable(ssltest ${TEST_SRCS}) target_link_libraries(ssltest Crow::Crow) add_warnings_optimizations(ssltest) +if("${CMAKE_SYSTEM_NAME}" STREQUAL "Android") + target_link_libraries(ssltest log) +endif() + if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") set_target_properties(ssltest PROPERTIES COMPILE_FLAGS "--coverage -fprofile-arcs -ftest-coverage") target_link_libraries(ssltest gcov) From 6a52860cfa3d97df28710bf9d4d308874ec215a2 Mon Sep 17 00:00:00 2001 From: Keith Williams Date: Thu, 11 Jan 2024 03:21:42 +0000 Subject: [PATCH 3/4] Fix clang debug build (Android and FreeBSD) --- cmake/compiler_options.cmake | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/cmake/compiler_options.cmake b/cmake/compiler_options.cmake index ffe1d017c..133ee1461 100644 --- a/cmake/compiler_options.cmake +++ b/cmake/compiler_options.cmake @@ -11,6 +11,27 @@ function(add_warnings_optimizations target_name) $<$:/Zi /O2 /Ob1> $<$:/Zi /Ob0 /Od /RTC1> ) + elseif(NOT CMAKE_COMPILER_IS_GNU AND + "${CMAKE_SYSTEM_NAME}" STREQUAL "Android") + # clang on Android, no prof/gprof + target_compile_options(${target_name} + PRIVATE + -Wall + -Wextra + -Wpedantic + $<$:-O2> + $<$:-O0 -g> + ) + elseif(NOT CMAKE_COMPILER_IS_GNU) + # clang, no prof + target_compile_options(${target_name} + PRIVATE + -Wall + -Wextra + -Wpedantic + $<$:-O2> + $<$:-O0 -g -pg> + ) else() target_compile_options(${target_name} PRIVATE From 6f8b41fc6e6e09f4112c657e4312e299f9c90268 Mon Sep 17 00:00:00 2001 From: Keith Williams Date: Sun, 14 Jan 2024 17:09:33 +0000 Subject: [PATCH 4/4] use lambda wrapper to fix lambda valid/invalid bug --- include/crow/http_connection.h | 8 +++--- include/crow/http_response.h | 4 +-- include/crow/utility.h | 50 +++++++++++++++++++++++++++++++--- tests/unittest.cpp | 22 +++++++++++++++ 4 files changed, 74 insertions(+), 10 deletions(-) diff --git a/include/crow/http_connection.h b/include/crow/http_connection.h index c059ce8d9..7c37cb40a 100644 --- a/include/crow/http_connection.h +++ b/include/crow/http_connection.h @@ -162,7 +162,7 @@ namespace crow need_to_call_after_handlers_ = false; if (!is_invalid_request) { - res.complete_request_handler_ = nullptr; + res.complete_request_handler_.clear(); auto self = this->shared_from_this(); res.is_alive_helper_ = [self]() -> bool { return self->adaptor_.is_open(); @@ -202,7 +202,7 @@ namespace crow void complete_request() { CROW_LOG_INFO << "Response: " << this << ' ' << req_.raw_url << ' ' << res.code << ' ' << close_connection_; - res.is_alive_helper_ = nullptr; + res.is_alive_helper_.clear(); if (need_to_call_after_handlers_) { @@ -271,8 +271,8 @@ namespace crow private: void prepare_buffers() { - res.complete_request_handler_ = nullptr; - res.is_alive_helper_ = nullptr; + res.complete_request_handler_.clear(); + res.is_alive_helper_.clear(); if (!adaptor_.is_open()) { diff --git a/include/crow/http_response.h b/include/crow/http_response.h index 47d1dc171..898fdbb7b 100644 --- a/include/crow/http_response.h +++ b/include/crow/http_response.h @@ -318,8 +318,8 @@ namespace crow private: bool completed_{}; - std::function complete_request_handler_; - std::function is_alive_helper_; + crow::utility::lambda_wrapper complete_request_handler_; + crow::utility::lambda_wrapper is_alive_helper_; static_file_info file_info; }; } // namespace crow diff --git a/include/crow/utility.h b/include/crow/utility.h index be5b08cdb..fe9ae7a6f 100644 --- a/include/crow/utility.h +++ b/include/crow/utility.h @@ -220,7 +220,7 @@ namespace crow { return p == s.size() ? 0 : s[p] == '<' ? ( - is_int(s, p) ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 1 : + is_int(s, p) ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 1 : is_uint(s, p) ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 2 : is_float(s, p) ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 3 : is_str(s, p) ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 4 : @@ -489,7 +489,6 @@ namespace crow namespace detail { - template struct get_index_of_element_from_tuple_by_type_impl { @@ -715,8 +714,8 @@ namespace crow // a special device. Thus we search for the string (case-insensitive), and then check if the string ends or if // is has a dangerous follow up character (.:\/) auto sanitizeSpecialFile = [](std::string& source, unsigned ofs, const char* pattern, bool includeNumber, char replacement) { - unsigned i = ofs; - size_t len = source.length(); + unsigned i = ofs; + size_t len = source.length(); const char* p = pattern; while (*p) { @@ -897,5 +896,48 @@ namespace crow return v.substr(begin, end - begin); } + + class call_error : public std::runtime_error + { + public: + call_error() : std::runtime_error{"call error"} + { + } + }; + + template + class lambda_wrapper + { + public: + lambda_wrapper() = default; + + lambda_wrapper(std::function func) : valid_(true), func_(func) + { + } + + void clear() { valid_ = false; } + + operator bool() const { return valid_; } + + lambda_wrapper& operator=(std::function func) + { + valid_ = true; + func_ = func; + return *this; + } + + ReturnType operator()(Args... args) const + { + if (valid_) + { + return func_(args...); + } + throw call_error(); + } + + private: + mutable bool valid_{}; + std::function func_; + }; } // namespace utility } // namespace crow diff --git a/tests/unittest.cpp b/tests/unittest.cpp index b280f07d6..e8153250f 100644 --- a/tests/unittest.cpp +++ b/tests/unittest.cpp @@ -3445,3 +3445,25 @@ TEST_CASE("lexical_cast") CHECK(utility::lexical_cast(4) == "4"); CHECK(utility::lexical_cast("10", 2) == 10.0f); } + +TEST_CASE("lambda_wrapper") +{ + utility::lambda_wrapper empty; + CHECK(empty != true); + CHECK_THROWS_AS(empty("hello"), crow::utility::call_error); + + utility::lambda_wrapper const_val([]()->int { return 42; }); + CHECK(const_val == true); + CHECK(const_val() == 42); + + utility::lambda_wrapper plus([](int a, int b)->int { return a + b; }); + CHECK(plus == true); + CHECK(plus(2, 3) == 5); + + const std::string name{"Motoko"}; + utility::lambda_wrapper func([name](std::string& str) { str = name; }); + CHECK(func == true); + std::string strval; + func(strval); + CHECK(strval == name); +}