pw_status: C version of Status - Create pw_Status enum with all of the status codes. - Have pw::Status implicitly convert to and from pw_Status to make transitioning between the plain enum and Status class seamless. Change-Id: If4dd659ecfd24d031c838d304298e1a3ae385b63
diff --git a/pw_status/BUILD b/pw_status/BUILD index d3ac94d..0dd9e6b 100644 --- a/pw_status/BUILD +++ b/pw_status/BUILD
@@ -1,4 +1,4 @@ -# Copyright 2019 The Pigweed Authors +# Copyright 2020 The Pigweed 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 @@ -34,7 +34,10 @@ pw_cc_test( name = "status_test", - srcs = ["status_test.cc"], + srcs = [ + "status_test.c", + "status_test.cc", + ], deps = ["//pw_status"], )
diff --git a/pw_status/BUILD.gn b/pw_status/BUILD.gn index c4e8a98..277ec33 100644 --- a/pw_status/BUILD.gn +++ b/pw_status/BUILD.gn
@@ -43,6 +43,7 @@ ":pw_status", ] sources = [ + "status_test.c", "status_test.cc", ] }
diff --git a/pw_status/public/pw_status/status.h b/pw_status/public/pw_status/status.h index 06bff9b..3196096 100644 --- a/pw_status/public/pw_status/status.h +++ b/pw_status/public/pw_status/status.h
@@ -1,4 +1,4 @@ -// Copyright 2019 The Pigweed Authors +// Copyright 2020 The Pigweed 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 @@ -11,166 +11,202 @@ // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. - #pragma once +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// This is the pw_Status enum. pw_Status is used to return the status from an +// operation. +// +// In C++, use the pw::Status class instead of the pw_Status enum. pw_Status and +// Status implicitly convert to one another and can be passed cleanly between C +// and C++ APIs. +// +// pw_Status uses the canonical Google error codes. The following was copied +// from Tensorflow and prefixed with PW_STATUS_. +typedef enum { + PW_STATUS_OK = 0, + + // The operation was cancelled (typically by the caller). + PW_STATUS_CANCELLED = 1, + + // Unknown error. An example of where this error may be returned is + // if a Status value received from another address space belongs to + // an error-space that is not known in this address space. Also, + // errors raised by APIs that do not return enough error information + // may be converted to this error. + PW_STATUS_UNKNOWN = 2, + + // Client specified an invalid argument. Note that this differs + // from FAILED_PRECONDITION. INVALID_ARGUMENT indicates arguments + // that are problematic regardless of the state of the system + // (e.g. a malformed file name). + PW_STATUS_INVALID_ARGUMENT = 3, + + // Deadline expired before operation could complete. For operations + // that change the state of the system, this error may be returned + // even if the operation has completed successfully. For example, a + // successful response from a server could have been delayed long + // enough for the deadline to expire. + PW_STATUS_DEADLINE_EXCEEDED = 4, + + // Some requested entity (e.g. file or directory) was not found. + // For privacy reasons, this code *may* be returned when the client + // does not have the access right to the entity. + PW_STATUS_NOT_FOUND = 5, + + // Some entity that we attempted to create (e.g. file or directory) + // already exists. + PW_STATUS_ALREADY_EXISTS = 6, + + // The caller does not have permission to execute the specified + // operation. PERMISSION_DENIED must not be used for rejections + // caused by exhausting some resource (use RESOURCE_EXHAUSTED + // instead for those errors). PERMISSION_DENIED must not be + // used if the caller cannot be identified (use UNAUTHENTICATED + // instead for those errors). + PW_STATUS_PERMISSION_DENIED = 7, + + // The request does not have valid authentication credentials for the + // operation. + PW_STATUS_UNAUTHENTICATED = 16, + + // Some resource has been exhausted, perhaps a per-user quota, or + // perhaps the entire filesystem is out of space. + PW_STATUS_RESOURCE_EXHAUSTED = 8, + + // Operation was rejected because the system is not in a state + // required for the operation's execution. For example, directory + // to be deleted may be non-empty, an rmdir operation is applied to + // a non-directory, etc. + // + // A litmus test that may help a service implementer in deciding + // between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE: + // (a) Use UNAVAILABLE if the client can retry just the failing call. + // (b) Use ABORTED if the client should retry at a higher-level + // (e.g. restarting a read-modify-write sequence). + // (c) Use FAILED_PRECONDITION if the client should not retry until + // the system state has been explicitly fixed. E.g. if an "rmdir" + // fails because the directory is non-empty, FAILED_PRECONDITION + // should be returned since the client should not retry unless + // they have first fixed up the directory by deleting files from it. + // (d) Use FAILED_PRECONDITION if the client performs conditional + // REST Get/Update/Delete on a resource and the resource on the + // server does not match the condition. E.g. conflicting + // read-modify-write on the same resource. + PW_STATUS_FAILED_PRECONDITION = 9, + + // The operation was aborted, typically due to a concurrency issue + // like sequencer check failures, transaction aborts, etc. + // + // See litmus test above for deciding between FAILED_PRECONDITION, + // ABORTED, and UNAVAILABLE. + PW_STATUS_ABORTED = 10, + + // Operation tried to iterate past the valid input range. E.g. seeking or + // reading past end of file. + // + // Unlike INVALID_ARGUMENT, this error indicates a problem that may + // be fixed if the system state changes. For example, a 32-bit file + // system will generate INVALID_ARGUMENT if asked to read at an + // offset that is not in the range [0,2^32-1], but it will generate + // OUT_OF_RANGE if asked to read from an offset past the current + // file size. + // + // There is a fair bit of overlap between FAILED_PRECONDITION and + // OUT_OF_RANGE. We recommend using OUT_OF_RANGE (the more specific + // error) when it applies so that callers who are iterating through + // a space can easily look for an OUT_OF_RANGE error to detect when + // they are done. + PW_STATUS_OUT_OF_RANGE = 11, + + // Operation is not implemented or not supported/enabled in this service. + PW_STATUS_UNIMPLEMENTED = 12, + + // Internal errors. Means some invariants expected by underlying + // system has been broken. If you see one of these errors, + // something is very broken. + PW_STATUS_INTERNAL = 13, + + // The service is currently unavailable. This is a most likely a + // transient condition and may be corrected by retrying with + // a backoff. + // + // See litmus test above for deciding between FAILED_PRECONDITION, + // ABORTED, and UNAVAILABLE. + PW_STATUS_UNAVAILABLE = 14, + + // Unrecoverable data loss or corruption. + PW_STATUS_DATA_LOSS = 15, + + // An extra enum entry to prevent people from writing code that + // fails to compile when a new code is added. + // + // Nobody should ever reference this enumeration entry. In particular, + // if you write C++ code that switches on this enumeration, add a default: + // case instead of a case that mentions this enumeration entry. + // + // Nobody should rely on the value listed here. It may change in the future. + PW_STATUS_DO_NOT_USE_RESERVED_FOR_FUTURE_EXPANSION_USE_DEFAULT_IN_SWITCH_INSTEAD_, +} pw_Status; + +// Returns a null-terminated string representation of the pw_Status. +const char* pw_StatusString(pw_Status status); + +#ifdef __cplusplus + +} // extern "C" + namespace pw { +// The Status class is a thin, zero-cost abstraction around the pw_Status enum. +// It initializes to Status::OK by default and adds ok() and str() methods. +// Implicit conversions are permitted between pw_Status and pw::Status. class Status { public: - // These are the canonical Google error codes (copied from Tensorflow). - enum Code { - OK = 0, + using Code = pw_Status; - // The operation was cancelled (typically by the caller). - CANCELLED = 1, + // All of the pw_Status codes are available in the Status class as, e.g. + // pw::Status::OK or pw::Status::OUT_OF_RANGE. + static constexpr Code OK = PW_STATUS_OK; + static constexpr Code CANCELLED = PW_STATUS_CANCELLED; + static constexpr Code UNKNOWN = PW_STATUS_UNKNOWN; + static constexpr Code INVALID_ARGUMENT = PW_STATUS_INVALID_ARGUMENT; + static constexpr Code DEADLINE_EXCEEDED = PW_STATUS_DEADLINE_EXCEEDED; + static constexpr Code NOT_FOUND = PW_STATUS_NOT_FOUND; + static constexpr Code ALREADY_EXISTS = PW_STATUS_ALREADY_EXISTS; + static constexpr Code PERMISSION_DENIED = PW_STATUS_PERMISSION_DENIED; + static constexpr Code UNAUTHENTICATED = PW_STATUS_UNAUTHENTICATED; + static constexpr Code RESOURCE_EXHAUSTED = PW_STATUS_RESOURCE_EXHAUSTED; + static constexpr Code FAILED_PRECONDITION = PW_STATUS_FAILED_PRECONDITION; + static constexpr Code ABORTED = PW_STATUS_ABORTED; + static constexpr Code OUT_OF_RANGE = PW_STATUS_OUT_OF_RANGE; + static constexpr Code UNIMPLEMENTED = PW_STATUS_UNIMPLEMENTED; + static constexpr Code INTERNAL = PW_STATUS_INTERNAL; + static constexpr Code UNAVAILABLE = PW_STATUS_UNAVAILABLE; + static constexpr Code DATA_LOSS = PW_STATUS_DATA_LOSS; - // Unknown error. An example of where this error may be returned is - // if a Status value received from another address space belongs to - // an error-space that is not known in this address space. Also, - // errors raised by APIs that do not return enough error information - // may be converted to this error. - UNKNOWN = 2, - - // Client specified an invalid argument. Note that this differs - // from FAILED_PRECONDITION. INVALID_ARGUMENT indicates arguments - // that are problematic regardless of the state of the system - // (e.g. a malformed file name). - INVALID_ARGUMENT = 3, - - // Deadline expired before operation could complete. For operations - // that change the state of the system, this error may be returned - // even if the operation has completed successfully. For example, a - // successful response from a server could have been delayed long - // enough for the deadline to expire. - DEADLINE_EXCEEDED = 4, - - // Some requested entity (e.g. file or directory) was not found. - // For privacy reasons, this code *may* be returned when the client - // does not have the access right to the entity. - NOT_FOUND = 5, - - // Some entity that we attempted to create (e.g. file or directory) - // already exists. - ALREADY_EXISTS = 6, - - // The caller does not have permission to execute the specified - // operation. PERMISSION_DENIED must not be used for rejections - // caused by exhausting some resource (use RESOURCE_EXHAUSTED - // instead for those errors). PERMISSION_DENIED must not be - // used if the caller cannot be identified (use UNAUTHENTICATED - // instead for those errors). - PERMISSION_DENIED = 7, - - // The request does not have valid authentication credentials for the - // operation. - UNAUTHENTICATED = 16, - - // Some resource has been exhausted, perhaps a per-user quota, or - // perhaps the entire filesystem is out of space. - RESOURCE_EXHAUSTED = 8, - - // Operation was rejected because the system is not in a state - // required for the operation's execution. For example, directory - // to be deleted may be non-empty, an rmdir operation is applied to - // a non-directory, etc. - // - // A litmus test that may help a service implementer in deciding - // between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE: - // (a) Use UNAVAILABLE if the client can retry just the failing call. - // (b) Use ABORTED if the client should retry at a higher-level - // (e.g. restarting a read-modify-write sequence). - // (c) Use FAILED_PRECONDITION if the client should not retry until - // the system state has been explicitly fixed. E.g. if an "rmdir" - // fails because the directory is non-empty, FAILED_PRECONDITION - // should be returned since the client should not retry unless - // they have first fixed up the directory by deleting files from it. - // (d) Use FAILED_PRECONDITION if the client performs conditional - // REST Get/Update/Delete on a resource and the resource on the - // server does not match the condition. E.g. conflicting - // read-modify-write on the same resource. - FAILED_PRECONDITION = 9, - - // The operation was aborted, typically due to a concurrency issue - // like sequencer check failures, transaction aborts, etc. - // - // See litmus test above for deciding between FAILED_PRECONDITION, - // ABORTED, and UNAVAILABLE. - ABORTED = 10, - - // Operation tried to iterate past the valid input range. E.g. seeking or - // reading past end of file. - // - // Unlike INVALID_ARGUMENT, this error indicates a problem that may - // be fixed if the system state changes. For example, a 32-bit file - // system will generate INVALID_ARGUMENT if asked to read at an - // offset that is not in the range [0,2^32-1], but it will generate - // OUT_OF_RANGE if asked to read from an offset past the current - // file size. - // - // There is a fair bit of overlap between FAILED_PRECONDITION and - // OUT_OF_RANGE. We recommend using OUT_OF_RANGE (the more specific - // error) when it applies so that callers who are iterating through - // a space can easily look for an OUT_OF_RANGE error to detect when - // they are done. - OUT_OF_RANGE = 11, - - // Operation is not implemented or not supported/enabled in this service. - UNIMPLEMENTED = 12, - - // Internal errors. Means some invariants expected by underlying - // system has been broken. If you see one of these errors, - // something is very broken. - INTERNAL = 13, - - // The service is currently unavailable. This is a most likely a - // transient condition and may be corrected by retrying with - // a backoff. - // - // See litmus test above for deciding between FAILED_PRECONDITION, - // ABORTED, and UNAVAILABLE. - UNAVAILABLE = 14, - - // Unrecoverable data loss or corruption. - DATA_LOSS = 15, - - // An extra enum entry to prevent people from writing code that - // fails to compile when a new code is added. - // - // Nobody should ever reference this enumeration entry. In particular, - // if you write C++ code that switches on this enumeration, add a default: - // case instead of a case that mentions this enumeration entry. - // - // Nobody should rely on the value listed here. It may change in the future. - DO_NOT_USE_RESERVED_FOR_FUTURE_EXPANSION_USE_DEFAULT_IN_SWITCH_INSTEAD_, - }; - - constexpr Status(Code code = Code::OK) : code_(code) {} + // Statuses are created with a Status::Code. + constexpr Status(Code code = OK) : code_(code) {} constexpr Status(const Status&) = default; constexpr Status& operator=(const Status&) = default; - constexpr Status& operator=(Code code) { - code_ = code; - return *this; - } + // Status implicitly converts to a Status::Code. + constexpr operator Code() const { return code_; } - constexpr Code code() const { return code_; } - constexpr bool ok() const { return code_ == Code::OK; } + // True if the status is Status::OK. + constexpr bool ok() const { return code_ == OK; } - // Returns a string representation of the Status::Code. - const char* str() const; + // Returns a null-terminated string representation of the Status. + const char* str() const { return pw_StatusString(code_); } private: Code code_; }; -constexpr bool operator==(Status lhs, Status rhs) { - return lhs.code() == rhs.code(); -} - -constexpr bool operator!=(Status lhs, Status rhs) { - return lhs.code() != rhs.code(); -} - } // namespace pw + +#endif // __cplusplus
diff --git a/pw_status/public/pw_status/status_with_size.h b/pw_status/public/pw_status/status_with_size.h index 95f544d..d3957b0 100644 --- a/pw_status/public/pw_status/status_with_size.h +++ b/pw_status/public/pw_status/status_with_size.h
@@ -1,4 +1,4 @@ -// Copyright 2019 The Pigweed Authors +// Copyright 2020 The Pigweed 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 @@ -52,8 +52,7 @@ // Creates a StatusWithSize with the provided status and size. explicit constexpr StatusWithSize(Status status, size_t size) - : StatusWithSize(size | - (static_cast<size_t>(status.code()) << kStatusShift)) {} + : StatusWithSize(size | (static_cast<size_t>(status) << kStatusShift)) {} constexpr StatusWithSize(const StatusWithSize&) = default; constexpr StatusWithSize& operator=(const StatusWithSize&) = default;
diff --git a/pw_status/status.cc b/pw_status/status.cc index 3a7e4fa..5047734 100644 --- a/pw_status/status.cc +++ b/pw_status/status.cc
@@ -1,4 +1,4 @@ -// Copyright 2019 The Pigweed Authors +// Copyright 2020 The Pigweed 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 @@ -14,15 +14,13 @@ #include "pw_status/status.h" -namespace pw { - #define PW_CASE_RETURN_ENUM_STRING(value) \ - case (value): \ + case PW_STATUS_##value: \ return #value -const char* Status::str() const { +extern "C" const char* pw_StatusString(pw_Status status) { // Status codes are ordered by assigned number (UNAUTHENTICATED is last). - switch (code_) { + switch (status) { PW_CASE_RETURN_ENUM_STRING(OK); PW_CASE_RETURN_ENUM_STRING(CANCELLED); PW_CASE_RETURN_ENUM_STRING(UNKNOWN); @@ -46,5 +44,3 @@ } #undef PW_CASE_RETURN_ENUM_STRING - -} // namespace pw
diff --git a/pw_status/status_test.c b/pw_status/status_test.c new file mode 100644 index 0000000..6a99679 --- /dev/null +++ b/pw_status/status_test.c
@@ -0,0 +1,77 @@ +// Copyright 2020 The Pigweed 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 +// +// https://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 "pw_status/status.h" + +#include <string.h> + +pw_Status PassStatusFromC(pw_Status status) { return status; } + +pw_Status PassStatusFromCpp(pw_Status status); + +#define CHECK_STATUS_FROM_CPP(status) \ + (PW_STATUS_##status != PassStatusFromCpp(PW_STATUS_##status)) + +int TestStatusFromC() { + int errors = 0; + + errors += CHECK_STATUS_FROM_CPP(OK); + errors += CHECK_STATUS_FROM_CPP(CANCELLED); + errors += CHECK_STATUS_FROM_CPP(UNKNOWN); + errors += CHECK_STATUS_FROM_CPP(INVALID_ARGUMENT); + errors += CHECK_STATUS_FROM_CPP(DEADLINE_EXCEEDED); + errors += CHECK_STATUS_FROM_CPP(NOT_FOUND); + errors += CHECK_STATUS_FROM_CPP(ALREADY_EXISTS); + errors += CHECK_STATUS_FROM_CPP(PERMISSION_DENIED); + errors += CHECK_STATUS_FROM_CPP(UNAUTHENTICATED); + errors += CHECK_STATUS_FROM_CPP(RESOURCE_EXHAUSTED); + errors += CHECK_STATUS_FROM_CPP(FAILED_PRECONDITION); + errors += CHECK_STATUS_FROM_CPP(ABORTED); + errors += CHECK_STATUS_FROM_CPP(OUT_OF_RANGE); + errors += CHECK_STATUS_FROM_CPP(UNIMPLEMENTED); + errors += CHECK_STATUS_FROM_CPP(INTERNAL); + errors += CHECK_STATUS_FROM_CPP(UNAVAILABLE); + errors += CHECK_STATUS_FROM_CPP(DATA_LOSS); + + return errors; +} + +#undef CHECK_STATUS_FROM_CPP + +#define CHECK_STATUS_STRING(status) \ + (strcmp(#status, pw_StatusString(PW_STATUS_##status)) != 0) + +int TestStatusStringsFromC() { + int errors = 0; + + errors += CHECK_STATUS_STRING(OK); + errors += CHECK_STATUS_STRING(CANCELLED); + errors += CHECK_STATUS_STRING(DEADLINE_EXCEEDED); + errors += CHECK_STATUS_STRING(NOT_FOUND); + errors += CHECK_STATUS_STRING(ALREADY_EXISTS); + errors += CHECK_STATUS_STRING(PERMISSION_DENIED); + errors += CHECK_STATUS_STRING(UNAUTHENTICATED); + errors += CHECK_STATUS_STRING(RESOURCE_EXHAUSTED); + errors += CHECK_STATUS_STRING(FAILED_PRECONDITION); + errors += CHECK_STATUS_STRING(ABORTED); + errors += CHECK_STATUS_STRING(OUT_OF_RANGE); + errors += CHECK_STATUS_STRING(UNIMPLEMENTED); + errors += CHECK_STATUS_STRING(INTERNAL); + errors += CHECK_STATUS_STRING(UNAVAILABLE); + errors += CHECK_STATUS_STRING(DATA_LOSS); + + return errors; +} + +#undef CHECK_STATUS_STRING
diff --git a/pw_status/status_test.cc b/pw_status/status_test.cc index b577cd6..98afa56 100644 --- a/pw_status/status_test.cc +++ b/pw_status/status_test.cc
@@ -1,4 +1,4 @@ -// Copyright 2019 The Pigweed Authors +// Copyright 2020 The Pigweed 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 @@ -29,13 +29,13 @@ TEST(Status, ConstructWithStatusCode) { Status status(Status::ABORTED); - EXPECT_EQ(Status::ABORTED, status.code()); + EXPECT_EQ(Status::ABORTED, status); } TEST(Status, AssignFromStatusCode) { Status status; status = Status::INTERNAL; - EXPECT_EQ(Status::INTERNAL, status.code()); + EXPECT_EQ(Status::INTERNAL, status); } TEST(Status, CompareToStatusCode) { @@ -77,5 +77,32 @@ EXPECT_STREQ("INVALID STATUS", Status(static_cast<Status::Code>(30)).str()); } +// Functions for executing the C pw_Status tests. +extern "C" { + +Status::Code PassStatusFromC(Status status); + +Status::Code PassStatusFromCpp(Status status) { return status; } + +int TestStatusFromC(void); + +int TestStatusStringsFromC(void); + +} // extern "C" + +TEST(StatusCLinkage, CallCFunctionWithStatus) { + EXPECT_EQ(Status::ABORTED, PassStatusFromC(Status::ABORTED)); + EXPECT_EQ(Status::UNKNOWN, PassStatusFromC(Status(Status::UNKNOWN))); + + EXPECT_EQ(Status(Status::NOT_FOUND), PassStatusFromC(Status::NOT_FOUND)); + EXPECT_EQ(Status(Status::OK), PassStatusFromC(Status(Status::OK))); +} + +TEST(StatusCLinkage, TestStatusFromC) { EXPECT_EQ(0, TestStatusFromC()); } + +TEST(StatusCLinkage, TestStatusStringsFromC) { + EXPECT_EQ(0, TestStatusStringsFromC()); +} + } // namespace } // namespace pw
diff --git a/pw_status/status_with_size_test.cc b/pw_status/status_with_size_test.cc index 772f8fe..ee9d56e 100644 --- a/pw_status/status_with_size_test.cc +++ b/pw_status/status_with_size_test.cc
@@ -1,4 +1,4 @@ -// Copyright 2019 The Pigweed Authors +// Copyright 2020 The Pigweed 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 @@ -55,7 +55,7 @@ for (int i = 0; i < 32; ++i) { StatusWithSize result(static_cast<Status::Code>(i), 0); EXPECT_EQ(result.ok(), i == 0); - EXPECT_EQ(i, static_cast<int>(result.status().code())); + EXPECT_EQ(i, static_cast<int>(result.status())); EXPECT_EQ(0u, result.size()); } } @@ -64,7 +64,7 @@ for (int i = 0; i < 32; ++i) { StatusWithSize result(static_cast<Status::Code>(i), i); EXPECT_EQ(result.ok(), i == 0); - EXPECT_EQ(i, static_cast<int>(result.status().code())); + EXPECT_EQ(i, static_cast<int>(result.status())); EXPECT_EQ(static_cast<size_t>(i), result.size()); } } @@ -74,7 +74,7 @@ StatusWithSize result(static_cast<Status::Code>(i), StatusWithSize::max_size()); EXPECT_EQ(result.ok(), i == 0); - EXPECT_EQ(i, static_cast<int>(result.status().code())); + EXPECT_EQ(i, static_cast<int>(result.status())); EXPECT_EQ(result.max_size(), result.size()); } }