format: add trivial printf wrapper
This commit is contained in:
parent
f29e77c795
commit
f451e5555e
@ -51,6 +51,9 @@ UTIL_FILES = \
|
||||
fixed.hpp \
|
||||
float.cpp \
|
||||
float.hpp \
|
||||
format.cpp \
|
||||
format.hpp \
|
||||
format.ipp \
|
||||
fourcc.cpp \
|
||||
fourcc.hpp \
|
||||
guid.cpp \
|
||||
@ -315,6 +318,7 @@ TEST_BIN = \
|
||||
test/extent \
|
||||
test/fixed \
|
||||
test/float \
|
||||
test/format \
|
||||
test/hash/murmur \
|
||||
test/hash/fasthash \
|
||||
test/hmac \
|
||||
|
26
format.cpp
Normal file
26
format.cpp
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
#include "format.hpp"
|
||||
|
||||
#include <utility>
|
||||
|
||||
|
||||
//std::string
|
||||
//util::format (std::string &&fmt)
|
||||
//{
|
||||
// return std::move (fmt);
|
||||
//}
|
47
format.hpp
Normal file
47
format.hpp
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
#ifndef __UTIL_FORMAT_HPP
|
||||
#define __UTIL_FORMAT_HPP
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace util {
|
||||
namespace format {
|
||||
template <typename ...Args>
|
||||
std::string render (const std::string &fmt, Args&&...);
|
||||
|
||||
class error : public std::runtime_error
|
||||
{ using runtime_error::runtime_error; };
|
||||
|
||||
// value-specifier mismatch
|
||||
class value_error : public error
|
||||
{ using error::error; };
|
||||
|
||||
// malformed format specifier
|
||||
class format_error : public error
|
||||
{ using error::error; };
|
||||
|
||||
// missing format specifier
|
||||
class missing_error : public error
|
||||
{ using error::error; };
|
||||
}
|
||||
}
|
||||
|
||||
#include "format.ipp"
|
||||
|
||||
#endif
|
94
format.ipp
Normal file
94
format.ipp
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
#if defined(__UTIL_FORMAT_IPP)
|
||||
#error
|
||||
#endif
|
||||
#define __UTIL_FORMAT_IPP
|
||||
|
||||
#include "debug.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <iterator>
|
||||
|
||||
namespace util {
|
||||
namespace detail { namespace format {
|
||||
template <typename InputIt>
|
||||
void
|
||||
render (InputIt first,
|
||||
InputIt last,
|
||||
std::ostringstream &dest)
|
||||
{
|
||||
static const char DELIMITER = '%';
|
||||
if (std::find (first, last, DELIMITER) != last)
|
||||
throw util::format::missing_error ("format specifier without value");
|
||||
|
||||
std::copy (first, last, std::ostream_iterator<char> (dest));
|
||||
}
|
||||
|
||||
|
||||
template <typename InputIt,
|
||||
typename ValueT,
|
||||
typename ...Args>
|
||||
void
|
||||
render (InputIt first,
|
||||
InputIt last,
|
||||
std::ostringstream &dest,
|
||||
const ValueT& val,
|
||||
Args&& ...args)
|
||||
{
|
||||
CHECK (first <= last);
|
||||
|
||||
static const char DELIMITER = '%';
|
||||
auto cursor = std::find (first, last, DELIMITER);
|
||||
std::copy (first, cursor, std::ostream_iterator<char> (dest));
|
||||
|
||||
if (cursor == last)
|
||||
return;
|
||||
|
||||
auto spec = cursor + 1;
|
||||
if (spec == last)
|
||||
throw util::format::format_error ("missing format specifier");
|
||||
|
||||
if (*spec != 's')
|
||||
throw util::format::format_error ("unhandled format specifier");
|
||||
|
||||
dest << val;
|
||||
|
||||
render (spec + 1, last, dest, std::forward<Args> (args)...);
|
||||
}
|
||||
} }
|
||||
|
||||
namespace format {
|
||||
template <typename ...Args>
|
||||
std::string
|
||||
render (const std::string &fmt, Args&&... args)
|
||||
{
|
||||
std::ostringstream out;
|
||||
|
||||
util::detail::format::render (
|
||||
fmt.begin (),
|
||||
fmt.end (),
|
||||
out,
|
||||
std::forward<Args> (args)...
|
||||
);
|
||||
|
||||
return out.str ();
|
||||
}
|
||||
}
|
||||
}
|
20
test/format.cpp
Normal file
20
test/format.cpp
Normal file
@ -0,0 +1,20 @@
|
||||
#include "format.hpp"
|
||||
|
||||
#include "tap.hpp"
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
using namespace std::string_literals;
|
||||
|
||||
util::TAP::logger tap;
|
||||
|
||||
tap.expect_eq (util::format::render ("identity"), "identity"s, "identity literal");
|
||||
tap.expect_eq (util::format::render ("%s", "identity"s), "identity"s, "identity substitution");
|
||||
|
||||
tap.expect_throw<util::format::missing_error> ([] (void) { util::format::render ("%s"); });
|
||||
tap.expect_throw<util::format::format_error> ([] (void) { util::format::render ("%!", 42); });
|
||||
tap.expect_throw<util::format::format_error> ([] (void) { util::format::render ("%", 42); });
|
||||
|
||||
return tap.status ();
|
||||
}
|
Loading…
Reference in New Issue
Block a user