uyha / scope

A C++17 library for declarative flow control

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

scope

Build and test

A standalone C++17 header-only library for Andrei Alexandrescu's Declarative Control Flow and P0052.

This project is a fork from Peter Sommerlad's scope17 implementation with changes to make it appropriate for being a standalone library.

Build and test

cmake -B build -S .
cmake --build build
ctest --test-dir build/tests

Usage

This is a header-only so you can download scope.hpp to your project and start using it.

Features

This library provides the following 4 classes:

  • scope_exit
  • scope_fail
  • scope_success
  • unique_resource

a utility function make_unique_resource_checked, and 3 macros:

  • SCOPE_EXIT
  • SCOPE_FAIL
  • SCOPE_SUCCESS

scope_exit, scope_fail, scope_success, and SCOPE_* macros

These classes provide a way to run code when a scope ends (either by reaching the of a block or by exception) without creating RAII classes. These classes differ in when they invoke their functions.

Invoke when scope ends with exception without exception
scope_exit yes yes
scope_fail yes no
scope_success no yes

The macros provide the same functionality to their lower-case counterparts, but they also create a unique variable when they are called. This frees the user from having to create the variable with unique names manually.

Warning: These SCOPE_* macros rely on the __COUNTER__ when it's available, which should not have any problem when the SCOPE_* macros are used on the same line. However, when the __COUNTER__ macro is not available, __LINE__ is used instead. This leads to compilation error when using the SCOPE_* macros on the same line. So either use compilers that support the __COUNTER__ macros (GCC, Clang, and MSVC all support it), or make sure that the SCOPE_* are not used on the same line.

Example

#include <iostream>

#include <scope.hpp>

int main() {
  try {
    auto on_exit    = scope::scope_exit([]{ std::cout << "exit\n"; });
    auto on_fail    = scope::scope_fail([]{ std::cout << "fail\n"; });
    auto on_success = scope::scope_success([]{ std::cout << "success\n"; });

    SCOPE_EXIT([]{ std::cout << "scope_exit\n"; });
    SCOPE_FAIL([]{ std::cout << "scope_fail\n"; });
    SCOPE_SUCCESS([]{ std::cout << "scope_success\n"; });
    throw 42;
  } catch (...) {
  }
}

The above snippet prints

scope_fail
scope_exit
fail
exit

unique_resource and make_unique_resource_checked

unique_resource holds an object and runs a function when the it goes out of scope while being "active". A unique_resource object is not "active" when its release function is called, or when it's created with the make_unique_resource_checked function and the resource is not valid (check example to see what valid means).

#include <cstdio>
#include <iostream>

#include <scope.hpp>

int main() {
  auto closer = [](FILE *handle) {
    static auto count = 0;
    std::cout << "called: " << count++ << std::endl;
    std::fclose(handle);
  };
  {
    auto filename = "hello.txt";
    auto file = scope::make_unique_resource_checked(std::fopen(filename, "w"),
                                                    nullptr, closer);
  }
  {
    auto filename = "/doesnotexist/hello.txt";
    auto file = scope::make_unique_resource_checked(std::fopen(filename, "w"),
                                                    nullptr, closer);
  }
}

The above snippet prints

called: 0

The second block will not invoke closer because the value returned from std::fopen(file, "w") is nullptr, hence it's consider not "valid" and the deleter is not invoked.

About

A C++17 library for declarative flow control

License:Boost Software License 1.0


Languages

Language:C++ 95.3%Language:CMake 4.7%