Add an Error and ResultOrError<T> type and tests

These types are meant to be used for computations that might but are not
expected to fail in backend/, such that the error case can be much
slower than the success case.

The NXT_TRY and NXT_TRY_RESULT macros are added to help write more
concise code that uses Error and ResultOrError.
This commit is contained in:
Corentin Wallez
2018-05-25 16:23:44 -04:00
committed by Corentin Wallez
parent 44b5ca4aa1
commit 1fda980fa6
7 changed files with 475 additions and 0 deletions

View File

@@ -30,6 +30,7 @@ Generate(
)
target_link_libraries(backend_utils_autogen nxtcpp)
target_include_directories(backend_utils_autogen PUBLIC ${GENERATED_DIR})
target_include_directories(backend_utils_autogen PRIVATE ${SRC_DIR})
function(GenerateProcTable backend)
Generate(
@@ -342,6 +343,10 @@ list(APPEND BACKEND_SOURCES
${BACKEND_DIR}/CommandBufferStateTracker.h
${BACKEND_DIR}/Device.cpp
${BACKEND_DIR}/Device.h
${BACKEND_DIR}/Error.cpp
${BACKEND_DIR}/Error.h
${BACKEND_DIR}/ErrorData.cpp
${BACKEND_DIR}/ErrorData.h
${BACKEND_DIR}/Forward.h
${BACKEND_DIR}/InputState.cpp
${BACKEND_DIR}/InputState.h

31
src/backend/Error.cpp Normal file
View File

@@ -0,0 +1,31 @@
// Copyright 2018 The NXT Authors
//
// 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.
#include "backend/Error.h"
#include "backend/ErrorData.h"
namespace backend {
ErrorData* MakeError(const char* message, const char* file, const char* function, int line) {
ErrorData* error = new ErrorData(message);
error->AppendBacktrace(file, function, line);
return error;
}
void AppendBacktrace(ErrorData* error, const char* file, const char* function, int line) {
error->AppendBacktrace(file, function, line);
}
} // namespace backend

83
src/backend/Error.h Normal file
View File

@@ -0,0 +1,83 @@
// Copyright 2018 The NXT Authors
//
// 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.
#ifndef BACKEND_ERROR_H_
#define BACKEND_ERROR_H_
#include "common/Result.h"
namespace backend {
// This is the content of an error value for MaybeError or ResultOrError, split off to its own
// file to avoid having all files including headers like <string> and <vector>
class ErrorData;
// MaybeError and ResultOrError are meant to be used as return value for function that are not
// expected to, but might fail. The handling of error is potentially much slower than successes.
using MaybeError = Result<void, ErrorData*>;
template <typename T>
using ResultOrError = Result<T, ErrorData*>;
// Returning a success is done like so:
// return {}; // for Error
// return SomethingOfTypeT; // for ResultOrError<T>
//
// Returning an error is done via:
// NXT_RETURN_ERROR("My error message");
#define NXT_RETURN_ERROR(EXPR) return MakeError(EXPR, __FILE__, __func__, __LINE__)
#define NXT_CONCAT1(x, y) x##y
#define NXT_CONCAT2(x, y) NXT_CONCAT1(x, y)
#define NXT_LOCAL_VAR NXT_CONCAT2(_localVar, __LINE__)
// When Errors aren't handled explicitly, calls to functions returning errors should be
// wrapped in an NXT_TRY. It will return the error if any, otherwise keep executing
// the current function.
#define NXT_TRY(EXPR) \
{ \
auto NXT_LOCAL_VAR = EXPR; \
if (NXT_UNLIKELY(NXT_LOCAL_VAR.IsError())) { \
ErrorData* error = NXT_LOCAL_VAR.AcquireError(); \
AppendBacktrace(error, __FILE__, __func__, __LINE__); \
return {error}; \
} \
} \
for (;;) \
break
// NXT_TRY_ASSIGN is the same as NXT_TRY for ResultOrError and assigns the success value, if
// any, to VAR.
#define NXT_TRY_ASSIGN(VAR, EXPR) \
{ \
auto NXT_LOCAL_VAR = EXPR; \
if (NXT_UNLIKELY(NXT_LOCAL_VAR.IsError())) { \
ErrorData* error = NXT_LOCAL_VAR.AcquireError(); \
AppendBacktrace(error, __FILE__, __func__, __LINE__); \
return {error}; \
} \
VAR = NXT_LOCAL_VAR.AcquireSuccess(); \
} \
for (;;) \
break
// Implementation detail of NXT_TRY and NXT_TRY_ASSIGN's adding to the Error's backtrace.
void AppendBacktrace(ErrorData* error, const char* file, const char* function, int line);
// Implementation detail of NXT_RETURN_ERROR
ErrorData* MakeError(const char* message, const char* file, const char* function, int line);
} // namespace backend
#endif // BACKEND_ERROR_H_

41
src/backend/ErrorData.cpp Normal file
View File

@@ -0,0 +1,41 @@
// Copyright 2018 The NXT Authors
//
// 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.
#include "backend/ErrorData.h"
namespace backend {
ErrorData::ErrorData() = default;
ErrorData::ErrorData(std::string message) : mMessage(std::move(message)) {
}
void ErrorData::AppendBacktrace(const char* file, const char* function, int line) {
BacktraceRecord record;
record.file = file;
record.function = function;
record.line = line;
mBacktrace.push_back(std::move(record));
}
const std::string& ErrorData::GetMessage() const {
return mMessage;
}
const std::vector<ErrorData::BacktraceRecord>& ErrorData::GetBacktrace() const {
return mBacktrace;
}
} // namespace backend

45
src/backend/ErrorData.h Normal file
View File

@@ -0,0 +1,45 @@
// Copyright 2018 The NXT Authors
//
// 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.
#ifndef BACKEND_ERRORDATA_H_
#define BACKEND_ERRORDATA_H_
#include <string>
#include <vector>
namespace backend {
class ErrorData {
public:
ErrorData();
ErrorData(std::string message);
struct BacktraceRecord {
const char* file;
const char* function;
int line;
};
void AppendBacktrace(const char* file, const char* function, int line);
const std::string& GetMessage() const;
const std::vector<BacktraceRecord>& GetBacktrace() const;
private:
std::string mMessage;
std::vector<BacktraceRecord> mBacktrace;
};
} // namespace backend
#endif // BACKEND_ERRORDATA_H_