Home

Awesome

<img src="https://github.com/lamarrr/STX/workflows/cpp-17:clang-14:macos-12/badge.svg"> <img src="https://github.com/lamarrr/STX/workflows/cpp-17:clang-14:ubuntu-22.04/badge.svg"> <img src="https://github.com/lamarrr/STX/workflows/cpp-17:gcc-12:ubuntu-22.04/badge.svg"> <img src="https://github.com/lamarrr/STX/workflows/cpp-17:msvc-2019:windows/badge.svg"> <img src="https://github.com/lamarrr/STX/workflows/cpp-17:clang-15:ubuntu-22.04-qemu-arm/badge.svg">

<br/> <div align="center"><img src="assets/stx.png"/> </div> <div align="center"><i> C++ 17 & C++ 20 error-handling and utility extensions.</i> </div>

Overview

STX is a collection of libraries and utilities designed to make working with C++ easier and less error-prone.

<div align="center"> <h3> <a href="http://lamarrr.github.io/STX"> READ THE DOCUMENTATION </a> </h3> </div> <div align="center"> <h3> <a href="https://github.com/lamarrr/STX/tree/master/examples"> SEE THE EXAMPLES </a> </h3> </div>

Features

Basic Examples

Option


#include <iostream>

#include "stx/option.h"

using stx::Option, stx::Some, stx::None;

auto safe_divide(double numerator, double denominator) -> Option<double> {
  if (denominator == 0.0) return None;
  return Some(numerator / denominator);
}

int main() {
  safe_divide(5.0, 2.0).match(
      [](auto value) { std::cout << "Result: " << value << std::endl; },
      []() { std::cout << "Cannot divide by zero" << std::endl; });
}

Result


#include <array>
#include <cinttypes>
#include <iostream>

#include "stx/result.h"

using std::array, std::string_view;
using namespace std::literals;

using stx::Result, stx::Ok, stx::Err;

enum class Version { V1 = 1, V2 = 2 };

auto parse_version(array<uint8_t, 6> const& header) -> Result<Version, string_view> {
  switch (header.at(0)) {
    case 1:
      return Ok(Version::V1);
    case 2:
      return Ok(Version::V2);
    default:
      return Err("Unknown Version"sv);
  }
}

int main() {
  parse_version({2, 3, 4, 5, 6, 7}).match([](auto version){
    std::cout << "Version: " << static_cast<int>(version) << std::endl;
  }, [](auto error){
    std::cout << error  << std::endl;
  });

}

Propagating Errors with TRY_OK

TRY_OK assigns the successful value to its first parameter version if parse_version returned an Ok , else propagates the error value.


// As in the example above
auto parse_version(array<uint8_t, 6> const& header) -> Result<Version, string_view>;

auto parse_data(array<uint8_t, 6> const& header) -> Result<uint8_t, string_view> {
  TRY_OK(version, parse_version(header));
  return Ok(version + header[1] + header[2]);
}

int main() {
  auto parsed = parse_data({2, 3, 4, 5, 6, 7}).unwrap();

  std::cout << parsed << std::endl;
}

You can also add const/volatile attributes to TRY_OK 's assigned value, i.e:


auto parse_data(array<uint8_t, 6> const& header) -> Result<uint8_t, string_view> {
  TRY_OK(const version, parse_version(header));
  return Ok(version + header[1] + header[2]);
}

Guidelines

auto safe_divide(float n, float d) -> Option<float>;

And we call:

float result = safe_divide(n, d).unwrap(); // compiles, because 'safe_divide' returns a temporary
Option option = safe_divide(n, d);
float result = option.unwrap();  // will not compile, because 'unwrap' consumes the value and is only usable with temporaries (as above) or r-value references (as below)

Alternatively, suppose the Option or Result is no longer needed, we can obtain an r-value reference:


Option option = safe_divide(n, d);
float result  = std::move(option).unwrap(); // will compile, the value is moved out of 'option' , 'option' should not be used any more

<b>NOTE</b>: Just as any moved-from object, Option and Result are not to be used after a std::move ! (as the objects will be left in an unspecified state).

To make explicit copies:


Option option = safe_divide(n, d);
float result = option.clone().unwrap(); // note that 'clone()' explicitly makes a copy of the 'Option'

We can also obtain an l-value reference to copy the value:


Option option = safe_divide(n, d);
float result = option.value(); // note that 'value()' returns an l-value reference and 'result' is copied from 'option''s value in the process


float result = safe_divide(n, d).value(); // this won't compile as 'value' always returns an l-value reference, use 'unwrap()' instead

Build Requirements

License

MIT License

FAQ

Is STX's ABI stable?

NO