Skip to content

Commit b398f28

Browse files
authored
merge develop
2 parents 7692078 + 617c12e commit b398f28

16 files changed

+541
-9
lines changed
Binary file not shown.
Binary file not shown.

.github/workflows/code_testing.yaml

+4-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ jobs:
1616
compiler: clang-17
1717
- os: ubuntu-22.04
1818
compiler: clang-18
19+
- os: ubuntu-22.04
20+
compiler: clang-19
1921

2022
- os: ubuntu-22.04
2123
compiler: gcc-12
@@ -45,15 +47,15 @@ jobs:
4547
- name: Configure conan
4648
uses: dice-group/cpp-conan-release-reusable-workflow/.github/actions/configure_conan@main
4749
with:
48-
conan-version: 2.3.1
50+
conan-version: 2.12.2
4951

5052
- name: add conan user
5153
run: |
5254
conan remote add -f dice-group https://conan.dice-research.org/artifactory/api/conan/tentris
5355
5456
- name: Cache conan data
5557
id: cache-conan
56-
uses: actions/cache@v4.0.2
58+
uses: actions/cache@v4
5759
with:
5860
path: ~/.conan2/p
5961
key: ${{ matrix.config.os }}-${{ matrix.config.compiler }}

.github/workflows/detect-pobr-diff.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ jobs:
1111
uses: dice-group/cpp-conan-release-reusable-workflow/.github/workflows/abi-diff.yml@main
1212
with:
1313
os: ubuntu-22.04
14-
compiler: clang-16
14+
compiler: clang-17
1515
cmake-version: 3.24.0
16-
conan-version: 2.3.1
16+
conan-version: 2.12.2
1717
base-branch: ${{ github.base_ref }}
1818
search-path: >
1919
include/dice/template-library/flex_array.hpp

.github/workflows/publish-conan-branch-package.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ jobs:
1212
with:
1313
public_artifactory: true
1414
os: ubuntu-22.04
15-
compiler: clang-18
15+
compiler: clang-17
1616
cmake-version: 3.24.0
17-
conan-version: 2.3.1
17+
conan-version: 2.12.2
1818
secrets:
1919
CONAN_USER: ${{ secrets.CONAN_USER }}
2020
CONAN_PW: ${{ secrets.CONAN_PW }}

.github/workflows/publish-release.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ jobs:
1717
with:
1818
public_artifactory: true
1919
os: ubuntu-22.04
20-
compiler: clang-14
20+
compiler: clang-17
2121
cmake-version: 3.24.0
22-
conan-version: 2.3.0
22+
conan-version: 2.12.2
2323
secrets:
2424
CONAN_USER: ${{ secrets.CONAN_USER }}
2525
CONAN_PW: ${{ secrets.CONAN_PW }}

CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.24)
22

33
project(
44
dice-template-library
5-
VERSION 1.10.1
5+
VERSION 1.11.0
66
DESCRIPTION
77
"This template library is a collection of template-oriented code that we, the Data Science Group at UPB, found pretty handy. It contains: `switch_cases` (Use runtime values in compile-time context), `integral_template_tuple` (Create a tuple-like structure that instantiates a template for a range of values), `integral_template_variant` (A wrapper type for `std::variant` guarantees to only contain variants of the form `T<IX>` and `for_{types,values,range}` (Compile time for loops for types, values or ranges))."
88
HOMEPAGE_URL "https://dice-research.org/")

README.md

+6
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ It contains:
1818
- `generator`: The reference implementation of `std::generator` from [P2502R2](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2502r2.pdf)
1919
- `channel`: A single producer, single consumer queue
2020
- `variant2`: Like `std::variant` but optimized for exactly two types
21+
- `mutex`/`shared_mutex`: Rust inspired mutex interfaces that hold their data instead of living next to it
2122

2223
## Usage
2324

