diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..b4b4e86 --- /dev/null +++ b/.clang-format @@ -0,0 +1,66 @@ +--- +Language: Cpp +AccessModifierOffset: -4 +AlignAfterOpenBracket: true +AlignConsecutiveAssignments: false +AlignEscapedNewlinesLeft: false +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Inline +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: false +BinPackArguments: true +BinPackParameters: true +BreakBeforeBinaryOperators: All +BreakBeforeBraces: Linux +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: true +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +IndentCaseLabels: false +IndentWidth: 4 +IndentWrappedFunctionNames: false +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 2 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Right +SpaceAfterCStyleCast: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 8 +UseTab: Never +... + diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..4ed4ef5 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,13 @@ +Current developers: +Evgeniy Alekseev aka arcanis + +Packagers: +Konstantin Voinov (openSuSe) + +Translators: +@Mermouy (French) +Ernesto Avilés Vzqz (Spanish) +@underr (Brazillian Portuguese) +Виктор Слободян (Ukrainian) +Steve Lemuel (Chinese) +Mariusz Kocoń (Polish) diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..c39f898 --- /dev/null +++ b/COPYING @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Evgeniy Alekseev + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..c571a77 --- /dev/null +++ b/README.md @@ -0,0 +1,68 @@ +# result + +Simple header-only variant-driven C++17 `Result` implementation. + +## Requirements + +* c++17 or c++1z with support of variant + +## Usage example + +```cpp +#include +#include + +#include "result.h" + +using namespace std::string_literals; + +enum class ErrorCode { Error }; +using IError = Result::Error; +template using IResult = Result::Result; + + +class Test +{ +public: + Test() = default; + ~Test() = default; + friend std::ostream &operator<<(std::ostream &os, const Test &) + { + os << "I'm test class"; + return os; + }; +}; + + +template Result::Content print_example(IResult r) +{ + switch (r.type()) { + case Result::Content::Value: + std::cout << "Result has value " << r.get() << std::endl; + return Result::Content::Value; + case Result::Content::Error: + std::cout << "Result has error " << r.error().message() << std::endl; + return Result::Content::Error; + case Result::Content::Empty: + std::cout << "Result does not contain anything" << std::endl; + return Result::Content::Empty; + } +} + + +int main() +{ + assert(print_example(42) == Result::Content::Value); + assert(print_example(IError("int error"s)) == Result::Content::Error); + + assert(print_example("a string"s) == Result::Content::Value); + assert(print_example(IError("std::string error"s)) + == Result::Content::Error); + + assert(print_example(Test()) == Result::Content::Value); + assert(print_example(IError("Test error"s)) + == Result::Content::Error); + + return 0; +} +``` diff --git a/result.hpp b/result.hpp new file mode 100644 index 0000000..484c205 --- /dev/null +++ b/result.hpp @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2017 Evgeniy Alekseev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + */ + + +#ifndef _RESULT_H_ +#define _RESULT_H_ + +#include +#include + +/** + * @addtogroup Result + * @brief Result namespace + */ +namespace Result +{ +/** + * @enum Content + * @brief Result content type enumeration + * @var Content::Empty + * invalid content + * @var Content::Value + * Result contains value + * @var Content::Error + * Result contains error + */ +enum class Content { Empty, Value, Error }; + +/** + * @brief Error representation + * @tparam ErrorEnum + * error code enumeration + */ +template class Error +{ +public: + /** + * @brief Error class default constructor + * @param message + * human readable error message + * @param code + * machine readable error code + */ + explicit Error(std::string message, ErrorEnum code) + : m_code(code) + { + m_message = std::move(message); + }; + /** + * @brief Error class constructor with default error code + * @param message + * human readable error message + */ + Error(ErrorEnum code) + : Error("", code){}; + /** + * @brief Error class constructor with empty error message + * @param code + * machine readable error code + */ + Error(std::string message) + : Error(message, static_cast(0)){}; + /** + * @brief Error class destructor + */ + ~Error() = default; + + /** + * @brief error message + * @return human readable error message + */ + std::string message() const { return m_message; }; + /** + * @brief error code + * @return machine readable error code + */ + ErrorEnum code() const { return m_code; }; + +private: + /** + * @brief human readable error message + */ + std::string m_message; + /** + * @brief machine readable error code + */ + ErrorEnum m_code; +}; + +/** + * @brief Result main class + * @tparam T + * value class name + * @tparam ErrorEnum + * error code enumeration + */ +template +class Result : public std::variant> +{ +public: + /** + * @brief Result constructor with value + * @param value + * result value + */ + Result(T value) + : std::variant>(value){}; + /** + * @brief Result constructor with error + * @param error + * result error + */ + Result(Error error) + : std::variant>(error){}; + + /** + * @brief get result value + * @throw std::bad_variant_access + * @return result value if holded + */ + T get() { return std::get(*this); }; + /** + * @brief get result error + * @throw std::bad_variant_access + * @return result error if holded + */ + Error error() { return std::get>(*this); }; + /** + * @brief get result content + */ + Content type() const + { + switch (this->index()) { + case 0: + return Content::Value; + case 1: + return Content::Error; + case std::variant_npos: + default: + return Content::Empty; + }; + }; +}; +}; + +#endif /* _RESULT_H_ */