File: string_util.h

package info (click to toggle)
cmph 2.0.2-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 6,748 kB
  • sloc: ansic: 10,582; cpp: 2,429; makefile: 151; sh: 111; python: 48; xml: 5
file content (133 lines) | stat: -rw-r--r-- 3,908 bytes parent folder | download | duplicates (5)
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
#ifndef __CXXMPH_STRING_UTIL_H__
#define __CXXMPH_STRING_UTIL_H__

// Helper functions for string formatting and terminal output. Should be used
// only for debugging and tests, since performance was not a concern.
// Implemented using variadic templates because it is cool.
//
// Adds the extra format %v to the printf formatting language. Uses the method
// cxxmph::tostr to implement custom printers and fallback to operator
// ostream::operator<< otherwise.

#include <cstdint>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <string>
#include <sstream>
#include <utility>
#include <vector>

#define CXXMPH_DEBUGLN(fmt) variadic_print(__FILE__, __LINE__, &std::cerr, fmt)
#define CXXMPH_INFOLN(fmt) variadic_print(__FILE__, __LINE__, &std::cout, fmt)

namespace cxxmph {

using std::pair;
using std::string;
using std::ostream;
using std::vector;

template <class T> void tostr(ostream *out, const T& v) {
  *out << v;
}
inline void tostr(std::ostream* out, uint8_t v) {
  *out << static_cast<uint32_t>(v);
}
template <class V>
inline void tostr(ostream* out, const vector<V>& v) {
  *out << "[";
  for (uint32_t i = 0; i < v.size(); ++i) {
    tostr(out, v[1]);
    if (i != v.size() - 1)*out << " ";
  }
  *out << "]";
}
template <class F, class S>
inline void tostr(ostream* out, const pair<F, S>& v) {
  *out << "(";
  tostr(out, v.first);
  *out << ",";
  tostr(out, v.second);
  *out << ")";
}

bool stream_printf(
    const std::string& format_string, uint32_t offset, std::ostream* out);

template <bool ispod> struct pod_snprintf {};
template <> struct pod_snprintf<false> {
  template <class T>
  int operator()(char*, size_t, const char*, const T&) {
     return -1;
  }
};
template <> struct pod_snprintf<true> {
  template <class T>
  int operator()(char* str, size_t size, const char* format, const T& v) {
    return snprintf(str, size, format, v);
  }
};

template <typename T, typename... Args>
bool stream_printf(const std::string& format_string, uint32_t offset,
                   std::ostream* out, const T& value, Args&&... args) {
  auto txt = format_string.c_str() + offset;
  while (*txt) {
    auto b = txt;
    for (; *txt != '%'; ++txt);
    if (*(txt + 1) == '%') ++txt;
    else if (txt == b) break;
    *out << string(b, txt - b);
    if (*(txt - 1) == '%') ++txt;
  }
  auto fmt = txt + 1;
  while (*fmt && *fmt != '%') ++fmt;
  if (strncmp(txt, "%v", 2) == 0) {
     txt += 2;
     tostr(out, value);
     if (txt != fmt) *out << string(txt, fmt);
  } else {
    char buf[256];  // Is this enough?
    auto n = pod_snprintf<std::is_pod<T>::value>()(
        buf, 256, std::string(txt, fmt).c_str(), value);
    if (n < 0) return false;
    *out << buf;
  }
  return stream_printf(format_string, fmt - format_string.c_str(), out,
                       std::forward<Args>(args)...);
}

template <typename... Args>
std::string format(const std::string& format_string, Args&&... args) {
  std::ostringstream out;
  if (!stream_printf(format_string, 0, &out, std::forward<Args>(args)...)) {
    return std::string();
  };
  return out.str();
}

template <typename... Args>
void infoln(const std::string& format_string, Args&&... args) {
  stream_printf(format_string + "\n", 0, &std::cout, std::forward<Args>(args)...);
}

struct variadic_print {
  variadic_print(const std::string& file, uint32_t line, std::ostream* out,
                 const std::string& format_line) 
     : file_(file), line_(line), out_(out), format_line_(format_line) {}
  template <typename... Args>
  void operator()(Args&&... args) {
    std::string fancy_format = "%v:%d: ";
    fancy_format += format_line_ + "\n";
    stream_printf(fancy_format, 0, out_, file_, line_, std::forward<Args>(args)...);
  }
  const std::string& file_;
  const uint32_t& line_;
  std::ostream* out_;
  const std::string& format_line_;
};

}  // namespace cxxmph

#endif // __CXXMPH_STRING_UTIL_H__