Skip to content

Commit 594c628

Browse files
committed
feat: add unique_resource
1 parent bec9eb0 commit 594c628

File tree

8 files changed

+1123
-6
lines changed

8 files changed

+1123
-6
lines changed

.github/workflows/ci-vcpkg.yml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,6 @@ jobs:
4747
- name: Set up vcpkg
4848
uses: lukka/run-vcpkg@5e0cab206a5ea620130caf672fce3e4a6b5666a1 # v11.5
4949

50-
# - name: Fix for AppleClang
51-
# run: |
52-
# sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer
53-
# if: runner.os == 'macOS'
54-
5550
- name: Build and test
5651
run: |
5752
cmake --preset debug-vcpkg -DBUILD_DOCS=OFF -DBUILD_EXAMPLES=OFF

README.md

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@
66

77
## Overview
88

9-
This project provides a set of scope guard utilities for managing exit actions in C++. These utilities ensure that specified actions are executed when a scope is exited, regardless of how the exit occurs. The scope guards include:
9+
This project provides a set of utilities for managing exit actions and resource handling in C++. These utilities ensure that specified actions are executed when a scope is exited, regardless of (or depending on) how the exit occurs. The scope guards include:
1010

1111
- `exit_action`: Executes an action when the scope is exited.
1212
- `fail_action`: Executes an action when the scope is exited due to an exception.
1313
- `success_action`: Executes an action when the scope is exited normally.
14+
- `unique_resource`: Manages a resource through a handle and disposes of that resource upon destruction (scope exit).
1415

1516
These utilities are useful for ensuring that resources are properly released or actions are taken when a scope is exited.
1617

@@ -19,11 +20,14 @@ These utilities are useful for ensuring that resources are properly released or
1920
- **exit_action**: Calls its exit function on destruction, when a scope is exited.
2021
- **fail_action**: Calls its exit function when a scope is exited via an exception.
2122
- **success_action**: Calls its exit function when a scope is exited normally.
23+
- **unique_resource**: Manages a resource with a custom deleter, ensuring the resource is released when the scope is exited.
2224

2325
## Usage
2426

2527
### Example Usage
2628

29+
#### Scope Guards
30+
2731
```cpp
2832
#include <iostream>
2933
#include <scope_action.h>
@@ -77,6 +81,29 @@ int main()
7781
}
7882
```
7983
84+
#### `unique_resource`
85+
86+
```cpp
87+
#include <cstdio>
88+
#include <unique_resource.h>
89+
90+
int main()
91+
{
92+
auto file = wwa::utils::make_unique_resource_checked(
93+
std::fopen("potentially_nonexistent_file.txt", "r"), nullptr, std::fclose
94+
);
95+
96+
if (file.get() != nullptr) {
97+
std::puts("The file exists.\n");
98+
}
99+
else {
100+
std::puts("The file does not exist.\n");
101+
}
102+
103+
return 0;
104+
}
105+
```
106+
80107
## API Documentation
81108

82109
The documentation is available at [https://sjinks.github.io/scope-action-cpp/](https://sjinks.github.io/scope-action-cpp/).
@@ -144,6 +171,50 @@ public:
144171
};
145172
```
146173

174+
### `unique_resource`
175+
176+
A universal RAII resource handle wrapper for resource handles that owns and manages a resource through a handle and disposes of that resource upon destruction.
177+
178+
```cpp
179+
template<typename Resource, typename Deleter>
180+
class [[nodiscard]] unique_resource {
181+
public:
182+
unique_resource();
183+
184+
template<typename Res, typename Del>
185+
unique_resource(Res&& r, Del&& d) noexcept(
186+
(std::is_nothrow_constructible_v<WrappedResource, Res> || std::is_nothrow_constructible_v<WrappedResource, Res&>) &&
187+
(std::is_nothrow_constructible_v<Deleter, Del> || std::is_nothrow_constructible_v<Deleter, Del&>)
188+
);
189+
190+
unique_resource(unique_resource&& other) noexcept(std::is_nothrow_move_constructible_v<Resource> && std::is_nothrow_move_constructible_v<Deleter>);
191+
~unique_resource() noexcept;
192+
193+
unique_resource& operator=(unique_resource&& other) noexcept(
194+
std::is_nothrow_move_assignable_v<Resource> && std::is_nothrow_move_assignable_v<Deleter>
195+
)
196+
197+
void release() noexcept;
198+
void reset() noexcept;
199+
200+
template<typename Res>
201+
void reset(Res&& r);
202+
203+
const Resource& get() const noexcept;
204+
const Deleter& get_deleter() const noexcept;
205+
206+
std::add_lvalue_reference_t<std::remove_pointer_t<Resource>> operator*() const noexcept;
207+
Resource operator->() const noexcept
208+
};
209+
210+
template<typename Resource, typename Deleter, typename Invalid = std::decay_t<Resource>>
211+
unique_resource<std::decay_t<Resource>, std::decay_t<Deleter>>
212+
make_unique_resource_checked(Resource&& r, const Invalid& invalid, Deleter&& d) noexcept(
213+
std::is_nothrow_constructible_v<std::decay_t<Resource>, Resource> &&
214+
std::is_nothrow_constructible_v<std::decay_t<Deleter>, Deleter>
215+
);
216+
```
217+
147218
## Building and Testing
148219

149220
### Prerequisites

examples/.clang-tidy

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
InheritParentConfig: true
3+
Checks: >
4+
-cppcoreguidelines-owning-memory

examples/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,6 @@ set_directory_properties(PROPERTIES INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}/src
88

99
add_executable(scope_action scope_action.cpp)
1010
target_link_libraries(scope_action PRIVATE wwa::scope_action)
11+
12+
add_executable(unique_resource unique_resource.cpp)
13+
target_link_libraries(unique_resource PRIVATE wwa::scope_action)

examples/unique_resource.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#include <cstdio>
2+
3+
#ifndef _WIN32
4+
# include <sys/socket.h>
5+
# include <unistd.h>
6+
#endif
7+
8+
#include "unique_resource.h"
9+
10+
int main()
11+
{
12+
//! [Using make_unique_resource_checked()]
13+
auto file = wwa::utils::make_unique_resource_checked(
14+
std::fopen("potentially_nonexistent_file.txt", "r"), nullptr, std::fclose
15+
);
16+
17+
if (file.get() != nullptr) {
18+
std::puts("The file exists.\n");
19+
}
20+
else {
21+
std::puts("The file does not exist.\n");
22+
}
23+
//! [Using make_unique_resource_checked()]
24+
25+
#ifndef _WIN32
26+
//! [Using unique_resource]
27+
int sock = socket(AF_INET, SOCK_STREAM, 0);
28+
if (sock != -1) {
29+
wwa::utils::unique_resource sock_guard(sock, close);
30+
// Do something with the socket
31+
// The socket will be closed when `sock_guard` goes out of scope
32+
}
33+
//! [Using unique_resource]
34+
#endif
35+
36+
return 0;
37+
}

0 commit comments

Comments
 (0)