-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
217 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} |