summaryrefslogtreecommitdiff
path: root/system/gd/common/strings.h
blob: 01944f55ebf9637ecbfa5247301ed405fda8a4cf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/*
 * Copyright 2020 The Android Open Source Project
 *
 * 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
 *
 *      http://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.
 */

#pragma once

#include <limits.h>
#include <string.h>

#include <charconv>
#include <chrono>
#include <iomanip>
#include <iterator>
#include <limits>
#include <optional>
#include <sstream>
#include <string>
#include <type_traits>
#include <vector>

#include "common/type_helper.h"
#include "os/log.h"

namespace bluetooth {
namespace common {

template <typename T>
inline std::string ToString(const T& value) {
  std::stringstream tmp;
  tmp << value;
  return tmp.str();
}

// Convert number into a hex string prefixed with 0x
template <typename T>
std::string ToHexString(T x) {
  if (x < 0) {
    if (x == INT_MIN) return "INT_MIN";
    return "-" + ToHexString(-x);
  }
  std::stringstream tmp;
  tmp << "0x" << std::internal << std::hex << std::setfill('0') << std::setw(sizeof(T) * 2) << (unsigned long)x;
  return tmp.str();
}

template <>
inline std::string ToHexString<>(signed long x) {
  if (x < 0) {
    if (x == LONG_MIN) return "LONG_MIN";
    return "-" + ToHexString<signed long>(-x);
  }
  std::stringstream tmp;
  tmp << "0x" << std::internal << std::hex << std::setfill('0') << std::setw(sizeof(signed long) * 2)
      << (unsigned long)x;
  return tmp.str();
}

template <>
inline std::string ToHexString<>(unsigned int x) {
  std::stringstream tmp;
  tmp << "0x" << std::internal << std::hex << std::setfill('0') << std::setw(sizeof(unsigned int) * 2)
      << (unsigned long)x;
  return tmp.str();
}

// Convert value into a hex decimal formatted string in lower case, prefixed with 0s
template <class InputIt>
std::string ToHexString(InputIt first, InputIt last) {
  static_assert(
      std::is_same_v<typename std::iterator_traits<InputIt>::value_type, uint8_t>, "Must use uint8_t iterator");
  std::stringstream ss;
  for (InputIt it = first; it != last; ++it) {
    // +(byte) to prevent an uint8_t to be interpreted as a char
    ss << std::hex << std::setw(2) << std::setfill('0') << +(*it);
  }
  return ss.str();
}
// Convenience method for normal cases and initializer list, e.g. ToHexString({0x12, 0x34, 0x56, 0xab})
std::string ToHexString(const std::vector<uint8_t>& value);

// Return true if |str| is a valid hex demical strings contains only hex decimal chars [0-9a-fA-F]
bool IsValidHexString(const std::string& str);

// Parse |str| into a vector of uint8_t, |str| must contains only hex decimal
std::optional<std::vector<uint8_t>> FromHexString(const std::string& str);

// Remove whitespace from both ends of the |str|, returning a copy
std::string StringTrim(std::string str);

// Split |str| into at most |max_token| tokens delimited by |delim|, unlimited tokens when |max_token| is 0
std::vector<std::string> StringSplit(const std::string& str, const std::string& delim, size_t max_token = 0);

// Join |strings| into a single string using |delim|
std::string StringJoin(const std::vector<std::string>& strings, const std::string& delim);

// Various number comparison functions, only base 10 is supported
std::optional<int64_t> Int64FromString(const std::string& str);
std::string ToString(int64_t value);
std::optional<uint64_t> Uint64FromString(const std::string& str);
std::string ToString(uint64_t value);
std::optional<bool> BoolFromString(const std::string& str);
std::string ToString(bool value);

// Migrate this method to std::format when C++20 becomes available
// printf like formatting to std::string
// format must contains format information, to print a string use StringFormat("%s", str)
template <typename... Args>
std::string StringFormat(const std::string& format, Args... args) {
  auto size = std::snprintf(nullptr, 0, format.c_str(), args...);
  ASSERT_LOG(size >= 0, "return value %d, error %d, text '%s'", size, errno, strerror(errno));
  // Add 1 for terminating null byte
  std::vector<char> buffer(size + 1);
  auto actual_size = std::snprintf(buffer.data(), buffer.size(), format.c_str(), args...);
  ASSERT_LOG(
      size == actual_size,
      "asked size %d, actual size %d, error %d, text '%s'",
      size,
      actual_size,
      errno,
      strerror(errno));
  // Exclude the terminating null byte
  return std::string(buffer.data(), size);
}

inline std::string StringFormatTime(const std::string& format, const struct std::tm& tm) {
  std::ostringstream os;
  os << std::put_time(&tm, format.c_str());
  return os.str();
}

inline std::string StringFormatTimeWithMilliseconds(
    const std::string& format,
    std::chrono::time_point<std::chrono::system_clock> time_point,
    struct tm* (*calendar_to_tm)(const time_t* timep) = localtime) {
  std::time_t epoch_time = std::chrono::system_clock::to_time_t(time_point);
  auto millis = time_point.time_since_epoch() / std::chrono::milliseconds(1) % 1000;
  std::tm tm = *calendar_to_tm(&epoch_time);
  std::ostringstream os;
  os << std::put_time(&tm, format.c_str()) << StringFormat(".%03u", millis);
  return os.str();
}

}  // namespace common
}  // namespace bluetooth