Home | History | Annotate | Download | only in base
      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.
     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.
     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 
     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>
     58   inline void AppendLiteral(const char (&in)[N]) {
     59     AppendString(in, N - 1);
     60   }
     61 
     62   // Appends a StringView to the buffer.
     63   void AppendString(StringView data) { AppendString(data.data(), data.size()); }
     64 
     65   // Appends an integer to the buffer.
     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>
     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.
    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.
    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 
    122   StringView GetStringView() {
    123     PERFETTO_DCHECK(pos_ <= size_);
    124     return StringView(buffer_, pos_);
    125   }
    126 
    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 
    136   size_t pos() const { return pos_; }
    137   size_t size() const { return size_; }
    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