Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ jobs:
# ===================
linux:
runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.experimental || false }}
strategy:
fail-fast: false
matrix:
Expand All @@ -111,6 +112,24 @@ jobs:
install_compiler: true
compiler_package: g++-10

- name: "clang-14, C++23 (early)"
os: ubuntu-22.04
cc: clang-14
cxx: clang++-14
cxx_standard: "-DSQLITE_ORM_ENABLE_CXX_23=ON"
install_compiler: true
compiler_package: clang-14
experimental: true

- name: "gcc-11, C++23 (early)"
os: ubuntu-22.04
cc: gcc-11
cxx: g++-11
cxx_standard: "-DSQLITE_ORM_ENABLE_CXX_23=ON"
install_compiler: true
compiler_package: g++-11
experimental: true

name: Linux - ${{ matrix.name }}

env:
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ cmake-build-debug/
build/
build-xcode/
build-code-edit/
build-local/
*.sqlite
*.db
*.db
4 changes: 4 additions & 0 deletions dev/functional/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@
#define SQLITE_ORM_CPP20_RANGES_SUPPORTED
#endif

#if __cpp_lib_ranges >= 202110L && !defined(SQLITE_ORM_BROKEN_CPP20_VIEWS)
#define SQLITE_ORM_CPP20_VIEWS_SUPPORTED
#endif

#if __cpp_lib_generator >= 202207L
#define SQLITE_ORM_CPP23_GENERATOR_SUPPORTED
#endif
Expand Down
4 changes: 4 additions & 0 deletions dev/functional/cxx_compiler_quirks.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,7 @@
#if defined(SQLITE_ORM_CONCEPTS_SUPPORTED) && (defined(__clang__) && (__clang_major__ == 10))
#define SQLITE_ORM_BROKEN_NONTEMPLATE_CONCEPTS
#endif

