Skip to content

Commit ed36910

Browse files
committed
feat: move to C++23
1 parent 67fc7b2 commit ed36910

12 files changed

+134
-114
lines changed

.clang-format

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
---
22
Language: Cpp
3+
InsertNewlineAtEOF: true
34
AccessModifierOffset: -2
45
AlignAfterOpenBracket: Align
56
AlignConsecutiveMacros: false
6-
AlignConsecutiveAssignments: false
7+
AlignConsecutiveAssignments:
8+
Enabled: true
9+
AcrossComments: false
10+
AcrossEmptyLines: false
711
AlignConsecutiveDeclarations: false
812
AlignEscapedNewlines: Right
913
AlignOperands: true

CMakeLists.txt

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
cmake_minimum_required(VERSION 3.16)
2-
project(lockpp LANGUAGES CXX VERSION 2.7)
2+
project(lockpp LANGUAGES CXX VERSION 3.0)
33

44
# --------------------------------------------------------------------------------------------------------
55
# Library options
@@ -14,8 +14,8 @@ option(lockpp_tests "Run tests" OFF)
1414
add_library(${PROJECT_NAME} INTERFACE)
1515
add_library(cr::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
1616

17-
target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_20)
18-
set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD 20 CXX_EXTENSIONS OFF CXX_STANDARD_REQUIRED ON)
17+
target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_23)
18+
set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD 23 CXX_EXTENSIONS OFF CXX_STANDARD_REQUIRED ON)
1919

2020
# --------------------------------------------------------------------------------------------------------
2121
# Include "include" folder

include/lockpp/lock.hpp

+20-29
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,50 @@
11
#pragma once
2+
23
#include "traits.hpp"
34
#include "locked.hpp"
45

5-
#include <mutex>
6-
#include <utility>
7-
#include <concepts>
8-
#include <shared_mutex>
9-
106
namespace lockpp
117
{
12-
template <typename Type, decayed Mutex = std::shared_mutex>
8+
template <typename T, typename Mutex = std::shared_mutex>
139
class lock
1410
{
1511
template <typename>
16-
using read_lock = shared_cond<Mutex, std::shared_lock, std::lock_guard>;
12+
using read_lock = mutex_traits<Mutex>::read_lock;
1713

1814
template <typename>
19-
using write_lock = shared_cond<Mutex, std::unique_lock, std::lock_guard>;
15+
using write_lock = mutex_traits<Mutex>::write_lock;
2016

2117
private:
22-
Type m_value;
18+
T m_value;
2319
mutable Mutex m_mutex;
2420

2521
public:
26-
template <typename... Args>
27-
explicit lock(Args &&...);
22+
template <typename... Ts>
23+
explicit lock(Ts &&...);
2824

2925
public:
30-
template <template <typename> class Lock = write_lock, typename... LockArgs>
31-
[[nodiscard]] locked<Type, Lock<Mutex>> write(LockArgs &&...) &;
26+
template <template <typename> class Lock = write_lock, typename... Ts>
27+
[[nodiscard]] locked<T, Lock<Mutex>> write(Ts &&...) &;
3228

3329
public:
34-
template <template <typename> class Lock = read_lock, typename... LockArgs>
35-
[[nodiscard]] locked<const Type, Lock<Mutex>> read(LockArgs &&...) const &;
36-
37-
template <template <typename> class Lock = read_lock, typename... LockArgs>
38-
[[nodiscard]] locked<const Type, Lock<Mutex>> read(LockArgs &&...) && = delete;
30+
template <template <typename> class Lock = read_lock, typename Self, typename... Ts>
31+
requires std::is_lvalue_reference_v<Self>
32+
[[nodiscard]] locked<const T, Lock<Mutex>> read(this Self &&, Ts &&...);
3933

4034
public:
4135
template <typename O>
42-
void assign(O &&value) &
43-
requires std::assignable_from<Type &, O>;
36+
requires std::assignable_from<T &, O>
37+
void assign(O &&value) &;
4438

4539
public:
46-
[[nodiscard]] Type &get_unsafe() &;
47-
[[nodiscard]] Type &get_unsafe() const &;
48-
[[nodiscard]] Type &get_unsafe() && = delete;
40+
template <typename Self>
41+
requires std::is_lvalue_reference_v<Self>
42+
[[nodiscard]] T &get_unsafe(this Self &&);
4943

5044
public:
51-
[[nodiscard]] Type copy() const &
52-
requires std::copyable<Type>;
53-
54-
[[nodiscard]] Type copy() &&
55-
requires std::copyable<Type>
56-
= delete;
45+
template <typename Self>
46+
requires std::is_lvalue_reference_v<Self> and std::copyable<T>
47+
[[nodiscard]] T copy(this Self &&);
5748
};
5849
} // namespace lockpp
5950

