Skip to content

Commit bbba921

Browse files
author
John Doe
committed
old shit becomes new shit
0 parents commit bbba921

File tree

1 file changed

+170
-0
lines changed

1 file changed

+170
-0
lines changed

main.cpp

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
2+
#include <iostream>
3+
#include <sstream>
4+
#include <string>
5+
#include <string_view>
6+
#include <exception>
7+
#include <stdexcept>
8+
#include <iomanip>
9+
10+
/*
11+
* todo:
12+
* - format specifiers
13+
* + compile time checking?
14+
~ how does __attribute__((format(printf, ...))) do it?
15+
~ possible, but ugly implementation: https://codereview.stackexchange.com/q/84768
16+
~ just how far can this be driven?
17+
*
18+
*
19+
* - indexed arguments: - i.e., `format(..., "%{1}.4s %{0}s", "world", "hello");` would
20+
* result in "hell world" (use of %.4s turns "hello" into "hell" :-))[1]
21+
* + Qt does something like this, but checking is runtime-bound. boo! awful.
22+
* + C# does this too, but like Qt, checking happens during runtime. however, C# also
23+
* has string interpolation.
24+
* + there are various implementations of type-safe *printf libraries for C++, but:
25+
* 1) they're either unreasonably bloated, or
26+
* 2) are either not idiomatic C++, or invent their own stupid style (like using PascalCase. yuck!)
27+
* 3) use unnecessary buildsystem cruft, rendering them difficult to integrate
28+
*
29+
* - use standard headers ONLY. no special machine-level floating point shit, or such.
30+
*
31+
*
32+
*
33+
* [1]:
34+
* int main()
35+
* {
36+
* const char* a = "hello";
37+
* const char* b = "world";
38+
* printf("%.4s %s\n", a, b);
39+
* return 0;
40+
* }
41+
*
42+
*/
43+
44+
namespace sfprintf
45+
{
46+
template<typename CharT>
47+
inline void quoteString(std::basic_ostream<CharT>& out, const std::basic_string<CharT>& str)
48+
{
49+
int cd;
50+
size_t i;
51+
out << CharT('"');
52+
for(i=0; i<str.length(); i++)
53+
{
54+
cd = str[i];
55+
switch(cd)
56+
{
57+
case '\n': out << CharT('\\') << CharT('n'); break;
58+
case '\r': out << CharT('\\') << CharT('r'); break;
59+
case '\t': out << CharT('\\') << CharT('t'); break;
60+
case '\0': out << CharT('\\') << CharT('0'); break;
61+
default:
62+
{
63+
if((cd > 31) && (cd < 127))
64+
{
65+
out << CharT(cd);
66+
}
67+
else
68+
{
69+
out << CharT('0') << CharT('x') << std::hex << int(cd);
70+
}
71+
}
72+
break;
73+
}
74+
}
75+
out << CharT('"');
76+
}
77+
78+
template<typename CharT>
79+
inline std::basic_string<CharT> quoteString(const std::basic_string<CharT>& s)
80+
{
81+
std::basic_string<CharT> os;
82+
quoteString(os, s);
83+
return os;
84+
}
85+
86+
87+
template<typename CharT>
88+
inline constexpr std::basic_ostream<CharT>& format(std::basic_ostream<CharT>& out, std::basic_string_view<CharT> format)
89+
{
90+
out << format;
91+
return out;
92+
}
93+
94+
template<typename CharT, typename Type, typename... Targs>
95+
constexpr std::basic_ostream<CharT>& format(
96+
/* output stream */
97+
std::basic_ostream<CharT>& out,
98+
/* format string */
99+
std::basic_string_view<CharT> fmt,
100+
/* the first typed argumnt */
101+
Type value,
102+
/* the rest of the arguments*/
103+
Targs... Fargs
104+
)
105+
{
106+
size_t i;
107+
int cd;
108+
for (i=0; i<fmt.length(); i++)
109+
{
110+
if(fmt[i] == '%')
111+
{
112+
cd = fmt[i + 1];
113+
switch(cd)
114+
{
115+
case '%':
116+
out << CharT('%');
117+
break;
118+
case 's':
119+
case 'd':
120+
case 'l':
121+
case 'c':
122+
{
123+
out << value;
124+
}
125+
break;
126+
case 'q':
127+
{
128+
std::basic_stringstream<CharT> tmp;
129+
tmp << value;
130+
quoteString(out, tmp.str());
131+
}
132+
break;
133+
default:
134+
{
135+
throw std::runtime_error("invalid format character");
136+
}
137+
break;
138+
}
139+
auto subst = fmt.substr(i+2, fmt.length());
140+
return format(out, subst, Fargs...);
141+
}
142+
out << fmt[i];
143+
}
144+
return out;
145+
}
146+
147+
template<typename CharT, size_t len, typename... ArgsT>
148+
inline std::basic_ostream<CharT>& format(
149+
std::basic_ostream<CharT>& out, const char(&fmt)[len], ArgsT&&... args)
150+
{
151+
return format(out, std::basic_string_view<CharT>(fmt, len), args...);
152+
}
153+
154+
}
155+
156+
int main()
157+
{
158+
std::stringstream buf;
159+
try
160+
{
161+
sfprintf::mysprintf(buf, "%s world%c %d\n", "Hello", '!', 123);
162+
auto s = buf.str();
163+
std::cout << s << "(len=" << s.length() << ")" << std::endl;
164+
}
165+
catch(std::runtime_error& e)
166+
{
167+
std::cerr << "runtime_error: " << e.what() << std::endl;
168+
}
169+
return 0;
170+
}

0 commit comments

Comments
 (0)