{"id":16073284,"url":"https://github.com/justusc/deferral","last_synced_at":"2025-04-11T05:41:49.321Z","repository":{"id":235576490,"uuid":"785287312","full_name":"justusc/deferral","owner":"justusc","description":"A header only library that implements the defer command in C++.","archived":false,"fork":false,"pushed_at":"2025-01-05T23:59:02.000Z","size":19,"stargazers_count":2,"open_issues_count":1,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-25T03:41:38.236Z","etag":null,"topics":["c-plus-plus","c-plus-plus-11","c-plus-plus-14","c-plus-plus-17","c-plus-plus-20","defer","header-only","modern-cpp","no-dependencies","scope-exit","scope-guard","single-file-library"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/justusc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-04-11T15:24:46.000Z","updated_at":"2025-01-05T23:59:05.000Z","dependencies_parsed_at":"2024-04-23T22:26:43.462Z","dependency_job_id":"811dee85-5d1a-4208-92ce-e0014ffc4087","html_url":"https://github.com/justusc/deferral","commit_stats":null,"previous_names":["justusc/deferral"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/justusc%2Fdeferral","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/justusc%2Fdeferral/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/justusc%2Fdeferral/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/justusc%2Fdeferral/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/justusc","download_url":"https://codeload.github.com/justusc/deferral/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248351303,"owners_count":21089268,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c-plus-plus","c-plus-plus-11","c-plus-plus-14","c-plus-plus-17","c-plus-plus-20","defer","header-only","modern-cpp","no-dependencies","scope-exit","scope-guard","single-file-library"],"created_at":"2024-10-09T08:05:47.179Z","updated_at":"2025-04-11T05:41:49.297Z","avatar_url":"https://github.com/justusc.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Deferral Library for C++\n\nDeferral is a modern C++ library that provides a scope-exit API, inspired by the `defer` statement found in languages like [Go](https://go.dev/blog/defer-panic-and-recover) and [Swift](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/statements/#Defer-Statement), as well as [ScopeGurad](https://youtu.be/WjTrfoiB0MQ) and [`scope_exit` TR v3](https://cplusplus.github.io/fundamentals-ts/v3.html#scopeguard). It enables developers to ensure that specific blocks of code are executed when the current scope ends, either successfully or due to an error, enhancing the management of resource cleanup and exception safety.\n\nWhile there are numerous implementations already available, Deferral aims to include many of the unique features from other scope guard packages. It also includes a few minor performance improvements. Finally, it provides a `defer` macro to match the syntax of Go and Swift.\n\nScope guard / scope exit has been implemented many times. See the links below for various implementations.\n\n 1. [`scope_exit` reference implementation](https://github.com/PeterSommerlad/SC22WG21_Papers/tree/master/workspace/P0052_scope_exit)\n 2. [ScopeGuard in Folly](https://github.com/facebook/folly/blob/main/folly/ScopeGuard.h).\n 3. [Boost.ScopeExit](https://www.boost.org/doc/libs/1_82_0/libs/scope_exit/doc/html/index.html) \n 4. [Other examples](https://github.com/topics/scope-guard)\n\n# How to Use the Library\n\n## Requirements\n\nDeferral's only requirement is a C++11 compatible compiler.\n\n## Incorporating Deferral in your project\n\nTo integrate Deferral into your C++ projects, may choose include the header files from the `/include` directory in your project. Ensure your compiler supports C++11 or later, as this library utilizes modern C++ features and deduction guides for template type inference.\n\n1. Copy the deferral.hh file into your project.\n2. Add the Deferral repo as a submodule or subtree to your project.\n3. CMake `find_package(deferral)`, if deferral is installed on the system\n\n\nDeferral offers three main components: `DeferExit`, `DeferFail`, and `DeferSuccess`. Each of these can be used to execute code at the end of a scope depending on the exit condition:\n- **DeferExit**: Executes code unconditionally at the end of a scope.\n- **DeferFail**: Executes code only if the scope exits due to an exception.\n- **DeferSuccess**: Executes code only if the scope exits without throwing any exception.\n\nYou can also use the `defer`, `defer_fail`, and `defer_success` macros for ease of use, which mimic the `defer` keyword from Go and Swift.\n\n## Usage Examples\n\nDeferral provides four different interfaces:\n - the macros\n - factory functions\n - class constructor (C++17 and later)\nThe macros provide the most concise API and are the recommended interface. The macros closely resemble\nthe syntax of `defer` in other languages and keep the code clean.\n\n### Basic Usage\n\nThe simplest usage of Deferral is to unconditionally execute a block of code on scope exit. Below are examples of using each of Deferral interfaces to automatically close an opened file. \n\n1. `defer` keyword-like macro\n   ```cpp\n   #include \"deferral.hh\"\n   \n   void exampleFunction() {\n     FILE* file = fopen(\"example.txt\", \"w\");\n     if (!file) return;\n     \n     defer { fclose(file); }; // Ensure file is closed at the end of the scope\n     \n     // Your code here, e.g., writing to the file\n   }\n   ```\n\n2. `DEFER` macro\n   ```cpp\n   #include \"deferral.hh\"\n   \n   void exampleFunction() {\n     FILE* file = fopen(\"example.txt\", \"w\");\n     if (!file) return;\n     \n     DEFER { fclose(file); }; // Ensure file is closed at the end of the scope\n     \n     // Your code here, e.g., writing to the file\n   }\n   ```\n\n3. `make_defer_exit` factory function\n   ```cpp\n   #include \"deferral.hh\"\n   \n   void exampleFunction() {\n     FILE* file = fopen(\"example.txt\", \"w\");\n     if (!file) return;\n     \n     auto d = deferral::make_defer_exit{[\u0026]() { fclose(file); }}; // Ensure file is closed at the end of the scope\n     \n     // Your code here, e.g., writing to the file\n   }\n   ```\n\n4. `DeferExit` class with template deduction guide (C++17 only)\n   ```cpp\n   #include \"deferral.hh\"\n   \n   void exampleFunction() {\n     FILE* file = fopen(\"example.txt\", \"w\");\n     if (!file) return;\n     \n     auto d = deferral::DeferExit{[\u0026]() { fclose(file); }}; // Ensure file is closed at the end of the scope\n     \n     // Your code here, e.g., writing to the file\n   }\n   ```\n\n### Conditional Execution On Exception / No Exception\n\nDeferral includes success and failure scope guards that conditionally execute the deferred function\nif an exception is or is not thrown respectively. That is, `defer_success` operation are executed\niif the the scope exits without an exception being thrown. `defer_fail` is the opposite, in a sense,\nto `defer_success`, where the operation is only executed when the scope exits due to an unhandled\nexception.\n\n```cpp\n#include \"deferral.hh\"\n\nvoid conditionalExample() {\n    try {\n        defer_success { std::cout \u003c\u003c \"No exceptions thrown.\\n\"; };\n        defer_fail { std::cout \u003c\u003c \"An exception was thrown.\\n\"; };\n\n        // Code that might throw ...\n    } catch (...) {\n        // fail deferral IS executed on throw ...\n        // success deferral is NOT executed on throw ...\n\n        throw;\n    }\n\n    // Success deferral is executed on normal return, \n    // and failure deferral is NOT executed\n}\n```\n\n## User Disabled Defer Functions\n\nDeferral provides the `release()` function to disable the deferred operation. To use this\nfeature, the deferral object must have a named variable that can be referrenced in the function.\nThis can be done with any of the following APIs:\n  - on exit: `defer_(x)`, `DEFER_(x)`, `deferral::make_defer_exit()`, `DeferExit{}`\n  - on success: `defer_success_(x)`, `DEFER_SUCCESS_(x)`, `deferral::make_defer_exit()`, `DeferExit{}`\n  - on failure: `defer_fail_(x)`, `DEFER_FAIL_(x)`, `deferral::make_defer_fail()`, `DeferFail{}`\n\nThe `defer_(success_|fail_|)_` and `DEFER_(SUCCESS_|FAIL_|)_` marcros create a variable with the\nname give agrument.\n\n```cpp\n#include \"deferral.hh\"\n\nstd::byte* exampleFunction(int n) {\n    std::byte* buf = new std::byte[n];\n\n    // Ensure buf is cleaned up on early exit\n    defer_(d) { delete [] buf; }; // Create variable `d`.\n    \n    // Perform some initialization that might fail.\n\n    d.release(); // buf is not deleted after this point\n    return buf;\n}\n```\n\nThe factory functions can be used to achive the same result.\n\n  - `deferral::make_defer_exit()`\n  - `deferral::make_defer_fail()`\n  - `deferral::make_defer_success()`\n\n```cpp\n#include \"deferral.hh\"\n\nstd::byte* exampleFunction(int n) {\n    std::byte* buf = new std::byte[n];\n\n    // Ensure buf is cleaned up on early exit\n    auto d = deferral::make_defer_exit([\u0026]() { delete [] buf; });\n    \n    // Perform some initialization that might fail.\n\n    d.release(); // buf is not deleted after this point\n    return buf;\n}\n```\n\nIf you are using the c++17 standard, or later, you can use the class classes directly with the\n\n```cpp\n#include \"deferral.hh\"\n\nstd::byte* exampleFunction(int n) {\n    std::byte* buf = new std::byte[n];\n\n    // Ensure buf is cleaned up on early exit\n    auto d = deferral::DeferExit{[\u0026]() { delete [] buf; }}; // C++17 or later\n    \n    // Perform some initialization that might fail.\n\n    d.release(); // buf is not deleted after this point\n    return buf;\n}\n```\n\n## Disable Macros and Keywords\n\nYou can disable macro generation in the code using the following macro definitions either as command line arguments or in-file macro definitions.\n\n### Disable Macros and Keywords\n\n1. Compiler command \n   ```shell\n   $ c++ -DDEFERRAL_NO_MACROS=1 ...\n   ```\n2. In file\n   ```c++\n   #define DEFERRAL_NO_MACROS 1\n   #include \u003cdeferral.hh\u003e\n   ```\n\n### Disable keywords\n1. Compiler command\n   ```shell\n   $ c++ -DDEFERRAL_NO_KEYWORDS=1 ...\n   ```\n2. In file\n   ```c++\n   #define DEFERRAL_NO_KEYWORDS 1\n   #include \u003cdeferral.hh\u003e\n   ```\n   \n# API Overview\n\n```c++\nnamespace deferral {\n\ntemplate \u003ctypename EF\u003e\nclass DeferExit {\n\n  template \u003ctypename F\u003e\n  explicit DeferExit(F\u0026\u0026 f) noexcept(...);\n  DeferExit(DeferExit\u0026\u0026 other) noexcept(...);\n  DeferExit(const DeferExit\u0026) = delete;\n\n  ~DeferExit() noexcept(...);\n\n  DeferExit\u0026 operator=(const DeferExit\u0026) = delete;\n  DeferExit\u0026 operator=(DeferExit\u0026\u0026) = delete;\n\n  void release() noexcept;\n}; // class DeferExit\n\n\ntemplate \u003ctypename EF\u003e\nclass DeferFail {\n\n  template \u003ctypename F\u003e\n  explicit DeferFail(F\u0026\u0026 f) noexcept(...);\n  DeferFail(DeferFail\u0026\u0026 other) noexcept(...);\n  DeferFail(const DeferFail\u0026) = delete;\n\n  ~DeferFail() noexcept;\n\n  DeferFail\u0026 operator=(const DeferFail\u0026) = delete;\n  DeferFail\u0026 operator=(DeferFail\u0026\u0026) = delete;\n\n  void release() noexcept;\n}; // class DeferFail\n\n\ntemplate \u003ctypename EF\u003e\nclass DeferSuccess {\n\n  template \u003ctypename F\u003e\n  explicit DeferSuccess(F\u0026\u0026 f) noexcept(...);\n  DeferSuccess(DeferSuccess\u0026\u0026 other) noexcept(...);\n  DeferSuccess(const DeferSuccess\u0026) = delete;\n\n  ~DeferSuccess() noexcept;\n\n  DeferSuccess\u0026 operator=(const DeferSuccess\u0026) = delete;\n  DeferSuccess\u0026 operator=(DeferSuccess\u0026\u0026) = delete;\n\n  void release() noexcept;\n}; // class DeferSuccess\n\n\n// Deduction guide, C++17 only.\n#if __cplusplus \u003e= 201703L\n\ntemplate \u003ctypename funcT\u003e\nDeferExit(funcT) -\u003e DeferExit\u003cfuncT\u003e;\n\ntemplate \u003ctypename funcT\u003e\nDeferFail(funcT) -\u003e DeferFail\u003cfuncT\u003e;\n\ntemplate \u003ctypename funcT\u003e\nDeferSuccess(funcT) -\u003e DeferSuccess\u003cfuncT\u003e;\n\n#endif\n\ntemplate \u003ctypename funcT\u003e\nDEFERRAL_VISIBILITY_HIDDEN inline DeferExit\u003ctypename std::decay\u003cfuncT\u003e::type\u003e\nmake_defer_exit(funcT\u0026\u0026 f) noexcept(...);\n\ntemplate \u003ctypename funcT\u003e\ninline DeferFail\u003ctypename std::decay\u003cfuncT\u003e::type\u003e\nmake_defer_fail(funcT\u0026\u0026 f) noexcept(...);\n\ntemplate \u003ctypename funcT\u003e\ninline DeferSuccess\u003ctypename std::decay\u003cfuncT\u003e::type\u003e\nmake_defer_success(funcT\u0026\u0026 f) noexcept(...);\n\n} // namespace deferral\n\n\n#if !defined(DEFERRAL_NO_MACROS)\n\n// Macros defining the primary API\n#define DEFER                        ...\n#define DEFER_(variable_name)        ...\n#define DEFER_FAIL                   ...\n#define DEFER_FAIL_(variable_name)   ...\n#define DEFER_SUCCESS                ...\n#define DEFER_SUCCESS(variable_name) ...\n\n\n#if !defined(DEFERRAL_NO_KEYWORDS)\n\n// Define macros that simulate key words\n#define defer_(variable_name)          DEFER_(variable_name)\n#define defer                          DEFER\n#define defer_fail_(variable_name)     DEFER_FAIL_(xvariable_name)\n#define defer_fail                     DEFER_FAIL\n#define defer_success_(variable_name)  DEFER_SUCCESS_(variable_name)\n#define defer_success                  DEFER_SUCCESS\n\n#endif\n\n#endif\n\n```\n\n# Contributing\n\nWe welcome contributions to the Deferral library! Whether it's bug reports, feature requests, or pull requests, your help is valuable to us. Please feel free to contribute to making this library even better.\n\n# License\n\nThis library is distributed under the MIT License. Feel free to use it in your projects as you see fit.\n\n\u003e MIT License\n\u003e\n\u003e Copyright (c) 2024 Justus Calvin\n\u003e \n\u003e Permission is hereby granted, free of charge, to any person obtaining a copy\n\u003e of this software and associated documentation files (the \"Software\"), to deal\n\u003e in the Software without restriction, including without limitation the rights\n\u003e to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n\u003e copies of the Software, and to permit persons to whom the Software is\n\u003e furnished to do so, subject to the following conditions:\n\u003e \n\u003e The above copyright notice and this permission notice shall be included in all\n\u003e copies or substantial portions of the Software.\n\u003e \n\u003e THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n\u003e IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n\u003e FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n\u003e AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n\u003e LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n\u003e OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n\u003e SOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjustusc%2Fdeferral","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjustusc%2Fdeferral","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjustusc%2Fdeferral/lists"}