Skip to content

Instantly share code, notes, and snippets.

@trvswgnr
Created April 12, 2025 13:49
Show Gist options
  • Save trvswgnr/039277b4b845a55d4ef9c1fa7c7a3e7e to your computer and use it in GitHub Desktop.
Save trvswgnr/039277b4b845a55d4ef9c1fa7c7a3e7e to your computer and use it in GitHub Desktop.
rust's result and println implemented in c++
#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