Skip to content

Scope

Scope

Description

Run a scoped block and automatically deinitialize the object at the end.

Executes scope_body and ensures obj_deinit(obj) is called afterward, regardless of the block’s control flow. This is similar to RAII-style resource management in C++ but implemented manually via a macro.

The object is passed by pointer. It is not copied or moved.

This macro ensures the object is only evaluated once by capturing it internally using TYPE_OF.

The memory pointed to by obj is not cleared after deinitialization; if zeroing is needed, do it inside obj_deinit.

Parameters:

Parameters

Name Direction Description
obj in Pointer to the object to manage.
obj_deinit in Function or macro to deinitialize the object.
scope_body in Block of code that uses the object. MyStruct s = MyStructInit(); Scope(&s, MyStructDeinit, { UseStruct(&s); });

Success

Always continues execution after scope.

Failure

Caller must handle errors inside the scoped body.

Usage example (Cross-references)

Usage examples (Cross-references)
    
        Project project = {0};
        Scope(&project, ProjectDeinit, {
            // read project config
            Str config = StrInit();
            // read project config
            Str config = StrInit();
            Scope(&config, StrDeinit, {
                if (!ReadCompleteFile(config_path, &config.data, &config.length, &config.capacity)) {
                    LOG_FATAL("Failed to read config file.");
            // recursively explore directories and get files that need documentation
            Strs file_paths = VecInit();
            Scope(&file_paths, VecDeinit, {
                // temporary vector to store all directory paths to explore files in
                Strs dir_paths = VecInitWithDeepCopy(NULL, StrDeinit);
                // temporary vector to store all directory paths to explore files in
                Strs dir_paths = VecInitWithDeepCopy(NULL, StrDeinit);
                Scope(&dir_paths, VecDeinit, {
                    VecMerge(&dir_paths, &project.source_directories);
                    VecMerge(&dir_paths, &project.test_directories);
    
                        SysDirContents dir_contents = SysGetDirContents(dir_name.data);
                        Scope(&dir_contents, VecDeinit, {
                            VecForeach(&dir_contents, dir_entry) {
                                // if it's a directory then store it for exploration later on
    VecForeach(&file_paths, file_path) {
        Str file_contents = StrInit();
        Scope(&file_contents, StrDeinit, {
            if (!ReadCompleteFile(file_path.data, &file_contents.data, &file_contents.length, &file_contents.capacity)) {
                LOG_ERROR("Failed to read \"{}\" source file.", file_path.data);
    
            Str output_path = StrInit();
            Scope(&output_path, StrDeinit, {
                StrMerge(&output_path, &file_path);
                LOG_INFO("{}", output_path);
    
                Str md_code = StrInit();
                Scope(&md_code, StrDeinit, {
                    // Create template strings for StrWriteFmt with escaped braces
                    const char *mdHeader =
                    // dump code to output path
                    FILE *f = fopen(output_path.data, "w");
                    Scope(f, fclose, { fwrite(md_code.data, 1, md_code.length, f); });
                });
            });
Last updated on