include/lockpp/lock.inl

+28-29
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,53 @@
11
#pragma once
2+
23
#include "lock.hpp"
34

45
namespace lockpp
56
{
6-
template <typename Type, decayed Mutex>
7-
template <typename... Args>
8-
lock<Type, Mutex>::lock(Args &&...args) : m_value(std::forward<Args>(args)...)
7+
template <typename T, typename Mutex>
8+
template <typename... Ts>
9+
lock<T, Mutex>::lock(Ts &&...args) : m_value(std::forward<Ts>(args)...)
910
{
1011
}
1112

12-
template <typename Type, decayed Mutex>
13-
template <template <typename> class Lock, typename... LockArgs>
14-
locked<Type, Lock<Mutex>> lock<Type, Mutex>::write(LockArgs &&...lock_args) &
13+
template <typename T, typename Mutex>
14+
template <template <typename> class Lock, typename... Ts>
15+
locked<T, Lock<Mutex>> lock<T, Mutex>::write(Ts &&...lock_args) &
1516
{
16-
return {&m_value, m_mutex, std::forward<LockArgs>(lock_args)...};
17+
return {&m_value, m_mutex, std::forward<Ts>(lock_args)...};
1718
}
1819

19-
template <typename Type, decayed Mutex>
20-
template <template <typename> class Lock, typename... LockArgs>
21-
locked<const Type, Lock<Mutex>> lock<Type, Mutex>::read(LockArgs &&...lock_args) const &
20+
template <typename T, typename Mutex>
21+
template <template <typename> class Lock, typename Self, typename... Ts>
22+
requires std::is_lvalue_reference_v<Self>
23+
locked<const T, Lock<Mutex>> lock<T, Mutex>::read(this Self &&self, Ts &&...lock_args)
2224
{
23-
return {&m_value, m_mutex, std::forward<LockArgs>(lock_args)...};
25+
return {&self.m_value, self.m_mutex, std::forward<Ts>(lock_args)...};
2426
}
2527

26-
template <typename Type, decayed Mutex>
27-
template <typename O>
28-
void lock<Type, Mutex>::assign(O &&value) &
29-
requires std::assignable_from<Type &, O>
28+
template <typename T, typename Mutex>
29+
template <typename O>
30+
requires std::assignable_from<T &, O>
31+
void lock<T, Mutex>::assign(O &&value) &
3032
{
3133
auto locked = write();
32-
*locked = std::forward<O>(value);
33-
}
34-
35-
template <typename Type, decayed Mutex>
36-
Type &lock<Type, Mutex>::get_unsafe() &
37-
{
38-
return m_value;
34+
*locked = std::forward<O>(value);
3935
}
4036

41-
template <typename Type, decayed Mutex>
42-
Type &lock<Type, Mutex>::get_unsafe() const &
37+
template <typename T, typename Mutex>
38+
template <typename Self>
39+
requires std::is_lvalue_reference_v<Self>
40+
T &lock<T, Mutex>::get_unsafe(this Self &&self)
4341
{
44-
return m_value;
42+
return self.m_value;
4543
}
4644

47-
template <typename Type, decayed Mutex>
48-
Type lock<Type, Mutex>::copy() const &
49-
requires std::copyable<Type>
45+
template <typename T, typename Mutex>
46+
template <typename Self>
47+
requires std::is_lvalue_reference_v<Self> and std::copyable<T>
48+
T lock<T, Mutex>::copy(this Self &&self)
5049
{
51-
auto locked = read();
50+
auto locked = self.read();
5251
return *locked;
5352
}
5453
} // namespace lockpp

