chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
cc_library(
|
||||
pretty_log
|
||||
SRCS pretty_log.cc
|
||||
DEPS phi common)
|
||||
cc_library(
|
||||
string_helper
|
||||
SRCS string_helper.cc
|
||||
DEPS phi common)
|
||||
@@ -0,0 +1,17 @@
|
||||
// Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#include "paddle/utils/string/pretty_log.h"
|
||||
|
||||
#include "paddle/common/flags.h"
|
||||
@@ -0,0 +1,88 @@
|
||||
// Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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 <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "paddle/common/flags.h"
|
||||
#include "paddle/utils/string/printf.h"
|
||||
|
||||
namespace paddle {
|
||||
|
||||
namespace string {
|
||||
|
||||
inline std::string black() { return "\e[30m"; }
|
||||
inline std::string red() { return "\e[31m"; }
|
||||
inline std::string b_red() { return "\e[41m"; }
|
||||
inline std::string green() { return "\e[32m"; }
|
||||
inline std::string yellow() { return "\e[33m"; }
|
||||
inline std::string blue() { return "\e[34m"; }
|
||||
inline std::string purple() { return "\e[35m"; }
|
||||
inline std::string cyan() { return "\e[36m"; }
|
||||
inline std::string light_gray() { return "\e[37m"; }
|
||||
inline std::string white() { return "\e[37m"; }
|
||||
inline std::string light_red() { return "\e[91m"; }
|
||||
inline std::string dim() { return "\e[2m"; }
|
||||
inline std::string bold() { return "\e[1m"; }
|
||||
inline std::string underline() { return "\e[4m"; }
|
||||
inline std::string blink() { return "\e[5m"; }
|
||||
inline std::string reset() { return "\e[0m"; }
|
||||
|
||||
using TextBlock = std::pair<std::string, std::string>;
|
||||
|
||||
struct Style {
|
||||
static std::string info() { return black(); }
|
||||
static std::string warn() { return b_red(); }
|
||||
static std::string suc() { return green(); }
|
||||
static std::string H1() { return bold() + purple(); }
|
||||
static std::string H2() { return green(); }
|
||||
static std::string H3() { return green(); }
|
||||
static std::string detail() { return light_gray(); }
|
||||
};
|
||||
|
||||
template <typename... Args>
|
||||
static void PrettyLogEndl(const std::string &style,
|
||||
const char *fmt,
|
||||
const Args &...args) {
|
||||
std::cerr << style << Sprintf(fmt, args...) << reset() << std::endl;
|
||||
}
|
||||
template <typename... Args>
|
||||
static void PrettyLog(const std::string &style,
|
||||
const char *fmt,
|
||||
const Args &...args) {
|
||||
std::cerr << style << Sprintf(fmt, args...) << reset();
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
static void PrettyLogInfo(const char *fmt, const Args &...args) {
|
||||
PrettyLogEndl(Style::info(), fmt, args...);
|
||||
}
|
||||
template <typename... Args>
|
||||
static void PrettyLogDetail(const char *fmt, const Args &...args) {
|
||||
PrettyLogEndl(Style::detail(), fmt, args...);
|
||||
}
|
||||
template <typename... Args>
|
||||
static void PrettyLogH1(const char *fmt, const Args &...args) {
|
||||
PrettyLogEndl(Style::H1(), fmt, args...);
|
||||
}
|
||||
template <typename... Args>
|
||||
static void PrettyLogH2(const char *fmt, const Args &...args) {
|
||||
PrettyLogEndl(Style::H2(), fmt, args...);
|
||||
}
|
||||
|
||||
} // namespace string
|
||||
} // namespace paddle
|
||||
@@ -0,0 +1,132 @@
|
||||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// Compared with std::stringstream, there are primary purpose of
|
||||
// string::Printf:
|
||||
//
|
||||
// 1. Type-safe printing, with why and how explained in
|
||||
// http://www.drdobbs.com/stringprintf-a-typesafe-printf-family-fo/184401999.
|
||||
// Implementation includes
|
||||
//
|
||||
// https://github.com/c42f/tinyformat
|
||||
// boost::format
|
||||
// std::stringstream
|
||||
//
|
||||
// std::stringstream is not convenient enough in many cases. For example:
|
||||
//
|
||||
// std::cout << std::setprecision(2) << std::fixed << 1.23456 << "\n";
|
||||
//
|
||||
// boost::format is the most convenient one. We can have
|
||||
//
|
||||
// std::cout << format("%2% %1%") % 36 % 77;
|
||||
//
|
||||
// or
|
||||
//
|
||||
// format fmter("%2% %1%");
|
||||
// fmter % 36; fmter % 77;
|
||||
// std::cout << fmter.c_str();
|
||||
//
|
||||
// But the overloading of % might be overkilling and it would be
|
||||
// more efficient if it can write to std::cout directly.
|
||||
//
|
||||
// tinyformat has an interface compatible with the C-printf style,
|
||||
// and it can writes to a stream or returns a std::string:
|
||||
//
|
||||
// std::cout << tfm::printf(
|
||||
// "%s, %s %d, %.2d:%.2d\n",
|
||||
// weekday, month, day, hour, min);
|
||||
//
|
||||
// or
|
||||
//
|
||||
// tfm::format(std::cout,
|
||||
// "%s, %s %d, %.2d:%.2d\n",
|
||||
// weekday, month, day, hour, min);
|
||||
//
|
||||
// 2. High-performance -- most printed strings are not too long and
|
||||
// doesn't need dynamic memory allocation. Many StringPrintf
|
||||
// implementations doesn't enforce type-safe, but are
|
||||
// high-performance, including
|
||||
//
|
||||
// https://developers.google.com/optimization/reference/base/stringprintf/
|
||||
// https://github.com/adobe/chromium/blob/master/base/stringprintf.h
|
||||
// https://github.com/google/protobuf/blob/master/src/google/protobuf/stubs/stringprintf.h
|
||||
//
|
||||
// According to
|
||||
// https://github.com/c42f/tinyformat#compile-time-and-code-bloat,
|
||||
// boost::format runs too slow and results in large executable binary
|
||||
// files. So here we port tinyformat.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "paddle/utils/string/tinyformat/tinyformat.h" // https://github.com/c42f/tinyformat
|
||||
|
||||
namespace paddle {
|
||||
namespace string {
|
||||
|
||||
template <typename... Args>
|
||||
void Fprintf(std::ostream& out, const char* fmt, const Args&... args) {
|
||||
try {
|
||||
tinyformat::vformat(out, fmt, tinyformat::makeFormatList(args...));
|
||||
} catch (const tinyformat::detail::FormatError&) {
|
||||
out << fmt;
|
||||
}
|
||||
}
|
||||
|
||||
inline std::string Sprintf() { return ""; }
|
||||
|
||||
template <typename... Args>
|
||||
std::string Sprintf(const Args&... args) {
|
||||
std::ostringstream oss;
|
||||
Fprintf(oss, "%s", args...);
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
std::string Sprintf(const char* fmt, const Args&... args) {
|
||||
try {
|
||||
std::ostringstream oss;
|
||||
Fprintf(oss, fmt, args...);
|
||||
return oss.str();
|
||||
} catch (const tinyformat::detail::FormatError&) {
|
||||
return fmt;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void Printf(const char* fmt, const Args&... args) {
|
||||
Fprintf(std::cout, fmt, args...);
|
||||
}
|
||||
|
||||
inline std::string HumanReadableSize(double f_size) {
|
||||
size_t i = 0;
|
||||
double orig = f_size;
|
||||
const std::vector<std::string> units(
|
||||
{"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"});
|
||||
while (f_size >= 1024) {
|
||||
f_size /= 1024;
|
||||
i++;
|
||||
}
|
||||
if (i >= units.size()) {
|
||||
return Sprintf("%fB", orig);
|
||||
}
|
||||
return Sprintf("%f%s", f_size, units[i]);
|
||||
}
|
||||
|
||||
} // namespace string
|
||||
} // namespace paddle
|
||||
@@ -0,0 +1,37 @@
|
||||
/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved.
|
||||
|
||||
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 <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace paddle {
|
||||
namespace string {
|
||||
|
||||
static inline std::vector<std::string> Split(std::string const& original,
|
||||
char separator) {
|
||||
std::vector<std::string> results;
|
||||
std::string token;
|
||||
std::istringstream is(original);
|
||||
while (std::getline(is, token, separator)) {
|
||||
if (!token.empty()) {
|
||||
results.push_back(token);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
} // namespace string
|
||||
} // namespace paddle
|
||||
@@ -0,0 +1,87 @@
|
||||
// Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#include "paddle/utils/string/string_helper.h"
|
||||
|
||||
#include <cctype>
|
||||
#include <cstdio>
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
namespace paddle::string {
|
||||
|
||||
// remove leading and tailing spaces
|
||||
std::string trim_spaces(const std::string& str) {
|
||||
const char* p = str.c_str();
|
||||
|
||||
while (*p != 0 && isspace(*p)) {
|
||||
p++;
|
||||
}
|
||||
|
||||
size_t len = strlen(p);
|
||||
|
||||
while (len > 0 && isspace(p[len - 1])) {
|
||||
len--;
|
||||
}
|
||||
|
||||
return std::string(p, len);
|
||||
}
|
||||
|
||||
std::string erase_spaces(const std::string& str) {
|
||||
std::string result;
|
||||
result.reserve(str.size());
|
||||
const char* p = str.c_str();
|
||||
while (*p != 0) {
|
||||
if (!isspace(*p)) {
|
||||
result.append(p, 1);
|
||||
}
|
||||
++p;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ends_with(std::string const& input, std::string const& test) {
|
||||
if (test.size() > input.size()) return false;
|
||||
return std::equal(test.rbegin(), test.rend(), input.rbegin());
|
||||
}
|
||||
|
||||
// A helper class for reading lines from file.
|
||||
// A line buffer is maintained. It
|
||||
// doesn't need to know the maximum possible length of a line.
|
||||
char* LineFileReader::getdelim(FILE* f, char delim) {
|
||||
#ifndef _WIN32
|
||||
int32_t ret =
|
||||
static_cast<int32_t>(::getdelim(&_buffer, &_buf_size, delim, f));
|
||||
|
||||
if (ret >= 0) {
|
||||
if (ret >= 1 && _buffer[ret - 1] == delim) {
|
||||
_buffer[--ret] = 0;
|
||||
}
|
||||
|
||||
_length = static_cast<size_t>(ret);
|
||||
return _buffer;
|
||||
} else {
|
||||
_length = 0;
|
||||
int code = feof(f);
|
||||
(void)code;
|
||||
assert(code);
|
||||
return nullptr;
|
||||
}
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace paddle::string
|
||||
@@ -0,0 +1,394 @@
|
||||
// Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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 <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "paddle/common/macros.h"
|
||||
|
||||
namespace paddle {
|
||||
namespace string {
|
||||
|
||||
inline size_t count_spaces(const char* s) {
|
||||
size_t count = 0;
|
||||
|
||||
while (*s != 0 && isspace(*s++)) {
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
inline size_t count_nonspaces(const char* s) {
|
||||
size_t count = 0;
|
||||
|
||||
while (*s != 0 && !isspace(*s++)) {
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
template <class... ARGS>
|
||||
void format_string_append(std::string& str, // NOLINT
|
||||
const char* fmt, // NOLINT
|
||||
ARGS&&... args) {
|
||||
int len = snprintf(NULL, 0, fmt, args...);
|
||||
assert(len == 0);
|
||||
size_t oldlen = str.length();
|
||||
str.resize(oldlen + len + 1);
|
||||
int new_len =
|
||||
snprintf(&str[oldlen], (size_t)len + 1, fmt, args...); // NOLINT
|
||||
(void)new_len;
|
||||
assert(new_len == len);
|
||||
str.resize(oldlen + len);
|
||||
}
|
||||
|
||||
template <class... ARGS>
|
||||
void format_string_append(std::string& str, // NOLINT
|
||||
const std::string& fmt, // NOLINT
|
||||
ARGS&&... args) {
|
||||
format_string_append(str, fmt.c_str(), args...);
|
||||
}
|
||||
|
||||
template <class... ARGS>
|
||||
std::string format_string(const char* fmt, ARGS&&... args) {
|
||||
std::string str;
|
||||
format_string_append(str, fmt, args...);
|
||||
return str;
|
||||
}
|
||||
|
||||
template <class... ARGS>
|
||||
std::string format_string(const std::string& fmt, ARGS&&... args) {
|
||||
return format_string(fmt.c_str(), args...);
|
||||
}
|
||||
|
||||
// remove leading and tailing spaces
|
||||
std::string trim_spaces(const std::string& str);
|
||||
|
||||
// erase all spaces in str
|
||||
PADDLE_API std::string erase_spaces(const std::string& str);
|
||||
|
||||
inline int str_to_float(const char* str, float* v) {
|
||||
const char* head = str;
|
||||
char* cursor = NULL;
|
||||
int index = 0;
|
||||
while (*(head += count_spaces(head)) != 0) {
|
||||
v[index++] = std::strtof(head, &cursor);
|
||||
if (head == cursor) {
|
||||
break;
|
||||
}
|
||||
head = cursor;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
inline float* str_to_float(const std::string& str) {
|
||||
return reinterpret_cast<float*>(const_cast<char*>(str.c_str()));
|
||||
}
|
||||
|
||||
inline float* str_to_float(const char* str) {
|
||||
return reinterpret_cast<float*>(const_cast<char*>(str));
|
||||
}
|
||||
|
||||
// checks whether the test string is a suffix of the input string.
|
||||
bool ends_with(std::string const& input, std::string const& test);
|
||||
|
||||
// split string by delim
|
||||
template <class T = std::string>
|
||||
std::vector<T> split_string(const std::string& str, const std::string& delim) {
|
||||
size_t pre_pos = 0;
|
||||
size_t pos = 0;
|
||||
std::string tmp_str;
|
||||
std::vector<T> res_list;
|
||||
res_list.clear();
|
||||
if (str.empty()) {
|
||||
return res_list;
|
||||
}
|
||||
while ((pos = str.find(delim, pre_pos)) != std::string::npos) {
|
||||
tmp_str.assign(str, pre_pos, pos - pre_pos);
|
||||
res_list.push_back(tmp_str);
|
||||
pre_pos = pos + delim.size();
|
||||
}
|
||||
tmp_str.assign(str, pre_pos, str.length() - pre_pos);
|
||||
res_list.push_back(tmp_str);
|
||||
return res_list;
|
||||
}
|
||||
|
||||
// split string by spaces. Leading and tailing spaces are ignored. Consecutive
|
||||
// spaces are treated as one delim.
|
||||
template <class T = std::string>
|
||||
std::vector<T> split_string(const std::string& str) {
|
||||
std::vector<T> list;
|
||||
const char* p;
|
||||
int pre_pos = 0;
|
||||
int pos = 0;
|
||||
std::string tmp_str;
|
||||
if (str.empty()) {
|
||||
return list;
|
||||
}
|
||||
for (p = str.c_str(); *p != 0;) {
|
||||
if (!isspace(*p)) {
|
||||
pos = pre_pos;
|
||||
p++;
|
||||
|
||||
while (*p != 0 && !isspace(*p)) {
|
||||
pos++;
|
||||
p++;
|
||||
}
|
||||
tmp_str.assign(str, pre_pos, pos - pre_pos + 1);
|
||||
list.push_back(tmp_str);
|
||||
pre_pos = pos + 1;
|
||||
} else {
|
||||
pre_pos++;
|
||||
p++;
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
template <class Container>
|
||||
std::string join_strings(const Container& strs, char delim) {
|
||||
std::string str;
|
||||
|
||||
size_t i = 0;
|
||||
for (auto& elem : strs) {
|
||||
if (i > 0) {
|
||||
str += delim;
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
ss << elem;
|
||||
str += ss.str();
|
||||
++i;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
template <class Container>
|
||||
std::string join_strings(const Container& strs, const std::string& delim) {
|
||||
std::string str;
|
||||
|
||||
size_t i = 0;
|
||||
for (auto& elem : strs) {
|
||||
if (i > 0) {
|
||||
str += delim;
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
ss << elem;
|
||||
str += ss.str();
|
||||
++i;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
template <class Container, class DelimT, class ConvertFunc>
|
||||
std::string join_strings(const Container& strs,
|
||||
DelimT&& delim,
|
||||
ConvertFunc&& func) {
|
||||
std::stringstream ss;
|
||||
size_t i = 0;
|
||||
for (const auto& elem : strs) {
|
||||
if (i > 0) {
|
||||
ss << delim;
|
||||
}
|
||||
ss << func(elem);
|
||||
++i;
|
||||
}
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
struct str_ptr {
|
||||
const char* ptr;
|
||||
size_t len;
|
||||
str_ptr(const char* p, size_t n) : ptr(p), len(n) {}
|
||||
str_ptr(str_ptr& other) {
|
||||
ptr = other.ptr;
|
||||
len = other.len;
|
||||
}
|
||||
str_ptr(str_ptr&& other) {
|
||||
ptr = other.ptr;
|
||||
len = other.len;
|
||||
}
|
||||
size_t find_ptr(const char c) {
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
if (ptr[i] == c) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
std::string to_string(void) { return std::string(ptr, len); }
|
||||
};
|
||||
|
||||
struct str_ptr_stream {
|
||||
char* ptr = NULL;
|
||||
char* end = NULL;
|
||||
str_ptr_stream() {}
|
||||
explicit str_ptr_stream(const str_ptr& p) { reset(p.ptr, p.len); }
|
||||
void reset(const str_ptr& p) { reset(p.ptr, p.len); }
|
||||
void reset(const char* p, size_t len) {
|
||||
ptr = const_cast<char*>(p);
|
||||
end = ptr + len;
|
||||
}
|
||||
char* cursor(void) { return ptr; }
|
||||
char* finish(void) { return end; }
|
||||
void set_cursor(char* p) { ptr = p; }
|
||||
bool is_finish(void) { return (ptr == end); }
|
||||
template <typename T>
|
||||
str_ptr_stream& operator>>(T& x) {
|
||||
*this >> x;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
inline str_ptr_stream& operator>>(str_ptr_stream& ar, float& c) {
|
||||
char* next = NULL;
|
||||
c = strtof(ar.cursor(), &next);
|
||||
ar.set_cursor(std::min(++next, ar.finish()));
|
||||
return ar;
|
||||
}
|
||||
inline str_ptr_stream& operator>>(str_ptr_stream& ar, double& c) {
|
||||
char* next = NULL;
|
||||
c = strtod(ar.cursor(), &next);
|
||||
ar.set_cursor(std::min(++next, ar.finish()));
|
||||
return ar;
|
||||
}
|
||||
inline str_ptr_stream& operator>>(str_ptr_stream& ar, int32_t& c) {
|
||||
char* next = NULL;
|
||||
c = strtol(ar.cursor(), &next, 10);
|
||||
ar.set_cursor(std::min(++next, ar.finish()));
|
||||
return ar;
|
||||
}
|
||||
inline str_ptr_stream& operator>>(str_ptr_stream& ar, uint32_t& c) {
|
||||
char* next = NULL;
|
||||
c = strtoul(ar.cursor(), &next, 10);
|
||||
ar.set_cursor(std::min(++next, ar.finish()));
|
||||
return ar;
|
||||
}
|
||||
inline str_ptr_stream& operator>>(str_ptr_stream& ar, uint64_t& c) {
|
||||
char* next = NULL;
|
||||
c = strtoul(ar.cursor(), &next, 10);
|
||||
ar.set_cursor(std::min(++next, ar.finish()));
|
||||
return ar;
|
||||
}
|
||||
inline str_ptr_stream& operator>>(str_ptr_stream& ar, int64_t& c) {
|
||||
char* next = NULL;
|
||||
c = strtoll(ar.cursor(), &next, 10);
|
||||
ar.set_cursor(std::min(++next, ar.finish()));
|
||||
return ar;
|
||||
}
|
||||
inline int split_string_ptr(const char* str,
|
||||
size_t len,
|
||||
char delim,
|
||||
std::vector<str_ptr>* values) {
|
||||
if (len <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int num = 0;
|
||||
const char* p = str;
|
||||
const char* end = str + len;
|
||||
const char* last = str;
|
||||
while (p < end) {
|
||||
if (*p != delim) {
|
||||
++p;
|
||||
continue;
|
||||
}
|
||||
values->emplace_back(last, static_cast<size_t>(p - last));
|
||||
++num;
|
||||
++p;
|
||||
// skip continue delim
|
||||
while (*p == delim) {
|
||||
++p;
|
||||
}
|
||||
last = p;
|
||||
}
|
||||
if (p > last) {
|
||||
values->emplace_back(last, static_cast<size_t>(p - last));
|
||||
++num;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
inline int split_string_ptr(const char* str,
|
||||
size_t len,
|
||||
char delim,
|
||||
std::vector<str_ptr>* values,
|
||||
int max_num) {
|
||||
if (len <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int num = 0;
|
||||
const char* p = str;
|
||||
const char* end = str + len;
|
||||
const char* last = str;
|
||||
while (p < end) {
|
||||
if (*p != delim) {
|
||||
++p;
|
||||
continue;
|
||||
}
|
||||
values->emplace_back(last, static_cast<size_t>(p - last));
|
||||
++num;
|
||||
++p;
|
||||
if (num >= max_num) {
|
||||
return num;
|
||||
}
|
||||
// skip continue delim
|
||||
while (*p == delim) {
|
||||
++p;
|
||||
}
|
||||
last = p;
|
||||
}
|
||||
if (p > last) {
|
||||
values->emplace_back(last, static_cast<size_t>(p - last));
|
||||
++num;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
// A helper class for reading lines from file. A line buffer is maintained. It
|
||||
// doesn't need to know the maximum possible length of a line.
|
||||
|
||||
class LineFileReader {
|
||||
public:
|
||||
LineFileReader() {}
|
||||
LineFileReader(LineFileReader&&) = delete;
|
||||
LineFileReader(const LineFileReader&) = delete;
|
||||
~LineFileReader() { ::free(_buffer); }
|
||||
char* getline(FILE* f) { return this->getdelim(f, '\n'); }
|
||||
char* getdelim(FILE* f, char delim);
|
||||
char* get() { return _buffer; }
|
||||
size_t length() { return _length; }
|
||||
|
||||
private:
|
||||
char* _buffer = NULL;
|
||||
size_t _buf_size = 0;
|
||||
size_t _length = 0;
|
||||
};
|
||||
} // namespace string
|
||||
} // namespace paddle
|
||||
@@ -0,0 +1,916 @@
|
||||
// Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// tinyformat.h
|
||||
// Copyright (C) 2011, Chris Foster [chris42f (at) gmail (d0t) com]
|
||||
//
|
||||
// Boost Software License - Version 1.0
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person or organization
|
||||
// obtaining a copy of the software and accompanying documentation covered by
|
||||
// this license (the "Software") to use, reproduce, display, distribute,
|
||||
// execute, and transmit the Software, and to prepare derivative works of the
|
||||
// Software, and to permit third-parties to whom the Software is furnished to
|
||||
// do so, all subject to the following:
|
||||
//
|
||||
// The copyright notices in the Software and this entire statement, including
|
||||
// the above license grant, this restriction and the following disclaimer,
|
||||
// must be included in all copies of the Software, in whole or in part, and
|
||||
// all derivative works of the Software, unless such copies or derivative
|
||||
// works are solely in the form of machine-executable object code generated by
|
||||
// a source language processor.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Tinyformat: A minimal type safe printf replacement
|
||||
//
|
||||
// tinyformat.h is a type safe printf replacement library in a single C++
|
||||
// header file. Design goals include:
|
||||
//
|
||||
// * Type safety and extensibility for user defined types.
|
||||
// * C99 printf() compatibility, to the extent possible using std::ostream
|
||||
// * Simplicity and minimalism. A single header file to include and distribute
|
||||
// with your projects.
|
||||
// * Augment rather than replace the standard stream formatting mechanism
|
||||
// * C++98 support, with optional C++11 niceties
|
||||
//
|
||||
//
|
||||
// Main interface example usage
|
||||
// ----------------------------
|
||||
//
|
||||
// To print a date to std::cout:
|
||||
//
|
||||
// std::string weekday = "Wednesday";
|
||||
// const char* month = "July";
|
||||
// size_t day = 27;
|
||||
// long hour = 14;
|
||||
// int min = 44;
|
||||
//
|
||||
// tfm::printf("%s, %s %d, %.2d:%.2d\n", weekday, month, day, hour, min);
|
||||
//
|
||||
// The strange types here emphasize the type safety of the interface; it is
|
||||
// possible to print a std::string using the "%s" conversion, and a
|
||||
// size_t using the "%d" conversion. A similar result could be achieved
|
||||
// using either of the tfm::format() functions. One prints on a user provided
|
||||
// stream:
|
||||
//
|
||||
// tfm::format(std::cerr, "%s, %s %d, %.2d:%.2d\n",
|
||||
// weekday, month, day, hour, min);
|
||||
//
|
||||
// The other returns a std::string:
|
||||
//
|
||||
// std::string date = tfm::format("%s, %s %d, %.2d:%.2d\n",
|
||||
// weekday, month, day, hour, min);
|
||||
// std::cout << date;
|
||||
//
|
||||
// These are the three primary interface functions. There is also a
|
||||
// convenience function printfln() which appends a newline to the usual result
|
||||
// of printf() for super simple logging.
|
||||
//
|
||||
//
|
||||
// User defined format functions
|
||||
// -----------------------------
|
||||
//
|
||||
// Simulating variadic templates in C++98 is pretty painful since it requires
|
||||
// writing out the same function for each desired number of arguments. To make
|
||||
// this bearable tinyformat comes with a set of macros which are used
|
||||
// internally to generate the API, but which may also be used in user code.
|
||||
//
|
||||
// The three macros TINYFORMAT_ARGTYPES(n), TINYFORMAT_VARARGS(n) and
|
||||
// TINYFORMAT_PASSARGS(n) will generate a list of n argument types,
|
||||
// type/name pairs and argument names respectively when called with an integer
|
||||
// n between 1 and 16. We can use these to define a macro which generates the
|
||||
// desired user defined function with n arguments. To generate all 16 user
|
||||
// defined function bodies, use the macro TINYFORMAT_FOREACH_ARGNUM. For an
|
||||
// example, see the implementation of printf() at the end of the source file.
|
||||
//
|
||||
// Sometimes it's useful to be able to pass a list of format arguments through
|
||||
// to a non-template function. The FormatList class is provided as a way to do
|
||||
// this by storing the argument list in a type-opaque way. Continuing the
|
||||
// example from above, we construct a FormatList using makeFormatList():
|
||||
//
|
||||
// FormatListRef formatList = tfm::makeFormatList(weekday, month, day, hour,
|
||||
// min);
|
||||
//
|
||||
// The format list can now be passed into any non-template function and used
|
||||
// via a call to the vformat() function:
|
||||
//
|
||||
// tfm::vformat(std::cout, "%s, %s %d, %.2d:%.2d\n", formatList);
|
||||
//
|
||||
//
|
||||
// Additional API information
|
||||
// --------------------------
|
||||
//
|
||||
// Error handling: Format errors throw detail::FormatError, which is caught
|
||||
// at the public API level to fall back to the raw format string.
|
||||
//
|
||||
// User defined types: Uses operator<< for user defined types by default.
|
||||
// Overload formatValue() for more control.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "paddle/utils/string/to_string.h"
|
||||
#include "paddle/utils/test_macros.h"
|
||||
namespace paddle {
|
||||
namespace string {
|
||||
namespace tinyformat {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
namespace detail {
|
||||
|
||||
// Exception thrown on format errors instead of crashing via assert.
|
||||
// Caught at the public API level to fall back to returning the raw format
|
||||
// string, so that a wrong PADDLE_ENFORCE format never causes an abort.
|
||||
struct FormatError {};
|
||||
|
||||
// Test whether type T1 is convertible to type T2
|
||||
template <typename T1, typename T2>
|
||||
struct is_convertible {
|
||||
private:
|
||||
// two types of different size
|
||||
struct fail {
|
||||
char dummy[2];
|
||||
};
|
||||
struct succeed {
|
||||
char dummy;
|
||||
};
|
||||
// Try to convert a T1 to a T2 by plugging into tryConvert
|
||||
static fail tryConvert(...);
|
||||
static succeed tryConvert(const T2 &);
|
||||
static const T1 &makeT1();
|
||||
|
||||
public:
|
||||
// Standard trick: the (...) version of tryConvert will be chosen from
|
||||
// the overload set only if the version taking a T2 doesn't match.
|
||||
// Then we compare the sizes of the return types to check which
|
||||
// function matched. Very neat, in a disgusting kind of way :)
|
||||
static const bool value = sizeof(tryConvert(makeT1())) == sizeof(succeed);
|
||||
};
|
||||
|
||||
// Format the value by casting to type fmtT. This default implementation
|
||||
// should never be called.
|
||||
template <typename T,
|
||||
typename fmtT,
|
||||
bool convertible = is_convertible<T, fmtT>::value>
|
||||
struct formatValueAsType {
|
||||
static void invoke(std::ostream & /*out*/, const T & /*value*/) { assert(0); }
|
||||
};
|
||||
// Specialized version for types that can actually be converted to fmtT, as
|
||||
// indicated by the "convertible" template parameter.
|
||||
template <typename T, typename fmtT>
|
||||
struct formatValueAsType<T, fmtT, true> {
|
||||
static void invoke(std::ostream &out, const T &value) {
|
||||
out << static_cast<fmtT>(value);
|
||||
}
|
||||
};
|
||||
|
||||
// Convert an arbitrary type to integer. The version with convertible=false
|
||||
// throws an error.
|
||||
template <typename T, bool convertible = is_convertible<T, int>::value>
|
||||
struct convertToInt {
|
||||
static int invoke(const T & /*value*/) {
|
||||
throw FormatError();
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
// Specialization for convertToInt when conversion is possible
|
||||
template <typename T>
|
||||
struct convertToInt<T, true> {
|
||||
static int invoke(const T &value) { return static_cast<int>(value); }
|
||||
};
|
||||
|
||||
// Format at most ntrunc characters to the given stream.
|
||||
template <typename T>
|
||||
void formatTruncated(std::ostream &out, const T &value, int ntrunc) {
|
||||
std::ostringstream tmp;
|
||||
tmp << value;
|
||||
std::string result = tmp.str();
|
||||
out.write(result.c_str(),
|
||||
(std::min)(ntrunc, static_cast<int>(result.size())));
|
||||
}
|
||||
#define TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(type) \
|
||||
inline void formatTruncated(std::ostream &out, type *value, int ntrunc) { \
|
||||
std::streamsize len = 0; \
|
||||
while (len < ntrunc && value[len] != 0) ++len; \
|
||||
out.write(value, len); \
|
||||
}
|
||||
// Overload for const char* and char*. Could overload for signed & unsigned
|
||||
// char too, but these are technically unneeded for printf compatibility.
|
||||
TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(const char)
|
||||
TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(char)
|
||||
#undef TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR
|
||||
|
||||
} // namespace detail
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Variable formatting functions. May be overridden for user-defined types if
|
||||
// desired.
|
||||
|
||||
/// Format a value into a stream, delegating to operator<< by default.
|
||||
///
|
||||
/// Users may override this for their own types. When this function is called,
|
||||
/// the stream flags will have been modified according to the format string.
|
||||
/// The format specification is provided in the range [fmtBegin, fmtEnd). For
|
||||
/// truncating conversions, ntrunc is set to the desired maximum number of
|
||||
/// characters, for example "%.7s" calls formatValue with ntrunc = 7.
|
||||
///
|
||||
/// By default, formatValue() uses the usual stream insertion operator
|
||||
/// operator<< to format the type T, with special cases for the %c and %p
|
||||
/// conversions.
|
||||
template <typename T>
|
||||
void formatValue(std::ostream &out,
|
||||
const char * /*fmtBegin*/,
|
||||
const char *fmtEnd,
|
||||
int ntrunc,
|
||||
const T &value) {
|
||||
// The mess here is to support the %c and %p conversions: if these
|
||||
// conversions are active we try to convert the type to a char or const
|
||||
// void* respectively and format that instead of the value itself. For the
|
||||
// %p conversion it's important to avoid dereferencing the pointer, which
|
||||
// could otherwise lead to a crash when printing a dangling (const char*).
|
||||
const bool canConvertToChar = detail::is_convertible<T, char>::value;
|
||||
const bool canConvertToVoidPtr =
|
||||
detail::is_convertible<T, const void *>::value;
|
||||
if (canConvertToChar && *(fmtEnd - 1) == 'c') {
|
||||
detail::formatValueAsType<T, char>::invoke(out, value);
|
||||
} else if (canConvertToVoidPtr && *(fmtEnd - 1) == 'p') {
|
||||
detail::formatValueAsType<T, const void *>::invoke(out, value);
|
||||
} else if (ntrunc >= 0) {
|
||||
// Take care not to overread C strings in truncating conversions like
|
||||
// "%.4s" where at most 4 characters may be read.
|
||||
detail::formatTruncated(out, value, ntrunc);
|
||||
} else {
|
||||
out << value;
|
||||
}
|
||||
}
|
||||
|
||||
// Overloaded version for char types to support printing as an integer
|
||||
#define TINYFORMAT_DEFINE_FORMATVALUE_CHAR(charType) \
|
||||
inline void formatValue(std::ostream &out, \
|
||||
const char * /*fmtBegin*/, \
|
||||
const char *fmtEnd, \
|
||||
int /**/, \
|
||||
charType value) { \
|
||||
switch (*(fmtEnd - 1)) { \
|
||||
case 'u': \
|
||||
case 'd': \
|
||||
case 'i': \
|
||||
case 'o': \
|
||||
case 'X': \
|
||||
case 'x': \
|
||||
out << static_cast<int>(value); \
|
||||
break; \
|
||||
default: \
|
||||
out << value; \
|
||||
break; \
|
||||
} \
|
||||
}
|
||||
// per 3.9.1: char, signed char and unsigned char are all distinct types
|
||||
TINYFORMAT_DEFINE_FORMATVALUE_CHAR(char)
|
||||
TINYFORMAT_DEFINE_FORMATVALUE_CHAR(signed char)
|
||||
TINYFORMAT_DEFINE_FORMATVALUE_CHAR(unsigned char)
|
||||
#undef TINYFORMAT_DEFINE_FORMATVALUE_CHAR
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Tools for emulating variadic templates in C++98. The basic idea here is
|
||||
// stolen from the boost preprocessor metaprogramming library and cut down to
|
||||
// be just general enough for what we need.
|
||||
|
||||
#define TINYFORMAT_ARGTYPES(n) TINYFORMAT_ARGTYPES_##n
|
||||
#define TINYFORMAT_VARARGS(n) TINYFORMAT_VARARGS_##n
|
||||
#define TINYFORMAT_PASSARGS(n) TINYFORMAT_PASSARGS_##n
|
||||
#define TINYFORMAT_PASSARGS_TAIL(n) TINYFORMAT_PASSARGS_TAIL_##n
|
||||
|
||||
// To keep it as transparent as possible, the macros below have been generated
|
||||
// using python via the excellent cog.py code generation script. This avoids
|
||||
// the need for a bunch of complex (but more general) preprocessor tricks as
|
||||
// used in boost.preprocessor.
|
||||
//
|
||||
// To rerun the code generation in place, use `cog.py -r tinyformat.h`
|
||||
// (see http://nedbatchelder.com/code/cog). Alternatively you can just create
|
||||
// extra versions by hand.
|
||||
|
||||
/*[[[cog
|
||||
maxParams = 16
|
||||
|
||||
def makeCommaSepLists(lineTemplate, elemTemplate, startInd=1):
|
||||
for j in range(startInd,maxParams+1):
|
||||
list = ', '.join([elemTemplate % {'i':i} for i in range(startInd,j+1)])
|
||||
cog.outl(lineTemplate % {'j':j, 'list':list})
|
||||
|
||||
makeCommaSepLists('#define TINYFORMAT_ARGTYPES_%(j)d %(list)s',
|
||||
'class T%(i)d')
|
||||
|
||||
cog.outl()
|
||||
makeCommaSepLists('#define TINYFORMAT_VARARGS_%(j)d %(list)s',
|
||||
'const T%(i)d& v%(i)d')
|
||||
|
||||
cog.outl()
|
||||
makeCommaSepLists('#define TINYFORMAT_PASSARGS_%(j)d %(list)s', 'v%(i)d')
|
||||
|
||||
cog.outl()
|
||||
cog.outl('#define TINYFORMAT_PASSARGS_TAIL_1')
|
||||
makeCommaSepLists('#define TINYFORMAT_PASSARGS_TAIL_%(j)d , %(list)s',
|
||||
'v%(i)d', startInd = 2)
|
||||
|
||||
cog.outl()
|
||||
cog.outl('#define TINYFORMAT_FOREACH_ARGNUM(m) \\\n ' +
|
||||
' '.join(['m(%d)' % (j,) for j in range(1,maxParams+1)]))
|
||||
]]]*/
|
||||
#define TINYFORMAT_ARGTYPES_1 class T1
|
||||
#define TINYFORMAT_ARGTYPES_2 class T1, class T2
|
||||
#define TINYFORMAT_ARGTYPES_3 class T1, class T2, class T3
|
||||
#define TINYFORMAT_ARGTYPES_4 class T1, class T2, class T3, class T4
|
||||
#define TINYFORMAT_ARGTYPES_5 class T1, class T2, class T3, class T4, class T5
|
||||
#define TINYFORMAT_ARGTYPES_6 \
|
||||
class T1, class T2, class T3, class T4, class T5, class T6
|
||||
#define TINYFORMAT_ARGTYPES_7 \
|
||||
class T1, class T2, class T3, class T4, class T5, class T6, class T7
|
||||
#define TINYFORMAT_ARGTYPES_8 \
|
||||
class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8
|
||||
#define TINYFORMAT_ARGTYPES_9 \
|
||||
class T1, class T2, class T3, class T4, class T5, class T6, class T7, \
|
||||
class T8, class T9
|
||||
#define TINYFORMAT_ARGTYPES_10 \
|
||||
class T1, class T2, class T3, class T4, class T5, class T6, class T7, \
|
||||
class T8, class T9, class T10
|
||||
#define TINYFORMAT_ARGTYPES_11 \
|
||||
class T1, class T2, class T3, class T4, class T5, class T6, class T7, \
|
||||
class T8, class T9, class T10, class T11
|
||||
#define TINYFORMAT_ARGTYPES_12 \
|
||||
class T1, class T2, class T3, class T4, class T5, class T6, class T7, \
|
||||
class T8, class T9, class T10, class T11, class T12
|
||||
#define TINYFORMAT_ARGTYPES_13 \
|
||||
class T1, class T2, class T3, class T4, class T5, class T6, class T7, \
|
||||
class T8, class T9, class T10, class T11, class T12, class T13
|
||||
#define TINYFORMAT_ARGTYPES_14 \
|
||||
class T1, class T2, class T3, class T4, class T5, class T6, class T7, \
|
||||
class T8, class T9, class T10, class T11, class T12, class T13, \
|
||||
class T14
|
||||
#define TINYFORMAT_ARGTYPES_15 \
|
||||
class T1, class T2, class T3, class T4, class T5, class T6, class T7, \
|
||||
class T8, class T9, class T10, class T11, class T12, class T13, \
|
||||
class T14, class T15
|
||||
#define TINYFORMAT_ARGTYPES_16 \
|
||||
class T1, class T2, class T3, class T4, class T5, class T6, class T7, \
|
||||
class T8, class T9, class T10, class T11, class T12, class T13, \
|
||||
class T14, class T15, class T16
|
||||
|
||||
#define TINYFORMAT_VARARGS_1 const T1 &v1
|
||||
#define TINYFORMAT_VARARGS_2 const T1 &v1, const T2 &v2
|
||||
#define TINYFORMAT_VARARGS_3 const T1 &v1, const T2 &v2, const T3 &v3
|
||||
#define TINYFORMAT_VARARGS_4 \
|
||||
const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4
|
||||
#define TINYFORMAT_VARARGS_5 \
|
||||
const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5
|
||||
#define TINYFORMAT_VARARGS_6 \
|
||||
const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, \
|
||||
const T6 &v6
|
||||
#define TINYFORMAT_VARARGS_7 \
|
||||
const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, \
|
||||
const T6 &v6, const T7 &v7
|
||||
#define TINYFORMAT_VARARGS_8 \
|
||||
const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, \
|
||||
const T6 &v6, const T7 &v7, const T8 &v8
|
||||
#define TINYFORMAT_VARARGS_9 \
|
||||
const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, \
|
||||
const T6 &v6, const T7 &v7, const T8 &v8, const T9 &v9
|
||||
#define TINYFORMAT_VARARGS_10 \
|
||||
const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, \
|
||||
const T6 &v6, const T7 &v7, const T8 &v8, const T9 &v9, const T10 &v10
|
||||
#define TINYFORMAT_VARARGS_11 \
|
||||
const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, \
|
||||
const T6 &v6, const T7 &v7, const T8 &v8, const T9 &v9, const T10 &v10, \
|
||||
const T11 &v11
|
||||
#define TINYFORMAT_VARARGS_12 \
|
||||
const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, \
|
||||
const T6 &v6, const T7 &v7, const T8 &v8, const T9 &v9, const T10 &v10, \
|
||||
const T11 &v11, const T12 &v12
|
||||
#define TINYFORMAT_VARARGS_13 \
|
||||
const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, \
|
||||
const T6 &v6, const T7 &v7, const T8 &v8, const T9 &v9, const T10 &v10, \
|
||||
const T11 &v11, const T12 &v12, const T13 &v13
|
||||
#define TINYFORMAT_VARARGS_14 \
|
||||
const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, \
|
||||
const T6 &v6, const T7 &v7, const T8 &v8, const T9 &v9, const T10 &v10, \
|
||||
const T11 &v11, const T12 &v12, const T13 &v13, const T14 &v14
|
||||
#define TINYFORMAT_VARARGS_15 \
|
||||
const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, \
|
||||
const T6 &v6, const T7 &v7, const T8 &v8, const T9 &v9, const T10 &v10, \
|
||||
const T11 &v11, const T12 &v12, const T13 &v13, const T14 &v14, \
|
||||
const T15 &v15
|
||||
#define TINYFORMAT_VARARGS_16 \
|
||||
const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, \
|
||||
const T6 &v6, const T7 &v7, const T8 &v8, const T9 &v9, const T10 &v10, \
|
||||
const T11 &v11, const T12 &v12, const T13 &v13, const T14 &v14, \
|
||||
const T15 &v15, const T16 &v16
|
||||
|
||||
#define TINYFORMAT_PASSARGS_1 v1
|
||||
#define TINYFORMAT_PASSARGS_2 v1, v2
|
||||
#define TINYFORMAT_PASSARGS_3 v1, v2, v3
|
||||
#define TINYFORMAT_PASSARGS_4 v1, v2, v3, v4
|
||||
#define TINYFORMAT_PASSARGS_5 v1, v2, v3, v4, v5
|
||||
#define TINYFORMAT_PASSARGS_6 v1, v2, v3, v4, v5, v6
|
||||
#define TINYFORMAT_PASSARGS_7 v1, v2, v3, v4, v5, v6, v7
|
||||
#define TINYFORMAT_PASSARGS_8 v1, v2, v3, v4, v5, v6, v7, v8
|
||||
#define TINYFORMAT_PASSARGS_9 v1, v2, v3, v4, v5, v6, v7, v8, v9
|
||||
#define TINYFORMAT_PASSARGS_10 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10
|
||||
#define TINYFORMAT_PASSARGS_11 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11
|
||||
#define TINYFORMAT_PASSARGS_12 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12
|
||||
#define TINYFORMAT_PASSARGS_13 \
|
||||
v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13
|
||||
#define TINYFORMAT_PASSARGS_14 \
|
||||
v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14
|
||||
#define TINYFORMAT_PASSARGS_15 \
|
||||
v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15
|
||||
#define TINYFORMAT_PASSARGS_16 \
|
||||
v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16
|
||||
|
||||
#define TINYFORMAT_PASSARGS_TAIL_1
|
||||
#define TINYFORMAT_PASSARGS_TAIL_2 , v2
|
||||
#define TINYFORMAT_PASSARGS_TAIL_3 , v2, v3
|
||||
#define TINYFORMAT_PASSARGS_TAIL_4 , v2, v3, v4
|
||||
#define TINYFORMAT_PASSARGS_TAIL_5 , v2, v3, v4, v5
|
||||
#define TINYFORMAT_PASSARGS_TAIL_6 , v2, v3, v4, v5, v6
|
||||
#define TINYFORMAT_PASSARGS_TAIL_7 , v2, v3, v4, v5, v6, v7
|
||||
#define TINYFORMAT_PASSARGS_TAIL_8 , v2, v3, v4, v5, v6, v7, v8
|
||||
#define TINYFORMAT_PASSARGS_TAIL_9 , v2, v3, v4, v5, v6, v7, v8, v9
|
||||
#define TINYFORMAT_PASSARGS_TAIL_10 , v2, v3, v4, v5, v6, v7, v8, v9, v10
|
||||
#define TINYFORMAT_PASSARGS_TAIL_11 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11
|
||||
#define TINYFORMAT_PASSARGS_TAIL_12 \
|
||||
, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12
|
||||
#define TINYFORMAT_PASSARGS_TAIL_13 \
|
||||
, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13
|
||||
#define TINYFORMAT_PASSARGS_TAIL_14 \
|
||||
, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14
|
||||
#define TINYFORMAT_PASSARGS_TAIL_15 \
|
||||
, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15
|
||||
#define TINYFORMAT_PASSARGS_TAIL_16 \
|
||||
, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16
|
||||
|
||||
#define TINYFORMAT_FOREACH_ARGNUM(m) \
|
||||
m(1) m(2) m(3) m(4) m(5) m(6) m(7) m(8) m(9) m(10) m(11) m(12) m(13) m(14) \
|
||||
m(15) m(16)
|
||||
// [[[end]]]
|
||||
|
||||
namespace detail {
|
||||
|
||||
// Type-opaque holder for an argument to format(), with associated actions on
|
||||
// the type held as explicit function pointers. This allows FormatArg's for
|
||||
// each argument to be allocated as a homogeneous array inside FormatList
|
||||
// whereas a naive implementation based on inheritance does not.
|
||||
class FormatArg {
|
||||
public:
|
||||
FormatArg() {} // NOLINT
|
||||
|
||||
template <typename T>
|
||||
FormatArg(const T &value) // NOLINT
|
||||
: m_value(static_cast<const void *>(&value)),
|
||||
m_formatImpl(&formatImpl<T>),
|
||||
m_toIntImpl(&toIntImpl<T>) {}
|
||||
|
||||
void format(std::ostream &out,
|
||||
const char *fmtBegin,
|
||||
const char *fmtEnd,
|
||||
int ntrunc) const {
|
||||
m_formatImpl(out, fmtBegin, fmtEnd, ntrunc, m_value);
|
||||
}
|
||||
|
||||
int toInt() const { return m_toIntImpl(m_value); }
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
static void formatImpl(std::ostream &out,
|
||||
const char *fmtBegin,
|
||||
const char *fmtEnd,
|
||||
int ntrunc,
|
||||
const void *value) {
|
||||
formatValue(out, fmtBegin, fmtEnd, ntrunc, *static_cast<const T *>(value));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static int toIntImpl(const void *value) {
|
||||
return convertToInt<T>::invoke(*static_cast<const T *>(value));
|
||||
}
|
||||
|
||||
const void *m_value;
|
||||
void (*m_formatImpl)(std::ostream &out,
|
||||
const char *fmtBegin,
|
||||
const char *fmtEnd,
|
||||
int ntrunc,
|
||||
const void *value);
|
||||
int (*m_toIntImpl)(const void *value);
|
||||
};
|
||||
|
||||
// Parse and return an integer from the string c, as atoi()
|
||||
// On return, c is set to one past the end of the integer.
|
||||
inline int parseIntAndAdvance(const char *&c) { // NOLINT
|
||||
int i = 0;
|
||||
for (; *c >= '0' && *c <= '9'; ++c) i = 10 * i + (*c - '0');
|
||||
return i;
|
||||
}
|
||||
|
||||
// Print literal part of format string and return next format spec
|
||||
// position.
|
||||
//
|
||||
// Skips over any occurrences of '%%', printing a literal '%' to the
|
||||
// output. The position of the first % character of the next
|
||||
// nontrivial format spec is returned, or the end of string.
|
||||
inline const char *printFormatStringLiteral(std::ostream &out,
|
||||
const char *fmt) {
|
||||
const char *c = fmt;
|
||||
for (;; ++c) {
|
||||
switch (*c) {
|
||||
case '\0':
|
||||
out.write(fmt, c - fmt);
|
||||
return c;
|
||||
case '%':
|
||||
out.write(fmt, c - fmt);
|
||||
if (*(c + 1) != '%') return c;
|
||||
// for "%%", tack trailing % onto next literal section.
|
||||
fmt = ++c;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse a format string and set the stream state accordingly.
|
||||
//
|
||||
// The format mini-language recognized here is meant to be the one from C99,
|
||||
// with the form "%[flags][width][.precision][length]type".
|
||||
//
|
||||
// Formatting options which can't be natively represented using the ostream
|
||||
// state are returned in spacePadPositive (for space padded positive numbers)
|
||||
// and ntrunc (for truncating conversions). argIndex is incremented if
|
||||
// necessary to pull out variable width and precision . The function returns a
|
||||
// pointer to the character after the end of the current format spec.
|
||||
inline const char *streamStateFromFormat(std::ostream &out, // NOLINT
|
||||
bool &spacePadPositive, // NOLINT
|
||||
int &ntrunc, // NOLINT
|
||||
const char *fmtStart,
|
||||
const detail::FormatArg *formatters,
|
||||
int &argIndex, // NOLINT
|
||||
int numFormatters) {
|
||||
if (*fmtStart != '%') {
|
||||
throw FormatError();
|
||||
return fmtStart;
|
||||
}
|
||||
// Reset stream state to defaults.
|
||||
out.width(0);
|
||||
out.precision(6);
|
||||
out.fill(' ');
|
||||
// Reset most flags; ignore irrelevant unitbuf & skipws.
|
||||
out.unsetf(std::ios::adjustfield | std::ios::basefield |
|
||||
std::ios::floatfield | std::ios::showbase | std::ios::boolalpha |
|
||||
std::ios::showpoint | std::ios::showpos | std::ios::uppercase);
|
||||
bool precisionSet = false;
|
||||
bool widthSet = false;
|
||||
int widthExtra = 0;
|
||||
const char *c = fmtStart + 1;
|
||||
// 1) Parse flags
|
||||
for (;; ++c) {
|
||||
switch (*c) {
|
||||
case '#':
|
||||
out.setf(std::ios::showpoint | std::ios::showbase);
|
||||
continue;
|
||||
case '0':
|
||||
// overridden by left alignment ('-' flag)
|
||||
if (!(out.flags() & std::ios::left)) {
|
||||
// Use internal padding so that numeric values are
|
||||
// formatted correctly, eg -00010 rather than 000-10
|
||||
out.fill('0');
|
||||
out.setf(std::ios::internal, std::ios::adjustfield);
|
||||
}
|
||||
continue;
|
||||
case '-':
|
||||
out.fill(' ');
|
||||
out.setf(std::ios::left, std::ios::adjustfield);
|
||||
continue;
|
||||
case ' ':
|
||||
// overridden by show positive sign, '+' flag.
|
||||
if (!(out.flags() & std::ios::showpos)) spacePadPositive = true;
|
||||
continue;
|
||||
case '+':
|
||||
out.setf(std::ios::showpos);
|
||||
spacePadPositive = false;
|
||||
widthExtra = 1;
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// 2) Parse width
|
||||
if (*c >= '0' && *c <= '9') {
|
||||
widthSet = true;
|
||||
out.width(parseIntAndAdvance(c));
|
||||
}
|
||||
if (*c == '*') {
|
||||
widthSet = true;
|
||||
int width = 0;
|
||||
if (argIndex < numFormatters)
|
||||
width = formatters[argIndex++].toInt();
|
||||
else
|
||||
throw FormatError();
|
||||
if (width < 0) {
|
||||
// negative widths correspond to '-' flag set
|
||||
out.fill(' ');
|
||||
out.setf(std::ios::left, std::ios::adjustfield);
|
||||
width = -width;
|
||||
}
|
||||
out.width(width);
|
||||
++c;
|
||||
}
|
||||
// 3) Parse precision
|
||||
if (*c == '.') {
|
||||
++c;
|
||||
int precision = 0;
|
||||
if (*c == '*') {
|
||||
++c;
|
||||
if (argIndex < numFormatters)
|
||||
precision = formatters[argIndex++].toInt();
|
||||
else
|
||||
throw FormatError();
|
||||
} else {
|
||||
if (*c >= '0' && *c <= '9')
|
||||
precision = parseIntAndAdvance(c);
|
||||
else if (*c == '-') // negative precisions ignored, treated as zero.
|
||||
parseIntAndAdvance(++c);
|
||||
}
|
||||
out.precision(precision);
|
||||
precisionSet = true;
|
||||
}
|
||||
// 4) Ignore any C99 length modifier
|
||||
while (*c == 'l' || *c == 'h' || *c == 'L' || *c == 'j' || *c == 'z' ||
|
||||
*c == 't')
|
||||
++c;
|
||||
// 5) We're up to the conversion specifier character.
|
||||
// Set stream flags based on conversion specifier (thanks to the
|
||||
// boost::format class for forging the way here).
|
||||
bool intConversion = false;
|
||||
switch (*c) {
|
||||
case 'u':
|
||||
case 'd':
|
||||
case 'i':
|
||||
out.setf(std::ios::dec, std::ios::basefield);
|
||||
intConversion = true;
|
||||
break;
|
||||
case 'o':
|
||||
out.setf(std::ios::oct, std::ios::basefield);
|
||||
intConversion = true;
|
||||
break;
|
||||
case 'X':
|
||||
out.setf(std::ios::uppercase);
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
case 'p':
|
||||
out.setf(std::ios::hex, std::ios::basefield);
|
||||
intConversion = true;
|
||||
break;
|
||||
case 'E':
|
||||
out.setf(std::ios::uppercase);
|
||||
break;
|
||||
case 'e':
|
||||
out.setf(std::ios::scientific, std::ios::floatfield);
|
||||
out.setf(std::ios::dec, std::ios::basefield);
|
||||
break;
|
||||
case 'F':
|
||||
out.setf(std::ios::uppercase);
|
||||
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
out.setf(std::ios::fixed, std::ios::floatfield);
|
||||
break;
|
||||
case 'G':
|
||||
out.setf(std::ios::uppercase);
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
out.setf(std::ios::dec, std::ios::basefield);
|
||||
// As in boost::format, let stream decide float format.
|
||||
out.flags(out.flags() & ~std::ios::floatfield);
|
||||
break;
|
||||
case 'a':
|
||||
case 'A':
|
||||
throw FormatError();
|
||||
break;
|
||||
case 'c':
|
||||
// Handled as special case inside formatValue()
|
||||
break;
|
||||
case 's':
|
||||
if (precisionSet) ntrunc = static_cast<int>(out.precision());
|
||||
// Make %s print booleans as "true" and "false"
|
||||
out.setf(std::ios::boolalpha);
|
||||
break;
|
||||
case 'n':
|
||||
// Not supported - will cause problems!
|
||||
throw FormatError();
|
||||
break;
|
||||
case '\0':
|
||||
throw FormatError();
|
||||
return c;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (intConversion && precisionSet && !widthSet) {
|
||||
// "precision" for integers gives the minimum number of digits (to be
|
||||
// padded with zeros on the left). This isn't really supported by the
|
||||
// iostreams, but we can approximately simulate it with the width if
|
||||
// the width isn't otherwise used.
|
||||
out.width(out.precision() + widthExtra);
|
||||
out.setf(std::ios::internal, std::ios::adjustfield);
|
||||
out.fill('0');
|
||||
}
|
||||
return c + 1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
inline void formatImpl(std::ostream &out,
|
||||
const char *fmt,
|
||||
const detail::FormatArg *formatters,
|
||||
int numFormatters) {
|
||||
// Saved stream state
|
||||
std::streamsize origWidth = out.width();
|
||||
std::streamsize origPrecision = out.precision();
|
||||
std::ios::fmtflags origFlags = out.flags();
|
||||
char origFill = out.fill();
|
||||
|
||||
for (int argIndex = 0; argIndex < numFormatters; ++argIndex) {
|
||||
// Parse the format string
|
||||
fmt = printFormatStringLiteral(out, fmt);
|
||||
bool spacePadPositive = false;
|
||||
int ntrunc = -1;
|
||||
const char *fmtEnd = streamStateFromFormat(out,
|
||||
spacePadPositive,
|
||||
ntrunc,
|
||||
fmt,
|
||||
formatters,
|
||||
argIndex,
|
||||
numFormatters);
|
||||
if (argIndex >= numFormatters) {
|
||||
// Check args remain after reading any variable width/precision
|
||||
throw FormatError();
|
||||
return;
|
||||
}
|
||||
const FormatArg &arg = formatters[argIndex];
|
||||
// Format the arg into the stream.
|
||||
if (!spacePadPositive) {
|
||||
arg.format(out, fmt, fmtEnd, ntrunc);
|
||||
} else {
|
||||
// The following is a special case with no direct correspondence
|
||||
// between stream formatting and the printf() behaviour. Simulate
|
||||
// it crudely by formatting into a temporary string stream and
|
||||
// munging the resulting string.
|
||||
std::ostringstream tmpStream;
|
||||
tmpStream.copyfmt(out);
|
||||
tmpStream.setf(std::ios::showpos);
|
||||
arg.format(tmpStream, fmt, fmtEnd, ntrunc);
|
||||
std::string result = tmpStream.str(); // allocates... yuck.
|
||||
for (size_t i = 0, iend = result.size(); i < iend; ++i)
|
||||
if (result[i] == '+') result[i] = ' ';
|
||||
out << result;
|
||||
}
|
||||
fmt = fmtEnd;
|
||||
}
|
||||
|
||||
// Print remaining part of format string.
|
||||
fmt = printFormatStringLiteral(out, fmt);
|
||||
if (fmt != nullptr && *fmt != '\0' && *fmt != 0) throw FormatError();
|
||||
|
||||
// Restore stream state
|
||||
out.width(origWidth);
|
||||
out.precision(origPrecision);
|
||||
out.flags(origFlags);
|
||||
out.fill(origFill);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// List of template arguments format(), held in a type-opaque way.
|
||||
///
|
||||
/// A const reference to FormatList (typedef'd as FormatListRef) may be
|
||||
/// conveniently used to pass arguments to non-template functions: All type
|
||||
/// information has been stripped from the arguments, leaving just enough of a
|
||||
/// common interface to perform formatting as required.
|
||||
class FormatList {
|
||||
public:
|
||||
FormatList(detail::FormatArg *formatters, int N)
|
||||
: m_formatters(formatters), m_N(N) {}
|
||||
|
||||
friend void vformat(std::ostream &out,
|
||||
const char *fmt,
|
||||
const FormatList &list);
|
||||
|
||||
private:
|
||||
const detail::FormatArg *m_formatters;
|
||||
int m_N;
|
||||
};
|
||||
|
||||
/// Reference to type-opaque format list for passing to vformat()
|
||||
typedef const FormatList &FormatListRef;
|
||||
|
||||
namespace detail {
|
||||
|
||||
// Format list subclass with fixed storage to avoid dynamic allocation
|
||||
template <int N>
|
||||
class FormatListN : public FormatList {
|
||||
public:
|
||||
template <typename... Args>
|
||||
FormatListN(const Args &...args) // NOLINT
|
||||
: FormatList(&m_formatterStore[0], N),
|
||||
m_formatterStore{FormatArg(args)...} {
|
||||
static_assert(sizeof...(args) == N, "Number of args must be N");
|
||||
}
|
||||
|
||||
private:
|
||||
FormatArg m_formatterStore[N];
|
||||
};
|
||||
|
||||
// Special 0-arg version - MSVC says zero-sized C array in struct is nonstandard
|
||||
template <>
|
||||
class FormatListN<0> : public FormatList {
|
||||
public:
|
||||
FormatListN() : FormatList(0, 0) {}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Primary API functions
|
||||
|
||||
/// Make type-agnostic format list from list of template arguments.
|
||||
///
|
||||
/// The exact return type of this function is an implementation detail and
|
||||
/// shouldn't be relied upon. Instead it should be stored as a FormatListRef:
|
||||
///
|
||||
/// FormatListRef formatList = makeFormatList( /*...*/ );
|
||||
template <typename... Args>
|
||||
detail::FormatListN<sizeof...(Args)> makeFormatList(const Args &...args) {
|
||||
return detail::FormatListN<sizeof...(args)>(args...);
|
||||
} // NOLINT
|
||||
|
||||
/// Format list of arguments to the stream according to the given format string.
|
||||
///
|
||||
/// The name vformat() is chosen for the semantic similarity to vprintf(): the
|
||||
/// list of format arguments is held in a single function argument.
|
||||
inline void vformat(std::ostream &out, const char *fmt, FormatListRef list) {
|
||||
detail::formatImpl(out, fmt, list.m_formatters, list.m_N);
|
||||
}
|
||||
|
||||
/// Format list of arguments to the stream according to given format string.
|
||||
template <typename... Args>
|
||||
void format(std::ostream &out, const char *fmt, const Args &...args) {
|
||||
vformat(out, fmt, makeFormatList(args...));
|
||||
}
|
||||
|
||||
/// Format list of arguments according to the given format string and return
|
||||
/// the result as a string.
|
||||
template <typename... Args>
|
||||
std::string format(const char *fmt, const Args &...args) {
|
||||
std::ostringstream oss;
|
||||
format(oss, fmt, args...);
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
/// Format list of arguments to std::cout, according to the given format string
|
||||
template <typename... Args>
|
||||
void printf(const char *fmt, const Args &...args) {
|
||||
format(std::cout, fmt, args...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void printfln(const char *fmt, const Args &...args) {
|
||||
format(std::cout, fmt, args...);
|
||||
std::cout << '\n';
|
||||
}
|
||||
|
||||
} // namespace tinyformat
|
||||
} // namespace string
|
||||
} // namespace paddle
|
||||
@@ -0,0 +1,81 @@
|
||||
/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved.
|
||||
|
||||
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 <sstream>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <typeindex>
|
||||
#include <vector>
|
||||
|
||||
namespace paddle {
|
||||
namespace string {
|
||||
inline std::ostream& operator<<(std::ostream& s, const std::type_index& t) {
|
||||
s << t.name();
|
||||
return s;
|
||||
}
|
||||
|
||||
template <typename T,
|
||||
typename std::enable_if<!std::is_enum<T>::value, int>::type = 0>
|
||||
inline std::string to_string(T v) {
|
||||
std::ostringstream sout;
|
||||
sout << v;
|
||||
return sout.str();
|
||||
}
|
||||
|
||||
template <typename T,
|
||||
typename std::enable_if<std::is_enum<T>::value, int>::type = 0>
|
||||
inline std::string to_string(T v) {
|
||||
return std::to_string(static_cast<int>(v));
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::string to_string(std::type_index t) {
|
||||
return t.name();
|
||||
}
|
||||
|
||||
// Faster std::string/const char* type
|
||||
template <>
|
||||
inline std::string to_string(std::string v) {
|
||||
return v;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::string to_string(const char* v) {
|
||||
return std::string(v);
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os,
|
||||
const std::vector<std::vector<size_t>>& lod) {
|
||||
os << "{";
|
||||
for (auto& v : lod) {
|
||||
os << "{";
|
||||
bool is_first = true;
|
||||
for (auto& i : v) {
|
||||
if (is_first) {
|
||||
os << i;
|
||||
is_first = false;
|
||||
} else {
|
||||
os << ", " << i;
|
||||
}
|
||||
}
|
||||
os << "}";
|
||||
}
|
||||
os << "}";
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace string
|
||||
} // namespace paddle
|
||||
Reference in New Issue
Block a user