1 /*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "perfetto/base/status.h"
18
19 #include <algorithm>
20 #include <cstdarg>
21 #include <cstdio>
22 #include <string>
23 #include <utility>
24
25 namespace perfetto::base {
26
ErrStatus(const char * format,...)27 Status ErrStatus(const char* format, ...) {
28 std::string buf;
29 buf.resize(1024);
30 for (;;) {
31 va_list ap;
32 va_start(ap, format);
33 int N = vsnprintf(buf.data(), buf.size() - 1, format, ap);
34 va_end(ap);
35
36 if (N <= 0) {
37 buf = "[printf format error]";
38 break;
39 }
40
41 auto sN = static_cast<size_t>(N);
42 if (sN > buf.size() - 1) {
43 // Indicates that the string was truncated and sN is the "number of
44 // non-null bytes which would be needed to fit the result". This is the
45 // C99 standard behaviour in the case of truncation. In that case, resize
46 // the buffer to match the returned value (with + 1 for the null
47 // terminator) and try again.
48 buf.resize(sN + 1);
49 continue;
50 }
51 if (sN == buf.size() - 1) {
52 // Indicates that the string was likely truncated and sN is just the
53 // number of bytes written into the string. This is the behaviour of
54 // non-standard compilers (MSVC) etc. In that case, just double the
55 // storage and try again.
56 buf.resize(sN * 2);
57 continue;
58 }
59
60 // Otherwise, indicates the string was written successfully: we need to
61 // resize to match the number of non-null bytes and return.
62 buf.resize(sN);
63 break;
64 }
65 return Status(std::move(buf));
66 }
67
GetPayload(std::string_view type_url) const68 std::optional<std::string_view> Status::GetPayload(
69 std::string_view type_url) const {
70 if (ok()) {
71 return std::nullopt;
72 }
73 for (const auto& kv : payloads_) {
74 if (kv.type_url == type_url) {
75 return kv.payload;
76 }
77 }
78 return std::nullopt;
79 }
80
SetPayload(std::string_view type_url,std::string value)81 void Status::SetPayload(std::string_view type_url, std::string value) {
82 if (ok()) {
83 return;
84 }
85 for (auto& kv : payloads_) {
86 if (kv.type_url == type_url) {
87 kv.payload = value;
88 return;
89 }
90 }
91 payloads_.push_back(Payload{std::string(type_url), std::move(value)});
92 }
93
ErasePayload(std::string_view type_url)94 bool Status::ErasePayload(std::string_view type_url) {
95 if (ok()) {
96 return false;
97 }
98 auto it = std::remove_if(
99 payloads_.begin(), payloads_.end(),
100 [type_url](const Payload& p) { return p.type_url == type_url; });
101 bool erased = it != payloads_.end();
102 payloads_.erase(it, payloads_.end());
103 return erased;
104 }
105
106 } // namespace perfetto::base
107