Skip to content

Commit 4e41951

Browse files
authored
Merge pull request #8 from spoorendonk/gcc14-build
Gcc14 build
2 parents 261132a + fcbf768 commit 4e41951

12 files changed

Lines changed: 268 additions & 18 deletions

File tree

.github/workflows/c-cpp.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,26 @@ jobs:
2727
conan profile detect --name=default
2828
make CONAN_PROFILE=.github/workflows/gcc15_c++26
2929
30+
linux-gcc14-build:
31+
runs-on: ubuntu-latest
32+
container:
33+
image: ubuntu:24.04
34+
steps:
35+
- uses: actions/checkout@v3
36+
- name: Update APT
37+
run: sudo apt-get update && sudo apt-get upgrade -y
38+
- name: Install GCC-14 and CMake
39+
run: sudo apt-get install -y gcc-14 g++-14 cmake
40+
- name: Install Conan 2.0
41+
run: |
42+
sudo apt-get install -y pipx
43+
pipx install conan
44+
echo "$HOME/.local/bin" >> $GITHUB_PATH
45+
- name: Build and run unit tests
46+
run: |
47+
conan profile detect --name=default
48+
make CONAN_PROFILE=.github/workflows/gcc14_c++23
49+
3050
# windows-build:
3151
# runs-on: windows-latest
3252
# steps:

.github/workflows/gcc14_c++23

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[settings]
2+
os=Linux
3+
arch=x86_64
4+
build_type=Release
5+
compiler=gcc
6+
compiler.cppstd=23
7+
compiler.version=14
8+
compiler.libcxx=libstdc++11
9+
10+
[buildenv]
11+
CC=gcc-14
12+
CXX=g++-14
13+
14+
[options]
15+
gcc14_compat=True

CMakeLists.txt

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,20 @@ project(
66
LANGUAGES CXX)
77

88
# ################### Options ####################
9-
set(CMAKE_CXX_STANDARD 26)
9+
option(MELON_ENABLE_GCC14_SUPPORT
10+
"Enable the optional GNU++14/C++23 compatibility layer." ON)
11+
if(MELON_ENABLE_GCC14_SUPPORT)
12+
set(_melon_default_cxx 23)
13+
else()
14+
set(_melon_default_cxx 26)
15+
endif()
16+
if(NOT DEFINED CMAKE_CXX_STANDARD)
17+
set(CMAKE_CXX_STANDARD ${_melon_default_cxx})
18+
endif()
1019
set(CMAKE_CXX_STANDARD_REQUIRED ON)
20+
set(CMAKE_CXX_EXTENSIONS OFF)
21+
option(MELON_BUILD_TESTS "Build the melon test suite" ON)
22+
option(MELON_FROM_CONAN "Indicates the project is configured from Conan" OFF)
1123

