mirror of
https://github.com/matrix-construct/construct
synced 2024-12-11 08:02:59 +01:00
250 lines
6.6 KiB
C++
250 lines
6.6 KiB
C++
// Matrix Construct
|
|
//
|
|
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
|
// Copyright (C) 2016-2018 Jason Volk <jason@zemos.net>
|
|
//
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
// copyright notice and this permission notice is present in all copies. The
|
|
// full license for this software is available in the LICENSE file.
|
|
|
|
#pragma once
|
|
#define HAVE_IRCD_FMT_H
|
|
|
|
/// Typesafe format strings from formal grammars & standard RTTI
|
|
namespace ircd::fmt
|
|
{
|
|
IRCD_EXCEPTION(ircd::error, error);
|
|
IRCD_PANICKING(error, invalid_format);
|
|
IRCD_PANICKING(error, invalid_type);
|
|
IRCD_PANICKING(error, illegal);
|
|
|
|
struct sprintf;
|
|
struct vsprintf;
|
|
struct snprintf;
|
|
struct vsnprintf;
|
|
struct snstringf;
|
|
struct vsnstringf;
|
|
struct literal_snstringf;
|
|
struct literal_snstringf__max;
|
|
template<size_t MAX> struct bsprintf;
|
|
using arg = std::tuple<const void *, const std::type_index &>;
|
|
|
|
literal_snstringf operator ""_snstringf(const char *text, const size_t len);
|
|
literal_snstringf__max operator,(const literal_snstringf, const ulong max);
|
|
template<class... args> std::string operator,(const literal_snstringf__max, args&&...);
|
|
}
|
|
|
|
namespace ircd
|
|
{
|
|
using fmt::operator ""_snstringf;
|
|
}
|
|
|
|
/// Typesafe snprintf() from formal grammar and RTTI.
|
|
///
|
|
/// This function accepts a format string and a variable number of arguments
|
|
/// composing formatted null-terminated output in the provided output buffer.
|
|
/// The format string is compliant with standard snprintf() (TODO: not yet).
|
|
/// The type information of the arguments is grabbed from the variadic template
|
|
/// and references are passed to the formal output grammars. This means you can
|
|
/// pass an std::string directly without calling c_str(), as well as pass a
|
|
/// non-null-terminated string_view safely.
|
|
///
|
|
class ircd::fmt::snprintf
|
|
{
|
|
window_buffer out; // Window on the output buffer.
|
|
const_buffer fmt; // Current running position in the fmtstr.
|
|
short idx; // Keeps count of the args for better err msgs
|
|
|
|
bool finished() const noexcept;
|
|
size_t remaining() const noexcept;
|
|
size_t consumed() const { return out.consumed(); }
|
|
string_view completed() const { return out.completed(); }
|
|
|
|
void append(const string_view &);
|
|
void argument(const arg &);
|
|
|
|
protected:
|
|
IRCD_OVERLOAD(internal)
|
|
snprintf(internal_t, const mutable_buffer &, const string_view &, const va_rtti &);
|
|
|
|
public:
|
|
operator ssize_t() const { return consumed(); }
|
|
operator string_view() const { return completed(); }
|
|
|
|
template<class... Args>
|
|
snprintf(char *const &buf,
|
|
const size_t &max,
|
|
const string_view &fmt,
|
|
Args&&... args)
|
|
:snprintf
|
|
{
|
|
internal, mutable_buffer{buf, max}, fmt, va_rtti{std::forward<Args>(args)...}
|
|
}{}
|
|
};
|
|
|
|
/// Same as snprintf() where n= is deduced by the buffer size argument
|
|
///
|
|
struct ircd::fmt::sprintf
|
|
:snprintf
|
|
{
|
|
template<class... Args>
|
|
sprintf(const mutable_buffer &buf,
|
|
const string_view &fmt,
|
|
Args&&... args)
|
|
:snprintf
|
|
{
|
|
internal, buf, fmt, va_rtti{std::forward<Args>(args)...}
|
|
}{}
|
|
};
|
|
|
|
/// A complement to fmt::snprintf() accepting an already-made va_rtti.
|
|
///
|
|
/// This function has no variadic template; instead it accepts the type
|
|
/// which would be composed by such a variadic template called
|
|
/// ircd::va_rtti directly.
|
|
///
|
|
/// ircd::va_rtti is a lightweight pairing of argument pointers to runtime
|
|
/// type indexes. ircd::va_rtti is not a template itself because its purpose
|
|
/// is to bring this type information out of the header files to where the
|
|
/// grammar is instantiated.
|
|
///
|
|
struct ircd::fmt::vsnprintf
|
|
:snprintf
|
|
{
|
|
vsnprintf(char *const &buf,
|
|
const size_t &max,
|
|
const string_view &fmt,
|
|
const va_rtti &ap)
|
|
:snprintf
|
|
{
|
|
internal, mutable_buffer{buf, max}, fmt, ap
|
|
}{}
|
|
};
|
|
|
|
/// Same as vsnprintf() where n is deduced from the buffer size.
|
|
///
|
|
struct ircd::fmt::vsprintf
|
|
:snprintf
|
|
{
|
|
vsprintf(const mutable_buffer &buf,
|
|
const string_view &fmt,
|
|
const va_rtti &ap)
|
|
:snprintf
|
|
{
|
|
internal, buf, fmt, ap
|
|
}{}
|
|
};
|
|
|
|
/// Allocates a buffer (std::string) of size for the result.
|
|
///
|
|
/// see snstringf() for vararg format overload.
|
|
struct ircd::fmt::vsnstringf
|
|
:std::string
|
|
{
|
|
vsnstringf(const size_t &max,
|
|
const string_view &fmt,
|
|
const va_rtti &ap)
|
|
:std::string
|
|
{
|
|
ircd::string(max, [&fmt, &ap]
|
|
(const mutable_buffer &buf) -> string_view
|
|
{
|
|
return vsprintf
|
|
{
|
|
buf, fmt, ap
|
|
};
|
|
})
|
|
}{}
|
|
};
|
|
|
|
/// Allocates a buffer (std::string) of size for the result.
|
|
///
|
|
/// Note: that OR'ing the size with ircd::SHRINK_TO_FIT constant will trigger
|
|
/// a standard string re-evaluation to determine if the final result string
|
|
/// should be transferred to a smaller buffer.
|
|
struct ircd::fmt::snstringf
|
|
:vsnstringf
|
|
{
|
|
template<class... args>
|
|
snstringf(const size_t &max,
|
|
const string_view &fmt,
|
|
args&&... a)
|
|
:vsnstringf
|
|
{
|
|
max, fmt, va_rtti{std::forward<args>(a)...}
|
|
}{}
|
|
};
|
|
|
|
/// Efficient in-place buffer convenience template.
|
|
///
|
|
/// This is an object which contains the result buffer internally. The size
|
|
/// of that buffer is given in the template parameter. This is clean and
|
|
/// efficient for basic format string operations on the stack while avoiding
|
|
/// the clutter of buffer statements and mgmt.
|
|
template<size_t MAX>
|
|
struct ircd::fmt::bsprintf
|
|
:snprintf
|
|
,string_view
|
|
{
|
|
char buf[MAX];
|
|
|
|
template<class... args>
|
|
bsprintf(const string_view &fmt,
|
|
args&&... a)
|
|
:snprintf
|
|
{
|
|
internal, buf, fmt, va_rtti{std::forward<args>(a)...}
|
|
}
|
|
,string_view
|
|
{
|
|
buf, size_t(static_cast<snprintf &>(*this))
|
|
}{}
|
|
};
|
|
|
|
/// Experimental typedef for format strings.
|
|
struct ircd::fmt::literal_snstringf
|
|
{
|
|
string_view format;
|
|
};
|
|
|
|
/// Experimental typedef for format strings.
|
|
struct ircd::fmt::literal_snstringf__max
|
|
{
|
|
literal_snstringf format;
|
|
size_t max;
|
|
};
|
|
|
|
template<class... args>
|
|
inline std::string
|
|
ircd::fmt::operator,(const literal_snstringf__max format,
|
|
args&&... a)
|
|
{
|
|
return fmt::snstringf
|
|
{
|
|
format.max, format.format.format, std::forward<args>(a)...
|
|
};
|
|
}
|
|
|
|
inline ircd::fmt::literal_snstringf__max
|
|
ircd::fmt::operator,(const literal_snstringf format,
|
|
const ulong max)
|
|
{
|
|
return literal_snstringf__max
|
|
{
|
|
format, max
|
|
};
|
|
}
|
|
|
|
inline ircd::fmt::literal_snstringf
|
|
ircd::fmt::operator ""_snstringf(const char *const format,
|
|
const size_t len)
|
|
{
|
|
return literal_snstringf
|
|
{
|
|
string_view
|
|
{
|
|
format, len
|
|
}
|
|
};
|
|
}
|