Skip to content

File expected.hpp

File List > include > nebula_common > util > expected.hpp

Go to the documentation of this file

// Copyright 2024 TIER IV, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#include <exception>
#include <stdexcept>
#include <string>
#include <variant>

namespace nebula
{
namespace util
{

struct bad_expected_access : public std::exception
{
  explicit bad_expected_access(const std::string & msg) : std::exception(), msg_(msg) {}

  const char * what() const noexcept override { return msg_.c_str(); }

private:
  const std::string msg_;
};

template <typename T, typename E>
struct expected
{
  bool has_value() { return std::holds_alternative<T>(value_); }

  T value()
  {
    if (!has_value()) {
      throw bad_expected_access("value() called but containing error");
    }
    return std::get<T>(value_);
  }

  T value_or(const T & default_)
  {
    if (has_value()) return value();
    return default_;
  }

  T value_or_throw(const std::string & error_msg)
  {
    if (has_value()) return value();
    throw std::runtime_error(error_msg);
  }

  T value_or_throw()
  {
    if (has_value()) return value();
    throw error();
  }

  E error()
  {
    if (has_value()) {
      throw bad_expected_access("error() called but containing value");
    }
    return std::get<E>(value_);
  }

  E error_or(const E & default_)
  {
    if (!has_value()) return error();
    return default_;
  }

  expected(const T & value) { value_ = value; }  // NOLINT(runtime/explicit)

  expected(const E & error) { value_ = error; }  // NOLINT(runtime/explicit)

private:
  std::variant<T, E> value_;
};

}  // namespace util
}  // namespace nebula