1224
# ################### Modules ####################
1325
include(GNUInstallDirs)
@@ -17,3 +29,8 @@ add_library(melon INTERFACE)
1729
target_include_directories(
1830
melon INTERFACE $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
1931
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
32+
33+
# ################### Tests ####################
34+
if(MELON_BUILD_TESTS)
35+
add_subdirectory(test)
36+
endif()

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,16 @@ Work in progress.
1313

1414
## How to link
1515

16-
:warning: Since commit [e494eb8d7db1629af280354dc4d76d3c36ed8701](https://github.com/fhamonic/melon/commit/e494eb8d7db1629af280354dc4d76d3c36ed8701) the use of Range-v3 has been replaced by C++26 ranges functionnalities which are currently only implemented in GCC 15.
16+
:warning: Since commit [e494eb8d7db1629af280354dc4d76d3c36ed8701](https://github.com/fhamonic/melon/commit/e494eb8d7db1629af280354dc4d76d3c36ed8701) the library leans on C++26 ranges functionalities which are currently only implemented in GCC 15.
1717

1818
| Compiler | Minimum version |
1919
| ----------- | --------------- |
2020
| GCC | 15 |
2121
| Clang | -- |
2222
| MSVC | -- |
2323

24+
:bulb: Need to stay on GCC 14 / C++23? Configure with `-DMELON_ENABLE_GCC14_SUPPORT=ON` (or pass `-o melon:gcc14_compat=True` when using Conan) to make Melon use its internal adapter shims so you keep the same API without any extra dependencies.
25+
2426
### As a local Conan package (latest commit)
2527

2628
```

conanfile.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ class MelonConan(ConanFile):
99
name = "melon"
1010
version = "1.0.0-alpha.1"
1111

12+
options = {"gcc14_compat": [True, False]}
13+
default_options = {"gcc14_compat": False}
14+
1215
license = "BSL-1.0"
1316
description = (
1417
"A modern and efficient graph library using C++20 ranges and concepts."
@@ -21,20 +24,32 @@ class MelonConan(ConanFile):
2124
no_copy_source = True
2225
generators = "CMakeToolchain", "CMakeDeps"
2326

24-
def requirements(self):
27+
def requirements(self):
2528
self.test_requires("gtest/[>=1.10.0 <cci]")
2629
# self.test_requires("mppp/1.0.3")
2730

31+
def _gcc14_enabled(self):
32+
return bool(self.options.get_safe("gcc14_compat", False))
33+
2834
def validate(self):
29-
check_min_cppstd(self, 26)
35+
min_std = 23 if self._gcc14_enabled() else 26
36+
check_min_cppstd(self, min_std)
3037

3138
def layout(self):
3239
cmake_layout(self)
3340

3441
def build(self):
3542
if not self.conf.get("tools.build:skip_test", default=False):
3643
cmake = CMake(self)
37-
cmake.configure(build_script_folder="test")
44+
cmake.configure(
45+
build_script_folder="test",
46+
variables={
47+
"MELON_ENABLE_GCC14_SUPPORT": "ON"
48+
if self._gcc14_enabled()
49+
else "OFF",
50+
"MELON_FROM_CONAN": "ON",
51+
},
52+
)
3853
cmake.build()
3954
self.run(os.path.join(self.cpp.build.bindir, "melon_test"))
4055

include/melon/algorithm/bidirectional_dijkstra.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <vector>
1313

1414
#include "melon/container/d_ary_heap.hpp"
15+
#include "melon/detail/concat_view.hpp"
1516
#include "melon/detail/intrusive_iterator_base.hpp"
1617
#include "melon/detail/map_if.hpp"
1718
#include "melon/detail/prefetch.hpp"
@@ -325,7 +326,7 @@ class bidirectional_dijkstra {
325326
requires(_Traits::store_path)
326327
{
327328
assert(path_found());
328-
return std::ranges::views::concat(
329+
return detail::views::concat(
329330
std::ranges::subrange(
330331
forward_path_iterator(
331332
this, _forward_pred_arcs_map[_midpoint.value()]),
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
#ifndef MELON_DETAIL_CONCAT_VIEW_HPP
2+
#define MELON_DETAIL_CONCAT_VIEW_HPP
3+
4+
#include <concepts>
5+
#include <iterator>
6+
#include <ranges>
7+
#include <type_traits>
8+
#include <utility>
9+
10+
namespace fhamonic {
11+
namespace melon {
12+
namespace detail {
13+
namespace views {
14+
15+
#if defined(__cpp_lib_ranges_concat)
16+
17+
inline constexpr auto concat = std::views::concat;
18+
19+
#else
20+
21+
template <typename V1, typename V2>
22+
concept concat_view_compatible =
23+
std::ranges::view<V1> && std::ranges::view<V2> &&
24+
std::ranges::input_range<V1> && std::ranges::input_range<V2> &&
25+
std::common_reference_with<std::ranges::range_reference_t<V1>,
26+
std::ranges::range_reference_t<V2> > &&
27+
std::common_reference_with<std::ranges::range_reference_t<V1>,
28+
std::ranges::range_value_t<V2> &> &&
29+
std::common_reference_with<std::ranges::range_reference_t<V2>,
30+
std::ranges::range_value_t<V1> &>;
31+
32+
template <std::ranges::view V1, std::ranges::view V2>
33+
requires concat_view_compatible<V1, V2>
34+
class concat_view : public std::ranges::view_interface<concat_view<V1, V2> > {
35+
private:
36+
V1 _first;
37+
V2 _second;
38+
39+
template <bool Const>
40+
using base_t = std::conditional_t<Const, const concat_view<V1, V2>,
41+
concat_view<V1, V2> >;
42+
43+
template <bool Const>
44+
class iterator {
45+
using Parent = base_t<Const>;
46+
using FirstBase = std::conditional_t<Const, const V1, V1>;
47+
using SecondBase = std::conditional_t<Const, const V2, V2>;
48+
49+
std::ranges::iterator_t<FirstBase> _first_it{};
50+
std::ranges::sentinel_t<FirstBase> _first_end{};
51+
std::ranges::iterator_t<SecondBase> _second_it{};
52+
std::ranges::sentinel_t<SecondBase> _second_end{};
53+
bool _in_first = true;
54+
55+
void satisfy() {
56+
if(_in_first && _first_it == _first_end) _in_first = false;
57+
}
58+
59+
public:
60+
using iterator_concept = std::input_iterator_tag;
61+
using iterator_category = std::input_iterator_tag;
62+
using difference_type = std::ptrdiff_t;
63+
using value_type =
64+
std::common_type_t<std::ranges::range_value_t<FirstBase>,
65+
std::ranges::range_value_t<SecondBase> >;
66+
using reference = std::common_reference_t<
67+
std::ranges::range_reference_t<FirstBase>,
68+
std::ranges::range_reference_t<SecondBase> >;
69+
70+
iterator() = default;
71+
72+
iterator(Parent & parent)
73+
: _first_it(std::ranges::begin(parent._first))
74+
, _first_end(std::ranges::end(parent._first))
75+
, _second_it(std::ranges::begin(parent._second))
76+
, _second_end(std::ranges::end(parent._second)) {
77+
satisfy();
78+
}
79+
80+
reference operator*() const {
81+
return _in_first ? *_first_it : *_second_it;
82+
}
83+
84+
iterator & operator++() {
85+
if(_in_first) {
86+
++_first_it;
87+
satisfy();
88+
} else {
89+
++_second_it;
90+
}
91+
return *this;
92+
}
93+
94+
void operator++(int) { ++(*this); }
95+
96+
friend bool operator==(const iterator & it,
97+
std::default_sentinel_t) noexcept {
98+
if(it._in_first) return false;
99+
return it._second_it == it._second_end;
100+
}
101+
};
102+
103+
public:
104+
concat_view()
105+
requires std::default_initializable<V1> &&
106+
std::default_initializable<V2>
107+
= default;
108+
109+
constexpr concat_view(V1 first, V2 second)
110+
: _first(std::move(first)), _second(std::move(second)) {}
111+
112+
constexpr auto begin() { return iterator<false>(*this); }
113+
114+
constexpr auto begin() const
115+
requires std::ranges::range<const V1> && std::ranges::range<const V2>
116+
{
117+
return iterator<true>(*this);
118+
}
119+
120+
constexpr auto end() const noexcept { return std::default_sentinel; }
121+
constexpr auto end() noexcept { return std::default_sentinel; }
122+
};
123+
124+
template <std::ranges::viewable_range R1, std::ranges::viewable_range R2>
125+
concat_view(std::views::all_t<R1>, std::views::all_t<R2>)
126+
-> concat_view<std::views::all_t<R1>, std::views::all_t<R2> >;
127+
128+
struct concat_fn {
129+
template <std::ranges::viewable_range R1, std::ranges::viewable_range R2>
130+
requires concat_view_compatible<std::views::all_t<R1>,
131+
std::views::all_t<R2> >
132+
constexpr auto operator()(R1 && r1, R2 && r2) const {
133+
return concat_view(std::views::all(std::forward<R1>(r1)),
134+
std::views::all(std::forward<R2>(r2)));
135+
}
136+
};
137+
138+
inline constexpr concat_fn concat{};
139+
140+
#endif
141+
142+
} // namespace views
143+
} // namespace detail
144+
} // namespace melon
145+
} // namespace fhamonic
146+
147+
#endif // MELON_DETAIL_CONCAT_VIEW_HPP

include/melon/views/complete_digraph.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <ranges>
66

77
#include "melon/container/static_map.hpp"
8+
#include "melon/detail/concat_view.hpp"
89
#include "melon/mapping.hpp"
910
#include "melon/views/graph_view.hpp"
1011

@@ -122,7 +123,7 @@ class complete_digraph : public graph_view_base {
122123
[[nodiscard]] constexpr auto in_arcs(const vertex u) const noexcept {
123124
assert(u < _num_vertices);
124125
const auto increment = static_cast<arc>(_num_vertices - 1);
125-
return std::views::concat(
126+
return detail::views::concat(
126127
std::ranges::subrange(
127128
custom_iota_iterator(static_cast<arc>(u - 1),
128129
static_cast<arc>(u) * increment,

include/melon/views/undirect.hpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <algorithm>
55
#include <ranges>
66

7+
#include "melon/detail/concat_view.hpp"
78
#include "melon/graph.hpp"
89
#include "melon/views/graph_view.hpp"
910

@@ -61,7 +62,7 @@ class undirect : public undirected_graph_view_base {
6162
requires outward_incidence_graph<_Graph> &&
6263
inward_incidence_graph<_Graph>
6364
{
64-
return std::views::concat(
65+
return detail::views::concat(
6566
std::views::transform(melon::out_arcs(_graph, u),
6667
[&](auto && a) -> std::pair<edge, vertex> {
6768
return {a, melon::arc_target(_graph, a)};
@@ -77,8 +78,8 @@ class undirect : public undirected_graph_view_base {
7778
requires outward_adjacency_graph<_Graph> &&
7879
inward_adjacency_graph<_Graph>
7980
{
80-
return std::views::concat(melon::out_neighbors(_graph, u),
81-
melon::in_neighbors(_graph, u));
81+
return detail::views::concat(melon::out_neighbors(_graph, u),
82+
melon::in_neighbors(_graph, u));
8283
}
8384

8485
template <typename T>

test/CMakeLists.txt

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,31 @@ include(CompilerWarnings)
1111
# ################### Packages ###################
1212
find_package(GTest)
1313
# find_package(mp++ REQUIRED)
14+
if(NOT GTest_FOUND)
15+
if(MELON_FROM_CONAN)
16+
message(
17+
FATAL_ERROR
18+
"GTest must be provided by Conan when MELON_FROM_CONAN is enabled.")
19+
endif()
20+
message(STATUS "GTest not found in registry. Fetching with FetchContent...")
21+
include(FetchContent)
22+
FetchContent_Declare(
23+
googletest
24+
URL https://github.com/google/googletest/archive/refs/tags/v1.14.0.zip
25+
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
26+
)
27+
FetchContent_MakeAvailable(googletest)
28+
endif()
1429

1530
include(GoogleTest)
1631

1732
# ################### Library ####################
18-
add_library(melon INTERFACE)
19-
target_include_directories(
20-
melon INTERFACE $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/../include>
21-
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
33+
if(NOT TARGET melon)
34+
add_library(melon INTERFACE)
35+
target_include_directories(
36+
melon INTERFACE $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/../include>
37+
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
38+
endif()
2239
# target_link_libraries(melon INTERFACE mp++::mp++)
2340

2441
set_project_warnings(melon)
@@ -81,6 +98,4 @@ if(NOT "${LIBASAN_PATH}" STREQUAL "libasan.so")
8198
target_compile_options(melon_test PRIVATE -fsanitize=address)
8299
target_link_options(melon_test PRIVATE -fsanitize=address -lpthread)
83100
target_link_libraries(melon_test "${LIBASAN_PATH}")
84-
endif()
85-
86-
101+
endif()

0 commit comments

Comments
 (0)