error_condition example

// This program illustrates how one can plug one's error
// condition enumeration into std::error_condition facility.
 
 
// FILE: flights.h
 
# include <system_error>
 
enum class FlightsErrc
{
  // no 0
  NonexistentLocations = 10, // requested airport doesn't exist
  DatesInThePast,            // booking flight for yesterday
  InvertedDates,             // returning before departure
  NoFlightsFound       = 20, // did not find any combination
  ProtocolViolation    = 30, // e.g., bad XML
  ConnectionError,           // could not connect to server
  ResourceError,             // service run short of resources
  Timeout,                   // did not respond in time
};
 
namespace std
{
  template <>
    struct is_error_code_enum<FlightsErrc> : true_type {};
}
 
std::error_code make_error_code(FlightsErrc);
 
// FILE: seats.h

enum class SeatsErrc
{
  // no 0
  InvalidRequest = 1,    // e.g., bad XML
  CouldNotConnect,       // could not connect to server
  InternalError,         // service run short of resources
  NoResponse,            // did not respond in time
  NonexistentClass,      // requested class does not exist
  NoSeatAvailable,       // all seats booked
};

namespace std
{
  template <>
    struct is_error_code_enum<SeatsErrc> : true_type {};
}
 
std::error_code make_error_code(SeatsErrc);
 
// FILE queries.h

// # include "flights.h"
// # include "seats.h"

enum class FailureSource
{
    // no 0
    BadUserInput = 1,
    SystemError = 2,
    NoSolution = 3,
};

namespace std
{
  template <>
    struct is_error_condition_enum<FailureSource> : true_type {};
}

std::error_condition make_error_condition(FailureSource e);

// FILE: main.cpp
 
// # include "flights.h"
// # include "seats.h"
# include <cassert>
# include <iostream>
 
int main ()
{
  std::error_code ec = FlightsErrc::NoFlightsFound;   
  assert (ec == FailureSource::NoSolution);
  assert (ec != FailureSource::BadUserInput);
    
  ec = SeatsErrc::NonexistentClass;
  assert (ec != FailureSource::NoSolution);
  assert (ec == FailureSource::BadUserInput);
    
  std::cout << ec << std::endl;
}
 
 
// FILE: flights.cpp
 
// # include "flights.h"
 
namespace { // anonymous namespace
  
struct FlightsErrCategory : std::error_category
{
  const char* name() const noexcept override;
  std::string message(int ev) const override;
};
  
const char* FlightsErrCategory::name() const noexcept
{
  return "flights";
}
  
std::string FlightsErrCategory::message(int ev) const
{
  switch (static_cast<FlightsErrc>(ev))
  {
  case FlightsErrc::NonexistentLocations:
    return "nonexistent airport name in request";
   
  case FlightsErrc::DatesInThePast:
    return "request for a date from the past";
  
  case FlightsErrc::InvertedDates:
    return "requested flight return date before departure date";
  
  case FlightsErrc::NoFlightsFound:
    return "no filight combination found";
  
  case FlightsErrc::ProtocolViolation:
    return "received malformed request";
  
  case FlightsErrc::ConnectionError:
    return "could not connect to server";
  
  case FlightsErrc::ResourceError:
    return "insufficient resources";
  
  case FlightsErrc::Timeout:
    return "processing timed out";
  
  default:
    return "(unrecognized error)";
  }
}
  
const FlightsErrCategory theFlightsErrCategory {};
  
} // anonymous namespace
 
std::error_code make_error_code(FlightsErrc e)
{
  return {static_cast<int>(e), theFlightsErrCategory};
}

// FILE: seats.cpp
 
// # include "seats.h"
 
namespace { // anonymous namespace
  
struct SeatsErrCategory : std::error_category
{
  const char* name() const noexcept override;
  std::string message(int ev) const override;
};
  
const char* SeatsErrCategory::name() const noexcept
{
  return "seats";
}
  
std::string SeatsErrCategory::message(int ev) const
{
  switch (static_cast<SeatsErrc>(ev))
  {      
  case SeatsErrc::InvalidRequest:
    return "received malformed request";
 
  case SeatsErrc::CouldNotConnect:
    return "could not connect to server";
    
  case SeatsErrc::InternalError:
    return "insufficient resources";
    
  case SeatsErrc::NoResponse:
    return "processing timed out";
          
  case SeatsErrc::NonexistentClass:
    return "requested class does not exist";
   
  case SeatsErrc::NoSeatAvailable:
    return "all seats booked";
  
  default:
    return "(unrecognized error)";
  }
}
  
const SeatsErrCategory theSeatsErrCategory {};
  
} // anonymous namespace
 
std::error_code make_error_code(SeatsErrc e)
{
  return {static_cast<int>(e), theSeatsErrCategory};
}

// FILE: queries.cpp

// # include "queries.h"

namespace {

class FailureSourceCategory : public std::error_category
{
public:
  const char* name() const noexcept override;
  std::string message(int ev) const override;
  bool equivalent(
      const std::error_code& code,
      int condition) const noexcept override;
};
    
const char* FailureSourceCategory::name() const noexcept
{
    return "failure-source";
}
    
std::string FailureSourceCategory::message(int ev) const
{
  switch (static_cast<FailureSource>(ev))
  {
  case FailureSource::BadUserInput:
    return "invalid user request";
   
  case FailureSource::SystemError:
    return "internal error";
  
  case FailureSource::NoSolution:
    return "no solution found for specified request";
  
  default:
    return "(unrecognized condition)";
  }
}
    
bool FailureSourceCategory::equivalent(
      const std::error_code& ec,
      int cond) const noexcept
{
  const std::error_category& FlightsCat = 
    std::error_code{FlightsErrc{}}.category();
    
  switch (static_cast<FailureSource>(cond))
  {
  case FailureSource::BadUserInput:
    if (ec == SeatsErrc::NonexistentClass)
      return true;
    if (ec.category() == FlightsCat)
      return ec.value() >= 10 && ec.value() < 20;
    return false;
   
  case FailureSource::SystemError:
    if (ec == SeatsErrc::InvalidRequest ||
        ec == SeatsErrc::CouldNotConnect ||
        ec == SeatsErrc::InternalError ||
        ec == SeatsErrc::NoResponse)
      return true;
       
    if (ec.category() == FlightsCat)
      return ec.value() >= 30 && ec.value() < 40;
      
    return false;
  
  case FailureSource::NoSolution:
    if (ec == SeatsErrc::NoSeatAvailable)
      return true;
    if (ec.category() == FlightsCat)
      return ec.value() >= 20 && ec.value() < 30;
    return false;
            
  default:
    return false;
  }
}
    
const FailureSourceCategory theFailureSourceCategory {};
  
} // anonymous namespace
 
std::error_condition make_error_condition(FailureSource e)
{
  return {static_cast<int>(e), theFailureSourceCategory};
}