@@ -107,6 +108,11 @@ Additionally, `visit` does not involve any virtual function calls.
107108
### `type_traits.hpp`
108109
Things that are missing in the standard library `<type_traits>` header.
109110

111+
### `mutex`/`shared_mutex`
112+
Rust inspired mutex interfaces that hold their data instead of living next to it.
113+
The benefit of this approach is that it makes it harder (impossible in rust) to access the
114+
data without holding the mutex.
115+
110116
### Further Examples
111117

112118
Compilable code examples can be found in [examples](./examples). The example build requires the cmake

examples/CMakeLists.txt

+16
Original file line numberDiff line numberDiff line change
@@ -93,3 +93,19 @@ target_link_libraries(example_pool_allocator
9393
PRIVATE
9494
dice-template-library::dice-template-library
9595
)
96+
97+
98+
add_executable(example_mutex
99+
example_mutex.cpp)
100+
target_link_libraries(example_mutex
101+
PRIVATE
102+
dice-template-library::dice-template-library
103+
)
104+
105+
add_executable(example_shared_mutex
106+
example_shared_mutex.cpp)
107+
target_link_libraries(example_shared_mutex
108+
PRIVATE
109+
dice-template-library::dice-template-library
110+
)
111+

examples/example_mutex.cpp

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#include <dice/template-library/mutex.hpp>
2+
3+
#include <cassert>
4+
#include <thread>
5+
6+
int main() {
7+
dice::template_library::mutex<int> mut{0};
8+
9+
std::thread thrd{[&]() {
10+
*mut.lock() = 5;
11+
}};
12+
13+
thrd.join();
14+
assert(*mut.lock() == 5);
15+
}

