Skip to content

Commit 0bff7e9

Browse files
committed
Implement module helpers/utilities which will be used later
1 parent 8ff72c7 commit 0bff7e9

3 files changed

Lines changed: 249 additions & 0 deletions

File tree

‎src/Utilities/ExceptionHelper.h‎

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#ifndef MOD_PYTHON_ENGINE_EXCEPTION_HELPER_H
2+
#define MOD_PYTHON_ENGINE_EXCEPTION_HELPER_H
3+
4+
#include "PythonException.h"
5+
#include "PythonAPI.h"
6+
#include <string>
7+
#include <exception>
8+
9+
namespace PyEng::Utilities
10+
{
11+
/**
12+
* @brief Exception helper utility
13+
*/
14+
class ExceptionHelper
15+
{
16+
public:
17+
/**
18+
* @brief Format current exception
19+
*
20+
* Formats both Python and C++ exceptions into readable strings.
21+
* Must be called from within a catch block with GIL held.
22+
*
23+
* @return Formatted exception string
24+
*/
25+
[[nodiscard]] static std::string Format()
26+
{
27+
try
28+
{
29+
std::rethrow_exception(std::current_exception());
30+
}
31+
catch (Bridge::API::ErrorAlreadySet const&)
32+
{
33+
std::string traceback = Bridge::ExceptionHandler::FormatException();
34+
if (traceback.empty())
35+
traceback = "Unable to extract traceback...";
36+
37+
return "Python Exception:\n" + traceback;
38+
}
39+
catch (std::exception const& e)
40+
{
41+
return std::string("C++ Exception:\n") + e.what();
42+
}
43+
catch (...)
44+
{
45+
return "Unknown exception occurred...";
46+
}
47+
}
48+
49+
private:
50+
ExceptionHelper() = delete;
51+
};
52+
53+
} // namespace PyEng::Utilities
54+
55+
#endif // MOD_PYTHON_ENGINE_EXCEPTION_HELPER_H

‎src/Utilities/ExecutionResult.h‎

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#ifndef MOD_PYTHON_ENGINE_EXECUTION_RESULT_H
2+
#define MOD_PYTHON_ENGINE_EXECUTION_RESULT_H
3+
4+
#include <string>
5+
#include <utility>
6+
7+
namespace PyEng::Utilities
8+
{
9+
/**
10+
* @brief Generic result container for operations that can succeed or fail
11+
*
12+
* Can be used for any operation that needs to return success/failure status
13+
* along with output or error information.
14+
*/
15+
struct ExecutionResult
16+
{
17+
bool success;
18+
std::string output;
19+
std::string error;
20+
21+
/**
22+
* @brief Implicit conversion to bool for easy success checking
23+
*/
24+
explicit operator bool() const noexcept { return success; }
25+
26+
/**
27+
* @brief Create a successful result
28+
*
29+
* @param output Output message string (optional)
30+
* @return ExecutionResult with success=true
31+
*/
32+
static ExecutionResult Success(std::string const& output = "")
33+
{
34+
return {true, std::move(output), ""};
35+
}
36+
37+
/**
38+
* @brief Create a failed result
39+
*
40+
* @param error Error message string
41+
* @return ExecutionResult with success=false
42+
*/
43+
static ExecutionResult Error(std::string error)
44+
{
45+
return {false, "", std::move(error)};
46+
}
47+
48+
/**
49+
* @brief Get the relevant message (output if success, error if failed)
50+
*
51+
* @return Reference to output or error string
52+
*/
53+
[[nodiscard]] std::string const& GetMessage() const noexcept
54+
{
55+
return success ? output : error;
56+
}
57+
58+
/**
59+
* @brief Check if result has any message content
60+
*
61+
* @return True if output or error is not empty, false otherwise
62+
*/
63+
[[nodiscard]] bool HasMessage() const noexcept
64+
{
65+
return success ? !output.empty() : !error.empty();
66+
}
67+
};
68+
69+
} // namespace PyEng::Utilities
70+
71+
#endif // MOD_PYTHON_ENGINE_EXECUTION_RESULT_H

