1 /* 2 * Copyright (C) 2019 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 #ifndef INCLUDE_PERFETTO_BASE_STRING_WRITER_H_ 18 #define INCLUDE_PERFETTO_BASE_STRING_WRITER_H_ 19 20 #include <math.h> 21 #include <stdlib.h> 22 #include <string.h> 23 #include <limits> 24 25 #include "perfetto/base/logging.h" 26 #include "perfetto/base/scoped_file.h" 27 #include "perfetto/base/string_view.h" 28 29 namespace perfetto { 30 namespace base { 31 32 // A helper class which writes formatted data to a string buffer. 33 // This is used in the trace processor where we write O(GBs) of strings and 34 // sprintf is too slow. 35 class StringWriter { 36 public: 37 // Creates a string buffer from a char buffer and length. StringWriter(char * buffer,size_t size)38 StringWriter(char* buffer, size_t size) : buffer_(buffer), size_(size) {} 39 40 // Appends n instances of a char to the buffer. 41 void AppendChar(char in, size_t n = 1) { 42 PERFETTO_DCHECK(pos_ + n <= size_); 43 memset(&buffer_[pos_], in, n); 44 pos_ += n; 45 } 46 47 // Appends a length delimited string to the buffer. AppendString(const char * in,size_t n)48 void AppendString(const char* in, size_t n) { 49 PERFETTO_DCHECK(pos_ + n <= size_); 50 memcpy(&buffer_[pos_], in, n); 51 pos_ += n; 52 } 53 AppendStringView(StringView sv)54 void AppendStringView(StringView sv) { AppendString(sv.data(), sv.size()); } 55 56 // Appends a null-terminated string literal to the buffer. 57 template <size_t N> AppendLiteral(const char (& in)[N])58 inline void AppendLiteral(const char (&in)[N]) { 59 AppendString(in, N - 1); 60 } 61 62 // Appends a StringView to the buffer. AppendString(StringView data)63 void AppendString(StringView data) { AppendString(data.data(), data.size()); } 64 65 // Appends an integer to the buffer. AppendInt(int64_t value)66 void AppendInt(int64_t value) { AppendPaddedInt<'0', 0>(value); } 67 68 // Appends an integer to the buffer, padding with |padchar| if the number of 69 // digits of the integer is less than |padding|. 70 template <char padchar, uint64_t padding> AppendPaddedInt(int64_t sign_value)71 void AppendPaddedInt(int64_t sign_value) { 72 // Need to add 2 to the number of digits to account for minus sign and 73 // rounding down of digits10. 74 constexpr auto kMaxDigits = std::numeric_limits<uint64_t>::digits10 + 2; 75 constexpr auto kSizeNeeded = kMaxDigits > padding ? kMaxDigits : padding; 76 PERFETTO_DCHECK(pos_ + kSizeNeeded <= size_); 77 78 char data[kSizeNeeded]; 79 const bool negate = signbit(static_cast<double>(sign_value)); 80 uint64_t value = static_cast<uint64_t>(std::abs(sign_value)); 81 82 size_t idx; 83 for (idx = kSizeNeeded - 1; value >= 10;) { 84 char digit = value % 10; 85 value /= 10; 86 data[idx--] = digit + '0'; 87 } 88 data[idx--] = static_cast<char>(value) + '0'; 89 90 if (padding > 0) { 91 size_t num_digits = kSizeNeeded - 1 - idx; 92 for (size_t i = num_digits; i < padding; i++) { 93 data[idx--] = padchar; 94 } 95 } 96 97 if (negate) 98 buffer_[pos_++] = '-'; 99 AppendString(&data[idx + 1], kSizeNeeded - idx - 1); 100 } 101 102 // Appends a hex integer to the buffer. AppendHexInt(uint32_t value)103 void AppendHexInt(uint32_t value) { 104 // TODO(lalitm): trying to optimize this is premature given we almost never 105 // print hex ints. Reevaluate this in the future if we do print them more. 106 size_t res = static_cast<size_t>( 107 snprintf(buffer_ + pos_, size_ - pos_, "%x", value)); 108 PERFETTO_DCHECK(pos_ + res <= size_); 109 pos_ += res; 110 } 111 112 // Appends a double to the buffer. AppendDouble(double value)113 void AppendDouble(double value) { 114 // TODO(lalitm): trying to optimize this is premature given we almost never 115 // print doubles. Reevaluate this in the future if we do print them more. 116 size_t res = static_cast<size_t>( 117 snprintf(buffer_ + pos_, size_ - pos_, "%lf", value)); 118 PERFETTO_DCHECK(pos_ + res <= size_); 119 pos_ += res; 120 } 121 GetStringView()122 StringView GetStringView() { 123 PERFETTO_DCHECK(pos_ <= size_); 124 return StringView(buffer_, pos_); 125 } 126 CreateStringCopy()127 char* CreateStringCopy() { 128 char* dup = reinterpret_cast<char*>(malloc(pos_ + 1)); 129 if (dup) { 130 strncpy(dup, buffer_, pos_); 131 dup[pos_] = '\0'; 132 } 133 return dup; 134 } 135 pos()136 size_t pos() const { return pos_; } size()137 size_t size() const { return size_; } reset()138 void reset() { pos_ = 0; } 139 140 private: 141 char* buffer_ = nullptr; 142 size_t size_ = 0; 143 size_t pos_ = 0; 144 }; 145 146 } // namespace base 147 } // namespace perfetto 148 149 #endif // INCLUDE_PERFETTO_BASE_STRING_WRITER_H_ 150