include/lockpp/locked.hpp

+18-10
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,36 @@
11
#pragma once
2-
#include "traits.hpp"
2+
3+
#include <type_traits>
34

45
namespace lockpp
56
{
6-
template <typename Type, typename Lock>
7+
template <typename T, typename Lock>
78
class locked
89
{
9-
template <typename, decayed>
10+
template <typename, typename>
1011
friend class lock;
1112

1213
private:
1314
Lock m_lock;
14-
Type *m_value;
15+
T *m_value;
1516

1617
protected:
17-
template <typename... LockArgs>
18-
locked(Type *, lock_mutex_t<Lock> &, LockArgs &&...);
18+
template <typename Mutex, typename... Ts>
19+
locked(T *, Mutex &, Ts &&...);
20+
21+
public:
22+
template <typename Self>
23+
requires std::is_lvalue_reference_v<Self>
24+
[[nodiscard]] T &value(this Self &&) noexcept;
1925

2026
public:
21-
[[nodiscard]] Type &operator*() const & noexcept;
22-
[[nodiscard]] Type *operator->() const & noexcept;
27+
template <typename Self>
28+
requires std::is_lvalue_reference_v<Self>
29+
[[nodiscard]] T &operator*(this Self &&) noexcept;
2330

24-
[[nodiscard]] Type &operator*() && noexcept = delete;
25-
[[nodiscard]] Type *operator->() && noexcept = delete;
31+
template <typename Self>
32+
requires std::is_lvalue_reference_v<Self>
33+
[[nodiscard]] T *operator->(this Self &&) noexcept;
2634
};
2735
} // namespace lockpp
2836

include/lockpp/locked.inl

+23-11
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,38 @@
11
#pragma once
2-
#include "locked.hpp"
32

3+
#include "locked.hpp"
44
#include <utility>
55

66
namespace lockpp
77
{
8-
template <typename Type, class Lock>
9-
template <typename... LockArgs>
10-
locked<Type, Lock>::locked(Type *value, lock_mutex_t<Lock> &mutex, LockArgs &&...lock_args)
11-
: m_lock(mutex, std::forward<LockArgs>(lock_args)...), m_value(value)
8+
template <typename T, class Lock>
9+
template <typename Mutex, typename... Ts>
10+
locked<T, Lock>::locked(T *value, Mutex &mutex, Ts &&...lock_args)
11+
: m_lock(mutex, std::forward<Ts>(lock_args)...), m_value(value)
12+
{
13+
}
14+
15+
template <typename T, class Lock>
16+
template <typename Self>
17+
requires std::is_lvalue_reference_v<Self>
18+
[[nodiscard]] T &locked<T, Lock>::value(this Self &&self) noexcept
1219
{
20+
return *self.m_value;
1321
}
1422

15-
template <typename Type, class Lock>
16-
[[nodiscard]] Type &locked<Type, Lock>::operator*() const & noexcept
23+
template <typename T, class Lock>
24+
template <typename Self>
25+
requires std::is_lvalue_reference_v<Self>
26+
[[nodiscard]] T &locked<T, Lock>::operator*(this Self &&self) noexcept
1727
{
18-
return *m_value;
28+
return self.value();
1929
}
2030

21-
template <typename Type, class Lock>
22-
[[nodiscard]] Type *locked<Type, Lock>::operator->() const & noexcept
31+
template <typename T, class Lock>
32+
template <typename Self>
33+
requires std::is_lvalue_reference_v<Self>
34+
[[nodiscard]] T *locked<T, Lock>::operator->(this Self &&self) noexcept
2335
{
24-
return m_value;
36+
return self.m_value;
2537
}
2638
} // namespace lockpp

