Coverage Report

Created: 2025-10-10 06:58

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/brpc/src/butil/string_printf.cpp
Line
Count
Source
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
#include <stdio.h>                               // vsnprintf
19
#include <string.h>                              // strlen
20
#include "butil/string_printf.h"
21
22
namespace butil {
23
24
// Copyright 2012 Facebook, Inc.
25
//
26
// Licensed under the Apache License, Version 2.0 (the "License");
27
// you may not use this file except in compliance with the License.
28
// You may obtain a copy of the License at
29
//   http://www.apache.org/licenses/LICENSE-2.0
30
// Unless required by applicable law or agreed to in writing, software
31
// distributed under the License is distributed on an "AS IS" BASIS,
32
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
33
// See the License for the specific language governing permissions and
34
// limitations under the License.
35
36
namespace {
37
inline int string_printf_impl(std::string& output, const char* format,
38
0
                              va_list args) {
39
    // Tru to the space at the end of output for our output buffer.
40
    // Find out write point then inflate its size temporarily to its
41
    // capacity; we will later shrink it to the size needed to represent
42
    // the formatted string.  If this buffer isn't large enough, we do a
43
    // resize and try again.
44
45
0
    const int write_point = output.size();
46
0
    int remaining = output.capacity() - write_point;
47
0
    output.resize(output.capacity());
48
49
0
    va_list copied_args;
50
0
    va_copy(copied_args, args);
51
0
    int bytes_used = vsnprintf(&output[write_point], remaining, format,
52
0
                               copied_args);
53
0
    va_end(copied_args);
54
0
    if (bytes_used < 0) {
55
0
        return -1;
56
0
    } else if (bytes_used < remaining) {
57
        // There was enough room, just shrink and return.
58
0
        output.resize(write_point + bytes_used);
59
0
    } else {
60
0
        output.resize(write_point + bytes_used + 1);
61
0
        remaining = bytes_used + 1;
62
0
        bytes_used = vsnprintf(&output[write_point], remaining, format, args);
63
0
        if (bytes_used + 1 != remaining) {
64
0
            return -1;
65
0
        }
66
0
        output.resize(write_point + bytes_used);
67
0
    }
68
0
    return 0;
69
0
}
70
71
inline int string_printf_impl(std::string& output,  size_t hint,
72
0
                              const char* format, va_list args) {
73
0
    if (hint > output.capacity()) {
74
0
        output.reserve(hint);
75
0
    }
76
0
    return string_printf_impl(output,  format, args);
77
0
}
78
}  // end anonymous namespace
79
80
0
std::string string_printf(const char* format, ...) {
81
    // snprintf will tell us how large the output buffer should be, but
82
    // we then have to call it a second time, which is costly. By
83
    // guestimating the final size, we avoid the double snprintf in many
84
    // cases, resulting in a performance win. We use this constructor
85
    // of std::string to avoid a double allocation, though it does pad
86
    // the resulting string with nul bytes. Our guestimation is twice
87
    // the format string size, or 32 bytes, whichever is larger.  This
88
    // is a heuristic that doesn't affect correctness but attempts to be
89
    // reasonably fast for the most common cases.
90
0
    std::string ret;
91
0
    va_list ap;
92
0
    va_start(ap, format);
93
0
    if (string_printf_impl(ret, std::max(32UL, strlen(format) * 2),
94
0
                           format, ap) != 0) {
95
0
        ret.clear();
96
0
    }
97
0
    va_end(ap);
98
0
    return ret;
99
0
}
100
101
0
std::string string_printf(size_t hint_size, const char* format, ...) {
102
    // snprintf will tell us how large the output buffer should be, but
103
    // we then have to call it a second time, which is costly. By
104
    // passing the hint size of formatted string, we avoid the double
105
    // snprintf in many cases, resulting in a performance win. We use
106
    // this constructor  of std::string to avoid a double allocation,
107
    // though it does pad the resulting string with nul bytes.
108
0
    std::string ret;
109
0
    va_list ap;
110
0
    va_start(ap, format);
111
0
    if (string_printf_impl(ret, std::max(hint_size, strlen(format) * 2),
112
0
                           format, ap) != 0) {
113
0
        ret.clear();
114
0
    }
115
0
    va_end(ap);
116
0
    return ret;
117
0
}
118
119
// Basic declarations; allow for parameters of strings and string
120
// pieces to be specified.
121
0
int string_appendf(std::string* output, const char* format, ...) {
122
0
    va_list ap;
123
0
    va_start(ap, format);
124
0
    const int rc = string_vappendf(output, format, ap);
125
0
    va_end(ap);
126
0
    return rc;
127
0
}
128
129
0
int string_vappendf(std::string* output, const char* format, va_list args) {
130
0
    const size_t old_size = output->size();
131
0
    const int rc = string_printf_impl(*output, format, args);
132
0
    if (rc != 0) {
133
0
        output->resize(old_size);
134
0
    }
135
0
    return rc;
136
0
}
137
138
0
int string_printf(std::string* output, const char* format, ...) {
139
0
    va_list ap;
140
0
    va_start(ap, format);
141
0
    const int rc = string_vprintf(output, format, ap);
142
0
    va_end(ap);
143
0
    return rc;
144
0
};
145
146
0
int string_vprintf(std::string* output, const char* format, va_list args) {
147
0
    output->clear();
148
0
    const int rc = string_printf_impl(*output, format, args);
149
0
    if (rc != 0) {
150
0
        output->clear();
151
0
    }
152
0
    return rc;
153
0
};
154
155
}  // namespace butil