#if defined(__clang__) && (__clang_major__ <= 15)
#define SQLITE_ORM_BROKEN_CPP20_VIEWS
#endif
2 changes: 1 addition & 1 deletion dev/statement_serializer.h
Original file line number Diff line number Diff line change
Expand Up @@ -1797,7 +1797,7 @@ namespace sqlite_orm::internal {
const Ctx&) SQLITE_ORM_OR_CONST_CALLOP {
std::stringstream ss;
ss << "SET ";
#ifdef SQLITE_ORM_CPP20_RANGES_SUPPORTED
#ifdef SQLITE_ORM_CPP20_VIEWS_SUPPORTED
ss << streaming_serialized(statement | std::views::transform(&dynamic_set_entry::serialized_value));
#else
int index = 0;
Expand Down
10 changes: 9 additions & 1 deletion include/sqlite_orm/sqlite_orm.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,10 @@ using std::nullptr_t;
#define SQLITE_ORM_BROKEN_NONTEMPLATE_CONCEPTS
#endif

#if defined(__clang__) && (__clang_major__ <= 15)
#define SQLITE_ORM_BROKEN_CPP20_VIEWS
#endif

// #include "platform_definitions.h"

#if defined(_WIN32)
Expand Down Expand Up @@ -313,6 +317,10 @@ using std::nullptr_t;
#define SQLITE_ORM_CPP20_RANGES_SUPPORTED
#endif

#if __cpp_lib_ranges >= 202110L && !defined(SQLITE_ORM_BROKEN_CPP20_VIEWS)
#define SQLITE_ORM_CPP20_VIEWS_SUPPORTED
#endif

#if __cpp_lib_generator >= 202207L
#define SQLITE_ORM_CPP23_GENERATOR_SUPPORTED
#endif
Expand Down Expand Up @@ -23457,7 +23465,7 @@ namespace sqlite_orm::internal {
const Ctx&) SQLITE_ORM_OR_CONST_CALLOP {
std::stringstream ss;
ss << "SET ";
#ifdef SQLITE_ORM_CPP20_RANGES_SUPPORTED
#ifdef SQLITE_ORM_CPP20_VIEWS_SUPPORTED
ss << streaming_serialized(statement | std::views::transform(&dynamic_set_entry::serialized_value));
#else
int index = 0;
Expand Down
12 changes: 12 additions & 0 deletions tests/iterate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ TEST_CASE("Iterate select statement") {
};
#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED
constexpr orm_table_reference auto test_table = c<Test>();
#endif
#ifdef SQLITE_ORM_WITH_CPP20_ALIASES
constexpr orm_table_alias auto test_alias = "t"_alias.for_<Test>();
#endif

Expand All @@ -91,26 +93,32 @@ TEST_CASE("Iterate select statement") {
db.replace(expected);
std::vector<Test> expected_vec{expected};

#ifdef SQLITE_ORM_CPP20_VIEWS_SUPPORTED
SECTION("range-based for") {
for (Test&& obj: db.iterate(select(object<Test>()))) {
REQUIRE(obj == expected);
}
}
#endif

#ifdef SQLITE_ORM_STL_HAS_DEFAULT_SENTINEL
#ifdef SQLITE_ORM_CPP20_VIEWS_SUPPORTED
SECTION("borrowed iterator") {
std::input_iterator auto begin = db.iterate(select(object<Test>())).begin();
REQUIRE(*begin == expected);
REQUIRE(++begin == std::default_sentinel);
}
#endif
#endif

#if __cpp_lib_containers_ranges >= 202202L
#ifdef SQLITE_ORM_CPP20_VIEWS_SUPPORTED
SECTION("from range") {
std::ranges::view auto view = db.iterate(select(object<Test>()));
REQUIRE(std::vector<Test>{std::from_range, view} == expected_vec);
}
#endif
#endif

#if (SQLITE_VERSION_NUMBER >= 3008003) && defined(SQLITE_ORM_WITH_CTE)
#ifdef SQLITE_ORM_WITH_CPP20_ALIASES
Expand All @@ -128,14 +136,18 @@ TEST_CASE("Iterate select statement") {
auto view = db.yield<Test>();
REQUIRE(std::vector<Test>{std::from_range, view} == expected_vec);
}
#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED
SECTION("object generator, table reference") {
auto view = db.yield<test_table>();
REQUIRE(std::vector<Test>{std::from_range, view} == expected_vec);
}
#endif
#ifdef SQLITE_ORM_WITH_CPP20_ALIASES
SECTION("object generator, alias") {
auto view = db.yield<test_alias>();
REQUIRE(std::vector<Test>{std::from_range, view} == expected_vec);
}
#endif
SECTION("select generator") {
auto view = db.yield(select(object<Test>()));
REQUIRE(std::vector<Test>{std::from_range, view} == expected_vec);
Expand Down
30 changes: 22 additions & 8 deletions tests/static_tests/function_static_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
{ storage.template create_aggregate_function<f>() };
{ storage.template delete_aggregate_function<f>() };
};

constexpr auto clamp_int_ptr = &std::clamp<int>;
#endif

TEST_CASE("function static") {
Expand Down Expand Up @@ -248,7 +250,7 @@
static const char* name() {
return "";
}
static int operator()(int);

Check warning on line 253 in tests/static_tests/function_static_tests.cpp

View workflow job for this annotation

GitHub Actions / macOS - Apple Clang, C++17

declaring overloaded 'operator()' as 'static' is a C++2b extension [-Wc++2b-extensions]
};
#endif
struct AFunction {
Expand Down Expand Up @@ -343,16 +345,20 @@
}
#endif
SECTION("freestanding function") {
constexpr auto quotedScalar = "f"_scalar.quote(std::clamp<int>);
using quoted_type = decltype("f"_scalar.quote(std::clamp<int>));
#if defined(__GNUC__) && !defined(__clang__) && (__GNUC__ < 12)
SKIP("GCC < 12 cannot use this function pointer as NTTP in this test.");
#else
constexpr auto quotedScalar = "f"_scalar.quote(clamp_int_ptr);
using quoted_type = decltype("f"_scalar.quote(clamp_int_ptr));
using expected_callable_type = std::remove_cv_t<decltype(clamp_int_ptr)>;

STATIC_REQUIRE(quotedScalar._nme[0] == 'f' && quotedScalar._nme[1] == '\0');
STATIC_REQUIRE(std::is_same_v<decltype(quotedScalar),
const quoted_scalar_function<decltype(&std::clamp<int>),
const quoted_scalar_function<expected_callable_type,
const int&(const int&, const int&, const int&),
2>>);

STATIC_REQUIRE(std::is_same_v<quoted_type::callable_type, decltype(&std::clamp<int>)>);
STATIC_REQUIRE(std::is_same_v<quoted_type::callable_type, expected_callable_type>);
STATIC_REQUIRE(std::is_same_v<quoted_type::udf_type, const int&(const int&, const int&, const int&)>);

STATIC_REQUIRE(std::is_same_v<callable_arguments<quoted_type::udf_type>::return_type, int>);
Expand All @@ -368,18 +374,25 @@

using storage_type = decltype(make_storage(""));
STATIC_REQUIRE(storage_scalar_callable<storage_type, quotedScalar>);
#endif
}
SECTION("template function") {
constexpr auto quotedScalar = "f"_scalar.quote<const int&(const int&, const int&, const int&)>(std::clamp);
using quoted_type = decltype("f"_scalar.quote<const int&(const int&, const int&, const int&)>(std::clamp));
#if defined(__GNUC__) && !defined(__clang__) && (__GNUC__ < 12)
SKIP("GCC < 12 cannot use this function pointer as NTTP in this test.");
#else
constexpr auto quotedScalar =
"f"_scalar.quote<const int&(const int&, const int&, const int&)>(clamp_int_ptr);
using quoted_type =
decltype("f"_scalar.quote<const int&(const int&, const int&, const int&)>(clamp_int_ptr));
using expected_callable_type = std::remove_cv_t<decltype(clamp_int_ptr)>;

STATIC_REQUIRE(quotedScalar._nme[0] == 'f' && quotedScalar._nme[1] == '\0');
STATIC_REQUIRE(std::is_same_v<decltype(quotedScalar),
const quoted_scalar_function<decltype(&std::clamp<int>),
const quoted_scalar_function<expected_callable_type,
const int&(const int&, const int&, const int&),
2>>);

STATIC_REQUIRE(std::is_same_v<quoted_type::callable_type, decltype(&std::clamp<int>)>);
STATIC_REQUIRE(std::is_same_v<quoted_type::callable_type, expected_callable_type>);
STATIC_REQUIRE(std::is_same_v<quoted_type::udf_type, const int&(const int&, const int&, const int&)>);

STATIC_REQUIRE(std::is_same_v<callable_arguments<quoted_type::udf_type>::return_type, int>);
Expand All @@ -395,6 +408,7 @@

using storage_type = decltype(make_storage(""));
STATIC_REQUIRE(storage_scalar_callable<storage_type, quotedScalar>);
#endif
}
SECTION("lambda") {
constexpr auto lambda = [](unsigned long errcode) {
Expand Down
12 changes: 10 additions & 2 deletions tests/static_tests/iterator_t.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,10 @@ concept storage_yield_result_set = requires(S& storage_type, Select select) {

namespace {
struct Object {};
#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED
#if defined(SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED) && defined(SQLITE_ORM_WITH_CPP20_ALIASES)
constexpr orm_table_alias auto object_alias = "o"_alias.for_<Object>();
#endif
#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED
constexpr orm_table_reference auto object_table = c<Object>();
#endif
}
Expand Down Expand Up @@ -177,9 +179,15 @@ TEST_CASE("can view and iterate mapped") {

#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED
STATIC_REQUIRE(storage_iterate_mapped<storage_type, Object>);
#ifdef SQLITE_ORM_CPP20_VIEWS_SUPPORTED
STATIC_REQUIRE(storage_iterate_mapped_ref<storage_type, object_table, Object>);
#endif
#ifdef SQLITE_ORM_WITH_CPP20_ALIASES
#ifdef SQLITE_ORM_CPP20_VIEWS_SUPPORTED
STATIC_REQUIRE(storage_iterate_mapped_ref<storage_type, object_alias, Object>);
#endif
#endif
#endif

#ifdef SQLITE_ORM_CPP23_GENERATOR_SUPPORTED
STATIC_REQUIRE(storage_yield_mapped<storage_type, Object, Object>);
Expand All @@ -188,7 +196,7 @@ TEST_CASE("can view and iterate mapped") {
#endif
}

#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED
#if defined(SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED) && defined(SQLITE_ORM_CPP20_VIEWS_SUPPORTED)
TEST_CASE("can view and iterate result set") {
struct Object {};
using empty_storage_type = decltype(make_storage(""));
Expand Down
16 changes: 16 additions & 0 deletions tests/user_defined_functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@

#ifdef SQLITE_ORM_STATIC_CALL_OPERATOR_SUPPORTED
struct StaticCallOpFunction {
static bool operator()(int x, int y) {

Check warning on line 221 in tests/user_defined_functions.cpp

View workflow job for this annotation

GitHub Actions / macOS - Apple Clang, C++17

declaring overloaded 'operator()' as 'static' is a C++2b extension [-Wc++2b-extensions]
return x == y;
}

Expand Down Expand Up @@ -569,6 +569,9 @@
storage.sync_schema();

SECTION("freestanding function") {
#if defined(__GNUC__) && !defined(__clang__) && (__GNUC__ < 12)
SKIP("GCC < 12 cannot use this function as NTTP in quoted scalar tests.");
#else
constexpr auto err_fatal_error_f = "ERR_FATAL_ERROR"_scalar.quote(ERR_FATAL_ERROR);
Comment thread
trueqbit marked this conversation as resolved.
storage.create_scalar_function<err_fatal_error_f>();
{
Expand All @@ -577,6 +580,7 @@
REQUIRE(rows == expected);
}
storage.delete_scalar_function<err_fatal_error_f>();
#endif
}
SECTION("stateless lambda") {
constexpr auto is_fatal_error_f = "is_fatal_error"_scalar.quote([](unsigned long errcode) {
Expand Down Expand Up @@ -659,6 +663,9 @@
}
#endif
SECTION("specialized template function") {
#if defined(__GNUC__) && !defined(__clang__) && (__GNUC__ < 12)
SKIP("GCC < 12 cannot use std::clamp specialization as NTTP.");
#else
constexpr auto clamp_int_f = "clamp_int"_scalar.quote(std::clamp<int>);
Comment thread
trueqbit marked this conversation as resolved.
storage.create_scalar_function<clamp_int_f>();
{
Expand All @@ -667,8 +674,12 @@
REQUIRE(rows == expected);
}
storage.delete_scalar_function<clamp_int_f>();
#endif
}
SECTION("overloaded template function") {
#if defined(__GNUC__) && !defined(__clang__) && (__GNUC__ < 12)
SKIP("GCC < 12 cannot use std::clamp overload as NTTP.");
#else
constexpr auto clamp_int_f =
"clamp_int"_scalar.quote<const int&(const int&, const int&, const int&)>(std::clamp);
Comment thread
trueqbit marked this conversation as resolved.
storage.create_scalar_function<clamp_int_f>();
Expand All @@ -678,6 +689,7 @@
REQUIRE(rows == expected);
}
storage.delete_scalar_function<clamp_int_f>();
#endif
}
SECTION("non-copyable function object") {
// note: unlike msvc, gcc+clang require a constant template parameter to be copyable (and probably rightly so);
Expand All @@ -703,6 +715,9 @@
storage.delete_scalar_function<offset0_f>();
}
SECTION("escaped function identifier") {
#if defined(__GNUC__) && !defined(__clang__) && (__GNUC__ < 12)
SKIP("GCC < 12 cannot use std::clamp specialization as NTTP.");
#else
constexpr auto clamp_f = R"("clamp int")"_scalar.quote(std::clamp<int>);
Comment thread
trueqbit marked this conversation as resolved.
storage.create_scalar_function<clamp_f>();
{
Expand All @@ -711,6 +726,7 @@
REQUIRE(rows == expected);
}
storage.delete_scalar_function<clamp_f>();
#endif
}
}
#endif
Loading