Skip to content

Commit

Permalink
SERVER-19720 add a std::error_category() for MongoDB error codes
Browse files Browse the repository at this point in the history
  • Loading branch information
amidvidy committed Aug 13, 2015
1 parent c04aaef commit 3461812
Show file tree
Hide file tree
Showing 4 changed files with 236 additions and 1 deletion.
26 changes: 25 additions & 1 deletion src/mongo/base/SConscript
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,29 @@ env.CppUnitTest('base_test',
'parse_number_test.cpp',
'status_test.cpp',
'status_with_test.cpp',
'string_data_test.cpp'
'string_data_test.cpp',
])

env.Library(
target=[
'system_error'
],
source=[
'system_error.cpp',
],
LIBDEPS=[
'$BUILD_DIR/mongo/base',
],
)

env.CppUnitTest(
target=[
'system_error_test',
],
source=[
'system_error_test.cpp',
],
LIBDEPS=[
'system_error',
],
)
91 changes: 91 additions & 0 deletions src/mongo/base/system_error.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/**
* Copyright (C) 2015 MongoDB Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the GNU Affero General Public License in all respects for
* all of the code used other than as permitted herein. If you modify file(s)
* with this exception, you may extend this exception to your version of the
* file(s), but you are not obligated to do so. If you do not wish to do so,
* delete this exception statement from your version. If you delete this
* exception statement from all source files in the program, then also delete
* it in the license file.
*/

#include "mongo/platform/basic.h"

#include <boost/config.hpp>
#include <string>

#include "mongo/base/system_error.h"

namespace mongo {

namespace {

/**
* A std::error_category for the codes in the named ErrorCodes space.
*/
class MongoErrorCategoryImpl final : public std::error_category {
public:
MongoErrorCategoryImpl() = default;

const char* name() const noexcept override {
return "mongo";
}

std::string message(int ev) const override {
return ErrorCodes::errorString(ErrorCodes::fromInt(ev));
}

// We don't really want to override this function, but to override the second we need to,
// otherwise there will be issues with overload resolution. Additionally, the use of
// BOOST_NOEXCEPT is necessitated by the libc++/libstdc++ STL having 'noexcept' on the
// overridden methods, but not the Dinkumware STL as of MSVC 2013.
bool equivalent(const int code,
const std::error_condition& condition) const BOOST_NOEXCEPT override {
return std::error_category::equivalent(code, condition);
}

bool equivalent(const std::error_code& code, int condition) const BOOST_NOEXCEPT override {
switch (ErrorCodes::fromInt(condition)) {
case ErrorCodes::OK:
// Make ErrorCodes::OK to be equivalent to the default constructed error code.
return code == std::error_code();
default:
return false;
}
}
};

} // namespace

const std::error_category& mongoErrorCategory() {
// TODO: Remove this static, and make a constexpr instance when we move to C++14.
const static MongoErrorCategoryImpl instance{};
return instance;
}

std::error_code make_error_code(ErrorCodes::Error code) {
return std::error_code(ErrorCodes::fromInt(code), mongoErrorCategory());
}

std::error_condition make_error_condition(ErrorCodes::Error code) {
return std::error_condition(ErrorCodes::fromInt(code), mongoErrorCategory());
}

} // namespace mongo
57 changes: 57 additions & 0 deletions src/mongo/base/system_error.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* Copyright (C) 2015 MongoDB Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the GNU Affero General Public License in all respects for
* all of the code used other than as permitted herein. If you modify file(s)
* with this exception, you may extend this exception to your version of the
* file(s), but you are not obligated to do so. If you do not wish to do so,
* delete this exception statement from your version. If you delete this
* exception statement from all source files in the program, then also delete
* it in the license file.
*/

#pragma once

#include <system_error>
#include <type_traits>

#include "mongo/base/error_codes.h"

namespace mongo {

const std::error_category& mongoErrorCategory();

// The next two functions are explicitly named (contrary to our naming style) so that they can be
// picked up by ADL.
std::error_code make_error_code(ErrorCodes::Error code);

std::error_condition make_error_condition(ErrorCodes::Error code);

} // namespace mongo

namespace std {

/**
* Allows a std::error_condition to be implicitly constructed from a mongo::ErrorCodes::Error.
* We specialize this instead of is_error_code_enum as our ErrorCodes are platform independent.
*/
template <>
struct is_error_condition_enum<mongo::ErrorCodes::Error> : public true_type {};

} // namespace std
63 changes: 63 additions & 0 deletions src/mongo/base/system_error_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/**
* Copyright (C) 2015 MongoDB Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the GNU Affero General Public License in all respects for
* all of the code used other than as permitted herein. If you modify file(s)
* with this exception, you may extend this exception to your version of the
* file(s), but you are not obligated to do so. If you do not wish to do so,
* delete this exception statement from your version. If you delete this
* exception statement from all source files in the program, then also delete
* it in the license file.
*/

#include "mongo/platform/basic.h"

#include <system_error>

#include "mongo/base/system_error.h"
#include "mongo/unittest/unittest.h"

namespace mongo {
namespace {

TEST(SystemError, Category) {
ASSERT(make_error_code(ErrorCodes::AuthenticationFailed).category() == mongoErrorCategory());
ASSERT(std::error_code(ErrorCodes::AlreadyInitialized, mongoErrorCategory()).category() ==
mongoErrorCategory());
ASSERT(make_error_condition(ErrorCodes::AuthenticationFailed).category() ==
mongoErrorCategory());
ASSERT(std::error_condition(ErrorCodes::AuthenticationFailed).category() ==
mongoErrorCategory());
}

TEST(SystemError, Conversions) {
ASSERT(make_error_code(ErrorCodes::AlreadyInitialized) == ErrorCodes::AlreadyInitialized);
ASSERT(std::error_code(ErrorCodes::AlreadyInitialized, mongoErrorCategory()) ==
ErrorCodes::AlreadyInitialized);
ASSERT(make_error_condition(ErrorCodes::AlreadyInitialized) == ErrorCodes::AlreadyInitialized);
ASSERT(std::error_condition(ErrorCodes::AlreadyInitialized) == ErrorCodes::AlreadyInitialized);
}

TEST(SystemError, Equivalence) {
ASSERT(ErrorCodes::OK == std::error_code());
ASSERT(std::error_code() == ErrorCodes::OK);
}

} // namespace
} // namespace mongo

0 comments on commit 3461812

Please sign in to comment.