‎src/Utilities/StringHelper.h‎

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
#ifndef MOD_PYTHON_ENGINE_STRING_HELPER_H
2+
#define MOD_PYTHON_ENGINE_STRING_HELPER_H
3+
4+
#include <string_view>
5+
#include <string>
6+
#include <vector>
7+
8+
namespace PyEng::Utilities
9+
{
10+
/**
11+
* @brief Generic string manipulation utilities
12+
*/
13+
class StringHelper
14+
{
15+
public:
16+
/**
17+
* @brief Trim whitespace from the left (start) of string
18+
*/
19+
[[nodiscard]] static std::string_view TrimLeft(std::string_view str) noexcept
20+
{
21+
if (str.empty())
22+
return str;
23+
24+
size_t start = str.find_first_not_of(" \t\r\n");
25+
if (start == std::string_view::npos)
26+
return "";
27+
28+
return str.substr(start);
29+
}
30+
31+
/**
32+
* @brief Trim whitespace from the right (end) of string
33+
*/
34+
[[nodiscard]] static std::string_view TrimRight(std::string_view str) noexcept
35+
{
36+
if (str.empty())
37+
return str;
38+
39+
size_t end = str.find_last_not_of(" \t\r\n");
40+
if (end == std::string_view::npos)
41+
return "";
42+
43+
return str.substr(0, end + 1);
44+
}
45+
46+
/**
47+
* @brief Trim whitespace from both sides of string
48+
*/
49+
[[nodiscard]] static std::string_view Trim(std::string_view str) noexcept
50+
{
51+
return TrimRight(TrimLeft(str));
52+
}
53+
54+
/**
55+
* @brief Remove matching quotes from string
56+
*/
57+
[[nodiscard]] static std::string_view Unquote(std::string_view str) noexcept
58+
{
59+
if (str.length() < 2)
60+
return str;
61+
62+
char first = str.front();
63+
char last = str.back();
64+
65+
if ((first == '"' && last == '"') || (first == '\'' && last == '\''))
66+
return str.substr(1, str.length() - 2);
67+
68+
return str;
69+
}
70+
71+
/**
72+
* @brief Split string into lines with optional max length per line
73+
*
74+
* @param str String to split
75+
* @param maxLength Maximum line length (0 = unlimited)
76+
* @return Vector of trimmed, non-empty lines
77+
*/
78+
[[nodiscard]] static std::vector<std::string> SplitLines(std::string_view str, size_t maxLength = 0)
79+
{
80+
std::vector<std::string> result;
81+
if (str.empty())
82+
return result;
83+
84+
size_t pos = 0;
85+
86+
while (pos < str.length())
87+
{
88+
size_t newlinePos = str.find('\n', pos);
89+
size_t lineEnd = (newlinePos != std::string_view::npos) ? newlinePos : str.length();
90+
91+
std::string line(Trim(str.substr(pos, lineEnd - pos)));
92+
93+
line = Truncate(line, maxLength);
94+
if (!line.empty())
95+
result.push_back(std::move(line));
96+
97+
pos = (newlinePos != std::string_view::npos) ? newlinePos + 1 : str.length();
98+
}
99+
100+
return result;
101+
}
102+
103+
/**
104+
* @brief Truncate string to maximum length with suffix
105+
*/
106+
[[nodiscard]] static std::string Truncate(std::string_view str, size_t maxLength, std::string_view suffix = "...")
107+
{
108+
if (str.length() <= maxLength)
109+
return std::string(str);
110+
111+
if (maxLength <= suffix.length())
112+
return std::string(str.substr(0, maxLength));
113+
114+
return std::string(str.substr(0, maxLength - suffix.length())) + std::string(suffix);
115+
}
116+
117+
private:
118+
StringHelper() = delete;
119+
};
120+
121+
} // namespace PyEng::Utilities
122+
123+
#endif // MOD_PYTHON_ENGINE_STRING_HELPER_H

0 commit comments

Comments
 (0)