Skip to content

Commit

Permalink
add missing files
Browse files Browse the repository at this point in the history
  • Loading branch information
bha-evs committed Feb 7, 2024
1 parent 0b723d1 commit d2349dc
Show file tree
Hide file tree
Showing 2 changed files with 217 additions and 0 deletions.
96 changes: 96 additions & 0 deletions lib/include/bofstd/bofscopeguard.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#pragma once
#include <bofstd/bofstd.h>
#include <utility>
/*
The code you provided is implementing a simple scope guard utility named BofScopeGuard. A scope guard is a programming idiom used to ensure that a specific operation or set of operations is executed when exiting a scope, regardless of how the scope is exited (through normal execution, return, or an exception).
Let's break down the key components of the BofScopeGuard utility:
BofScopeGuardOnExit Enum Class:
It serves as a tag to indicate that the associated scope guard should be executed on exit.
BofScopeGuard Class Template:
It's a template class that takes a callable object (F) as its template parameter.
The BofScopeGuard object is constructed with a callable object (a lambda function, function pointer, functor, etc.).
The Dismiss method allows you to mark the scope guard as inactive, preventing its execution on exit.
The destructor of BofScopeGuard automatically executes the callable object when the scope is exited, unless dismissed.
operator+ Function:
It's a free function allowing for a convenient way to create BofScopeGuard objects using the + operator.
When BofScopeGuardOnExit is used with +, it creates a BofScopeGuard with the associated callable object.
BOF_SCOPE_EXIT Macro:
This macro provides a convenient way to declare a BofScopeGuard variable within a scope.
It uses a combination of the BOF_ANONYMOUS_VARIABLE macro and the BOF::BofScopeGuardOnExit tag to create an anonymous BofScopeGuard variable.
Here's an example of how you might use this BofScopeGuard utility:
cpp
Copy code
#include "your_scope_guard_header.h"
void exampleFunction()
{
BOF_SCOPE_EXIT
{
// This code will be executed when the scope is exited
// It can be used for cleanup, logging, or other operations
std::cout << "Exiting the scope!" << std::endl;
};
// Rest of the function...
// The BofScopeGuard's destructor will be called when exiting the scope
// The associated lambda function inside BOF_SCOPE_EXIT will be executed
}
In this example, the lambda function provided to BOF_SCOPE_EXIT will be executed when the scope is exited, ensuring that the specified actions are taken regardless of how the scope is exited. This is particularly useful for resource management and cleanup tasks.
*/
BEGIN_BOF_NAMESPACE()
#define BOF_CONCATENATE_IMPL(s1, s2) s1##s2
#define BOF_CONCATENATE(s1, s2) BOF_CONCATENATE_IMPL(s1, s2)
#ifdef __COUNTER__
#define BOF_ANONYMOUS_VARIABLE(str) BOF_CONCATENATE(str, __COUNTER__)
#else
#define BOF_ANONYMOUS_VARIABLE(str) BOF_CONCATENATE(str, __LINE__)
#endif

enum class BofScopeGuardOnExit
{
};
template <typename OutOfScopeCallback>
class BofScopeGuard
{
OutOfScopeCallback mOutOfScopeCallback;
bool mActive_B;

public:
BofScopeGuard() = delete;
BofScopeGuard(const BofScopeGuard &) = delete;
BofScopeGuard &operator=(const BofScopeGuard &) = delete;
BofScopeGuard(BofScopeGuard &&_rrhs) : mF(std::move(_rrhs.mOutOfScopeCallback)), mActive_B(_rrhs.mActive_B)
{
_rrhs.dismiss();
}
BofScopeGuard(OutOfScopeCallback _OutOfScopeCallback) : mOutOfScopeCallback(std::move(_OutOfScopeCallback)), mActive_B(true)
{
}
~BofScopeGuard()
{
if (mActive_B)
{
mOutOfScopeCallback();
}
}
void Dismiss()
{
mActive_B = false;
}
};
template <typename OutOfScopeCallback>
inline BofScopeGuard<OutOfScopeCallback> operator+(BofScopeGuardOnExit, OutOfScopeCallback &&_rrOutOfScopeCallback)
{
return BofScopeGuard<OutOfScopeCallback>(std::forward<OutOfScopeCallback>(_rrOutOfScopeCallback));
}

#define BOF_SCOPE_EXIT() auto BOF_ANONYMOUS_VARIABLE(BOF_SCOPE_EXIT_STATE) = BOF::BofScopeGuardOnExit() + [&]()
END_BOF_NAMESPACE()
121 changes: 121 additions & 0 deletions tests/src/ut_graph.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*
* Copyright (c) 2023-2033, OnBings All rights reserved.
*
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
* PURPOSE.
*
* This module implements the unit testing of the bofgraph functions
*
* Name: ut_graph.cpp
* Author: Bernard HARMEL: [email protected]
* Web: onbings.dscloud.me
* Revision: 1.0
*
* Rem: Initial version from https://github.com/Nelarius/imnodes
*
* History:
*
* V 1.00 Feb 5 2024 BHA : Initial release
*/
#include "gtestrunner.h"
#include <bofstd/bofgraph.h>

