Created
April 12, 2025 13:49
-
-
Save trvswgnr/039277b4b845a55d4ef9c1fa7c7a3e7e to your computer and use it in GitHub Desktop.
rust's result and println implemented in c++
This file contains hidden or 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
#include <iostream> | |
#include <string> | |
#include <string_view> | |
#include <tuple> | |
#include <typeinfo> | |
#include <cstdio> | |
#include <vector> | |
std::vector<size_t> find_placeholders(const std::string_view& fmt) { | |
std::vector<size_t> positions; | |
for (size_t i = 0; i < fmt.size(); ++i) { | |
if (fmt[i] == '{' && (i + 1 < fmt.size()) && fmt[i + 1] == '}') { | |
positions.push_back(i); | |
i++; | |
} | |
} | |
return positions; | |
} | |
void format_internal(std::string& result, const std::string_view& fmt, | |
const std::vector<size_t>& placeholders, size_t current_ph, | |
size_t& current_pos) { | |
result.append(fmt.substr(current_pos)); | |
} | |
template <typename T, typename... Args> | |
void format_internal(std::string& result, const std::string_view& fmt, | |
const std::vector<size_t>& placeholders, size_t current_ph, | |
size_t& current_pos, const T& value, const Args&... args) { | |
if (current_ph < placeholders.size()) { | |
size_t ph_pos = placeholders[current_ph]; | |
result.append(fmt.substr(current_pos, ph_pos - current_pos)); | |
current_pos = ph_pos + 2; | |
using std::to_string; | |
if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, const char*> | |
|| std::is_same_v<T, std::string_view>) { | |
result.append(value); | |
} else if constexpr (std::is_arithmetic_v<T>) { | |
result.append(to_string(value)); | |
} else { | |
result.append("<Object>"); | |
} | |
format_internal(result, fmt, placeholders, current_ph + 1, current_pos, args...); | |
} else { | |
format_internal(result, fmt, placeholders, current_ph, current_pos); | |
} | |
} | |
template <typename... Args> | |
std::string format(const std::string_view& fmt, const Args&... args) { | |
std::string result; | |
result.reserve(fmt.size() + sizeof...(args) * 8); | |
auto placeholders = find_placeholders(fmt); | |
if (placeholders.size() != sizeof...(args)) { | |
std::cerr << "Warning: Number of placeholders (" << placeholders.size() | |
<< ") doesn't match number of arguments (" << sizeof...(args) << ")\n"; | |
} | |
size_t current_pos = 0; | |
format_internal(result, fmt, placeholders, 0, current_pos, args...); | |
return result; | |
} | |
#define println(fmt, ...) \ | |
std::cout << format(fmt, ##__VA_ARGS__) << std::endl | |
#define print(fmt, ...) \ | |
std::cout << format(fmt, ##__VA_ARGS__) | |
#include <variant> | |
template<typename T, typename E> | |
class Result { | |
public: | |
using value_type = T; | |
using error_type = E; | |
private: | |
std::variant<T, E> data; | |
bool is_ok_value; | |
public: | |
template<typename U = T, | |
typename = std::enable_if_t<!std::is_same_v<std::decay_t<U>, Result>>> | |
Result(U&& value) : data(std::forward<U>(value)), is_ok_value(true) {} | |
template<typename U = E> | |
static Result<T, E> Err(U&& error) { | |
Result<T, E> result; | |
result.data = std::forward<U>(error); | |
result.is_ok_value = false; | |
return result; | |
} | |
Result() = default; | |
[[nodiscard]] bool is_ok() const { | |
return is_ok_value; | |
} | |
[[nodiscard]] bool is_err() const { | |
return !is_ok_value; | |
} | |
[[nodiscard]] const T& unwrap() const { | |
if (!is_ok_value) { | |
throw std::runtime_error("Called unwrap on an Err value"); | |
} | |
return std::get<T>(data); | |
} | |
[[nodiscard]] T&& unwrap() { | |
if (!is_ok_value) { | |
throw std::runtime_error("Called unwrap on an Err value"); | |
} | |
return std::get<T>(std::move(data)); | |
} | |
[[nodiscard]] const E& unwrap_err() const { | |
if (is_ok_value) { | |
throw std::runtime_error("Called unwrap_err on an Ok value"); | |
} | |
return std::get<E>(data); | |
} | |
template<typename F, typename U = std::invoke_result_t<F, T>> | |
[[nodiscard]] Result<U, E> map(F&& f) const { | |
if (is_ok_value) { | |
return Result<U, E>(f(std::get<T>(data))); | |
} else { | |
return Result<U, E>::Err(std::get<E>(data)); | |
} | |
} | |
template<typename F> | |
[[nodiscard]] auto and_then(F&& f) const -> std::invoke_result_t<F, T> { | |
using ResultType = std::invoke_result_t<F, T>; | |
if (is_ok_value) { | |
return f(std::get<T>(data)); | |
} else { | |
return ResultType::Err(std::get<E>(data)); | |
} | |
} | |
template<typename U> | |
[[nodiscard]] T unwrap_or(U&& default_value) const { | |
if (is_ok_value) { | |
return std::get<T>(data); | |
} else { | |
return std::forward<U>(default_value); | |
} | |
} | |
}; | |
template<typename T, typename E = std::string> | |
Result<T, E> Ok(T&& value) { | |
return Result<T, E>(std::forward<T>(value)); | |
} | |
Result<double, std::string> divide(double numerator, double denominator) { | |
if (denominator == 0.0) { | |
return Result<double, std::string>::Err("Division by zero error"); | |
} | |
return Ok<double>(numerator / denominator); | |
} | |
int main() { | |
println("hello darkness my old friend"); | |
println("answer is {}", 69); | |
println("pi is abour {}", 3.14159); | |
println("multiple values: {} and {}", "string", 123); | |
auto result = divide(10.0, 2.0); | |
if (result.is_ok()) { | |
println("Result: {}", result.unwrap()); | |
} else { | |
println("Error: {}", result.unwrap_err()); | |
} | |
auto result2 = divide(5.0, 0.0); | |
if (result2.is_ok()) { | |
println("Result: {}", result2.unwrap()); | |
} else { | |
println("Error: {}", result2.unwrap_err()); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment