blob: 6322c7a37ccfbe30e5e8b4fd3afbc8845ff2231d [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef _IGNITE_COMMON_EXPECTED
#define _IGNITE_COMMON_EXPECTED
#include <memory>
#include <ignite/common/utils.h>
namespace ignite
{
namespace common
{
/**
* Helper class to construct Expected class with error value.
*/
template<typename E>
struct Unexpected
{
/** Value type. */
typedef E ValueType;
/**
* Constructor.
*
* @param e Error value reference.
*/
Unexpected(const ValueType& e) : err(e)
{
// No-op;
}
/** Error. */
const ValueType& err;
};
/**
* Operation result wrapper.
*
* Represents a type, which can accept one of two value types - expected
* result or error.
*
* @tparam R Result type.
* @tparam E Error type.
* @tparam AR Allocator type used for the Result type.
* @tparam AE Allocator type used for the Error type.
*/
template<
typename R,
typename E,
typename AR = std::allocator<R>,
typename AE = std::allocator<E> >
class Expected
{
public:
/** Result type. */
typedef R ResultType;
/** Error type. */
typedef E ErrorType;
/** Allocator type used for the ResultType. */
typedef AR ResultAllocatorType;
/** Allocator type used for the ErrorType. */
typedef AE ErrorAllocatorType;
/**
* Constructor.
*
* Creates new instance, containing expected value.
* @param res Result.
*/
Expected(const ResultType& res) :
ok(true)
{
ResultAllocatorType ral;
ral.construct(AsResult(), res);
}
/**
* Constructor.
*
* Creates new instance, containing error.
* @param err Result.
*/
explicit Expected(Unexpected<ErrorType> err) :
ok(false)
{
ErrorAllocatorType ral;
ral.construct(AsError(), err.err);
}
/**
* Copy constructor.
*
* @param other Other.
*/
Expected(const Expected& other) :
ok(other.ok)
{
if (ok)
{
ResultAllocatorType ral;
ral.construct(AsResult(), *other.AsResult());
}
else
{
ErrorAllocatorType ral;
ral.construct(AsError(), *other.AsError());
}
}
/**
* Destructor.
*/
~Expected()
{
if (ok)
{
ResultAllocatorType ral;
ral.destroy(AsResult());
}
else
{
ErrorAllocatorType ral;
ral.destroy(AsError());
}
}
/**
* Check if the value is OK.
*
* @return @c false if the value is an error and @c true otherwise.
*/
bool IsOk() const
{
return ok;
}
/**
* Get result. Constant accesser.
*
* @return Result if it was set before.
* @throw ErrorType if there is no result.
*/
const ResultType& GetResult() const
{
if (!ok)
throw *AsError();
return *AsResult();
}
/**
* Get result.
*
* @return Result if it was set before.
* @throw ErrorType if there is no result.
*/
ResultType& GetResult()
{
if (!ok)
throw *AsError();
return *AsResult();
}
/**
* Get result. Constant accesser.
*
* @return Result if it was set before.
* @throw ErrorType if there is no result.
*/
const ResultType& operator*() const
{
return GetResult();
}
/**
* Get result.
*
* @return Result if it was set before.
* @throw ErrorType if there is no result.
*/
ResultType& operator*()
{
return GetResult();
}
/**
* Get result. Constant accesser.
*
* @return Result if it was set before.
* @throw ErrorType if there is no result.
*/
const ResultType& operator->() const
{
return GetResult();
}
/**
* Get result.
*
* @return Result if it was set before.
* @throw ErrorType if there is no result.
*/
ResultType& operator->()
{
return GetResult();
}
/**
* Get error.
*
* @return Error if it was set before. If there is no error, default
* constructed error is returned (which is expected to be "No error").
*/
const ErrorType& GetError() const
{
static ErrorType noError;
if (ok)
return noError;
return *AsError();
}
private:
/**
* Get storage as an result.
*
* @return Storage pointer as an result pointer.
*/
ResultType* AsResult()
{
return reinterpret_cast<ResultType*>(&storage);
}
/**
* Get storage as an result.
*
* @return Storage pointer as an result pointer.
*/
const ResultType* AsResult() const
{
return reinterpret_cast<const ResultType*>(&storage);
}
/**
* Get storage as an error.
*
* @return Storage pointer as an error pointer.
*/
ErrorType* AsError()
{
return reinterpret_cast<ErrorType*>(&storage);
}
/**
* Get storage as an error.
*
* @return Storage pointer as an error pointer.
*/
const ErrorType* AsError() const
{
return reinterpret_cast<const ErrorType*>(&storage);
}
/** Storage. */
int8_t storage[sizeof(typename Bigger<ResultType, ErrorType>::type)];
/** Result flag. Set to @c false if the value is an error. */
bool ok;
};
}
}
#endif // _IGNITE_COMMON_EXPECTED