class Graph_Test : public ::testing::Test
{
protected:
std::unique_ptr<BOF::BofDirGraph<uint32_t>> mpuDirGraph=nullptr;

void SetUp() override
{
BOF::BOF_DIR_GRAPH_PARAM BofDirGraphParam_X;
BofDirGraphParam_X.MultiThreadAware_B = true;
mpuDirGraph = std::make_unique<BOF::BofDirGraph<uint32_t>>(BofDirGraphParam_X);
}
};

TEST_F(Graph_Test, InsertAndEraseNode)
{
uint32_t node_id = mpuDirGraph->InsertNode(42);
ASSERT_TRUE(mpuDirGraph->NodeMap().Contain(node_id));

mpuDirGraph->EraseNode(node_id);
ASSERT_FALSE(mpuDirGraph->NodeMap().Contain(node_id));
}

TEST_F(Graph_Test, InsertAndEraseEdge)
{
uint32_t NodeA_U32 = mpuDirGraph->InsertNode(1);
uint32_t NodeB_U32 = mpuDirGraph->InsertNode(2);
uint32_t EdgeId_U32 = mpuDirGraph->InsertEdge(NodeA_U32, NodeB_U32);
ASSERT_TRUE(mpuDirGraph->EdgeMap().Contain(EdgeId_U32));

mpuDirGraph->EraseEdge(EdgeId_U32);
ASSERT_FALSE(mpuDirGraph->EdgeMap().Contain(EdgeId_U32));
}

TEST_F(Graph_Test, DFSTraversal)
{
uint32_t NodeA_U32 = mpuDirGraph->InsertNode(1);
uint32_t NodeB_U32 = mpuDirGraph->InsertNode(2);
uint32_t NodeC_U32 = mpuDirGraph->InsertNode(3);

mpuDirGraph->InsertEdge(NodeA_U32, NodeB_U32);
mpuDirGraph->InsertEdge(NodeB_U32, NodeC_U32);

std::vector<uint32_t> visited_nodes;
BOF::DfsTraverse(*mpuDirGraph, NodeA_U32, [&visited_nodes](uint32_t node) { visited_nodes.push_back(node); });

ASSERT_EQ(visited_nodes.size(), 3);
ASSERT_EQ(visited_nodes[0], NodeA_U32);
ASSERT_EQ(visited_nodes[1], NodeB_U32);
ASSERT_EQ(visited_nodes[2], NodeC_U32);
}

TEST_F(Graph_Test, FindAndContainsNode)
{
uint32_t node_id = mpuDirGraph->InsertNode(42);
ASSERT_TRUE(mpuDirGraph->NodeMap().Contain(node_id));

// Using find method to check if a node exists
BOF::IdMap<uint32_t>::iterator iter = mpuDirGraph->NodeMap().Find(node_id);
ASSERT_NE(iter, mpuDirGraph->NodeMap().end());

iter = mpuDirGraph->NodeMap().Find(node_id+1);
ASSERT_EQ(iter, mpuDirGraph->NodeMap().end());

ASSERT_TRUE(mpuDirGraph->NodeMap().Contain(node_id));
}

TEST_F(Graph_Test, FindAndContainsEdge)
{
uint32_t NodeA_U32 = mpuDirGraph->InsertNode(1);
uint32_t NodeB_U32 = mpuDirGraph->InsertNode(2);
uint32_t EdgeId_U32 = mpuDirGraph->InsertEdge(NodeA_U32, NodeB_U32);
ASSERT_TRUE(mpuDirGraph->EdgeMap().Contain(EdgeId_U32));

// Using find_edge method to check if an edge exists
BOF::IdMap<BOF::BofDirGraph<uint32_t>::Edge>::iterator iter = mpuDirGraph->EdgeMap().Find(EdgeId_U32);
ASSERT_NE(iter, mpuDirGraph->EdgeMap().end());

ASSERT_TRUE(mpuDirGraph->EdgeMap().Contain(EdgeId_U32));
}

TEST_F(Graph_Test, EraseNodeWithEdges)
{
uint32_t NodeA_U32 = mpuDirGraph->InsertNode(1);
uint32_t NodeB_U32 = mpuDirGraph->InsertNode(2);
uint32_t NodeC_U32 = mpuDirGraph->InsertNode(3);

mpuDirGraph->InsertEdge(NodeA_U32, NodeB_U32);
mpuDirGraph->InsertEdge(NodeB_U32, NodeC_U32);

ASSERT_EQ(mpuDirGraph->NbEdgeFromNode(NodeB_U32), 1);

mpuDirGraph->EraseNode(NodeB_U32);

ASSERT_FALSE(mpuDirGraph->NodeMap().Contain(NodeB_U32));
ASSERT_EQ(mpuDirGraph->NbEdgeFromNode(NodeA_U32), 0);
ASSERT_EQ(mpuDirGraph->NbEdgeFromNode(NodeC_U32), 0);
}

0 comments on commit d2349dc

Please sign in to comment.