examples/example_shared_mutex.cpp

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#include <dice/template-library/shared_mutex.hpp>
2+
3+
#include <cassert>
4+
#include <thread>
5+
6+
int main() {
7+
dice::template_library::shared_mutex<int> mut{0};
8+
9+
std::thread thrd1{[&]() {
10+
*mut.lock() = 5;
11+
}};
12+
13+
thrd1.join();
14+
15+
std::thread thrd2{[&]() {
16+
assert(*mut.lock_shared() == 5);
17+
}};
18+
19+
thrd2.join();
20+
21+
assert(*mut.lock() == 5);
22+
}
+134
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
#ifndef DICE_TEMPLATELIBRARY_MUTEX_HPP
2+
#define DICE_TEMPLATELIBRARY_MUTEX_HPP
3+
4+
#include <mutex>
5+
#include <optional>
6+
#include <type_traits>
7+
#include <utility>
8+
9+
namespace dice::template_library {
10+
11+
template<typename T, typename Mutex = std::mutex>
12+
struct mutex;
13+
14+
/**
15+
* An RAII guard for a value behind a mutex.
16+
* When this mutex_guard is dropped the lock is automatically released.
17+
*
18+
* @note to use this correctly it is important to understand that unlike rust, C++ cannot
19+
* enforce that you do not use pointers given out by this type beyond its lifetime.
20+
* You may not store pointers or references given out via this wrapper beyond its lifetime, otherwise behaviour is undefined.
21+
*
22+
* @tparam T the value type protected by the mutex
23+
* @tparam Mutex the mutex type
24+
*/
25+
template<typename T, typename Mutex = std::mutex>
26+
struct mutex_guard {
27+
using value_type = T;
28+
using mutex_type = Mutex;
29+
30+
private:
31+
friend struct mutex<T, Mutex>;
32+
33+
value_type *value_ptr_;
34+
std::unique_lock<mutex_type> lock_;
35+
36+
mutex_guard(std::unique_lock<mutex_type> &&lock, T &value) noexcept
37+
: value_ptr_{&value},
38+
lock_{std::move(lock)} {
39+
}
40+
41+
public:
42+
mutex_guard() = delete;
43+
mutex_guard(mutex_guard const &other) noexcept = delete;
44+
mutex_guard &operator=(mutex_guard const &other) noexcept = delete;
45+
mutex_guard(mutex_guard &&other) noexcept = default;
46+
mutex_guard &operator=(mutex_guard &&other) noexcept = default;
47+
~mutex_guard() = default;
48+
49+
value_type *operator->() const noexcept {
50+
return value_ptr_;
51+
}
52+
53+
value_type &operator*() const noexcept {
54+
return *value_ptr_;
55+
}
56+
57+
friend void swap(mutex_guard const &lhs, mutex_guard const &rhs) noexcept {
58+
using std::swap;
59+
swap(lhs.value_ptr_, rhs.value_ptr_);
60+
swap(lhs.lock_, rhs.lock_);
61+
}
62+
};
63+
64+
/**
65+
* A rust-like mutex type (https://doc.rust-lang.org/std/sync/struct.Mutex.html) that holds its data instead of living next to it.
66+
*
67+
* @note Because this is C++ it cannot be fully safe, like the rust version is, for more details see doc comment on mutex_guard.
68+
* @note This type is non-movable and non-copyable, if you need to do either of these things use `std::unique_ptr<mutex<T>>` or `std::shared_ptr<mutex<T>>`
69+
*
70+
* @tparam T value type stored
71+
* @tparam Mutex the mutex type
72+
*/
73+
template<typename T, typename Mutex>
74+
struct mutex {
75+
using value_type = T;
76+
using mutex_type = Mutex;
77+
78+
private:
79+
value_type value_;
80+
mutex_type mutex_;
81+
82+
public:
83+
constexpr mutex() noexcept(std::is_nothrow_default_constructible_v<value_type>) = default;
84+
constexpr ~mutex() noexcept(std::is_nothrow_destructible_v<value_type>) = default;
85+
86+
mutex(mutex const &other) = delete;
87+
mutex(mutex &&other) = delete;
88+
mutex &operator=(mutex const &other) = delete;
89+
mutex &operator=(mutex &&other) = delete;
90+
91+
explicit constexpr mutex(value_type const &value) noexcept(std::is_nothrow_copy_constructible_v<value_type>)
92+
: value_{value} {
93+
}
94+
95+
explicit constexpr mutex(value_type &&value) noexcept(std::is_nothrow_move_constructible_v<value_type>)
96+
: value_{std::move(value)} {
97+
}
98+
99+
template<typename ...Args>
100+
explicit constexpr mutex(std::in_place_t, Args &&...args) noexcept(std::is_nothrow_constructible_v<value_type, decltype(std::forward<Args>(args))...>)
101+
: value_{std::forward<Args>(args)...} {
102+
}
103+
104+
/**
105+
* Lock the mutex and return a guard that will keep it locked until it goes out of scope and
106+
* allows access to the inner value.
107+
*
108+
* @return mutex guard for the inner value
109+
* @throws std::system_error in case the underlying mutex implementation throws it
110+
*/
111+
[[nodiscard]] mutex_guard<value_type> lock() {
112+
return mutex_guard<value_type>{std::unique_lock<mutex_type>{mutex_}, value_};
113+
}
114+
115+
/**
116+
* Attempt to lock the mutex and return a guard that will keep it locked until it goes out of scope and
117+
* allows access to the inner value.
118+
*
119+
* @return nullopt in case the mutex could not be locked, otherwise a mutex guard for the inner value
120+
* @throws std::system_error in case the underlying mutex implementation throws it
121+
*/
122+
[[nodiscard]] std::optional<mutex_guard<value_type>> try_lock() {
123+
std::unique_lock<mutex_type> lock{mutex_, std::try_to_lock};
124+
if (!lock.owns_lock()) {
125+
return std::nullopt;
126+
}
127+
128+
return mutex_guard<value_type>{std::move(lock), value_};
129+
}
130+
};
131+
132+
} // namespace dice::template_library
133+
134+
#endif // DICE_TEMPLATELIBRARY_MUTEX_HPP

0 commit comments

Comments
 (0)