include/lockpp/traits.hpp

+17-17
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,27 @@
11
#pragma once
2-
#include <concepts>
3-
#include <type_traits>
2+
3+
#include <mutex>
4+
#include <shared_mutex>
45

56
namespace lockpp
67
{
78
template <typename T>
8-
concept decayed = std::same_as<T, std::decay_t<T>>;
9+
concept is_shared = requires(T &mutex) {
10+
{ mutex.lock_shared() };
11+
};
912

1013
template <typename T>
11-
concept shared_lockable = requires(T &mutex) { mutex.lock_shared(); };
12-
13-
template <decayed Mutex, template <typename> typename TrueType, template <typename> typename FalseType>
14-
using shared_cond = std::conditional_t<shared_lockable<Mutex>, TrueType<Mutex>, FalseType<Mutex>>;
15-
16-
template <typename Lock>
17-
consteval auto lock_mutex()
14+
struct mutex_traits
1815
{
19-
return []<template <typename> typename L, typename M>(L<M> *)
20-
{
21-
return std::type_identity<M>{};
22-
}(static_cast<Lock *>(nullptr));
23-
}
16+
using read_lock = std::lock_guard<T>;
17+
using write_lock = std::lock_guard<T>;
18+
};
2419

25-
template <typename Lock>
26-
using lock_mutex_t = typename decltype(lock_mutex<Lock>())::type;
20+
template <typename T>
21+
requires is_shared<T>
22+
struct mutex_traits<T>
23+
{
24+
using read_lock = std::shared_lock<T>;
25+
using write_lock = std::unique_lock<T>;
26+
};
2727
} // namespace lockpp

tests/CMakeLists.txt

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ project(lockpp-tests LANGUAGES CXX)
88
add_executable(${PROJECT_NAME})
99
add_executable(lockpp::tests ALIAS ${PROJECT_NAME})
1010

11-
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_20)
12-
set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD 20 CXX_EXTENSIONS OFF CXX_STANDARD_REQUIRED ON)
11+
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_23)
12+
set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD 23 CXX_EXTENSIONS OFF CXX_STANDARD_REQUIRED ON)
1313

1414
# --------------------------------------------------------------------------------------------------------
1515
# Add Sources
@@ -26,7 +26,7 @@ include("../cmake/cpm.cmake")
2626

2727
CPMFindPackage(
2828
NAME ut
29-
VERSION 2.0.0
29+
VERSION 2.1.0
3030
GIT_REPOSITORY "https://github.com/boost-ext/ut"
3131
OPTIONS "BOOST_UT_DISABLE_MODULE ON"
3232
)

tests/basic.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include <boost/ut.hpp>
2+
23
#include <lockpp/lock.hpp>
34

45
using namespace boost::ut;
@@ -29,18 +30,19 @@ suite<"basic"> assign_copy_suite = []()
2930
should("be readable") = [&]
3031
{
3132
auto locked = test.read();
32-
expect(*locked == "b");
3333

34+
expect(*locked == "b");
35+
expect(locked.value() == "b");
3436
expect(std::same_as<decltype(*locked), const std::string &>);
3537
};
3638

3739
should("be writable") = [&]
3840
{
3941
auto locked = test.write();
40-
4142
locked->clear();
4243

4344
expect(locked->empty());
45+
expect(locked.value().empty());
4446
expect(test.get_unsafe().empty());
4547

4648
expect(std::same_as<decltype(*locked), std::string &>);

0 commit comments

Comments
 (0)