mirror of
https://github.com/matrix-construct/construct
synced 2024-11-25 16:22:35 +01:00
ircd: Split up lexical.h; comments; cleanup.
This commit is contained in:
parent
01d7ec1560
commit
9c712486a1
5 changed files with 710 additions and 519 deletions
265
include/ircd/lex_cast.h
Normal file
265
include/ircd/lex_cast.h
Normal file
|
@ -0,0 +1,265 @@
|
||||||
|
/*
|
||||||
|
* charybdis: an advanced ircd.
|
||||||
|
* inline/stringops.h: inlined string operations used in a few places
|
||||||
|
*
|
||||||
|
* Copyright (C) 2005-2016 Charybdis Development Team
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||||
|
* USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#define HAVE_IRCD_LEX_CAST_H
|
||||||
|
|
||||||
|
//
|
||||||
|
// Lexical conversions
|
||||||
|
//
|
||||||
|
namespace ircd
|
||||||
|
{
|
||||||
|
IRCD_EXCEPTION_HIDENAME(ircd::error, bad_lex_cast)
|
||||||
|
|
||||||
|
template<class T> bool try_lex_cast(const string_view &);
|
||||||
|
|
||||||
|
template<class T> T lex_cast(std::string &);
|
||||||
|
template<class T> T lex_cast(const std::string &);
|
||||||
|
template<class T> T lex_cast(const std::string_view &);
|
||||||
|
template<class T> T lex_cast(const string_view &);
|
||||||
|
|
||||||
|
// User supplied destination buffer
|
||||||
|
template<class T> string_view lex_cast(T, char *const &buf, const size_t &max);
|
||||||
|
|
||||||
|
// Circular static thread_local buffer
|
||||||
|
const size_t LEX_CAST_BUFS {256}; // plenty
|
||||||
|
template<class T> string_view lex_cast(const T &t);
|
||||||
|
|
||||||
|
// Binary <-> Hex conversion suite
|
||||||
|
string_view u2a(const mutable_buffer &out, const const_raw_buffer &in);
|
||||||
|
const_raw_buffer a2u(const mutable_raw_buffer &out, const const_buffer &in);
|
||||||
|
|
||||||
|
// Binary <-> Base64 conversion suite
|
||||||
|
string_view b64encode(const mutable_buffer &out, const const_raw_buffer &in);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ircd
|
||||||
|
{
|
||||||
|
template<> bool try_lex_cast<std::string>(const string_view &); // stub always true
|
||||||
|
template<> bool try_lex_cast<std::string_view>(const string_view &); // stub always true
|
||||||
|
template<> bool try_lex_cast<string_view>(const string_view &); // stub always true
|
||||||
|
template<> bool try_lex_cast<long double>(const string_view &);
|
||||||
|
template<> bool try_lex_cast<double>(const string_view &);
|
||||||
|
template<> bool try_lex_cast<ulong>(const string_view &);
|
||||||
|
template<> bool try_lex_cast<long>(const string_view &);
|
||||||
|
template<> bool try_lex_cast<uint>(const string_view &);
|
||||||
|
template<> bool try_lex_cast<int>(const string_view &);
|
||||||
|
template<> bool try_lex_cast<ushort>(const string_view &);
|
||||||
|
template<> bool try_lex_cast<short>(const string_view &);
|
||||||
|
template<> bool try_lex_cast<uint8_t>(const string_view &);
|
||||||
|
template<> bool try_lex_cast<int8_t>(const string_view &);
|
||||||
|
template<> bool try_lex_cast<bool>(const string_view &);
|
||||||
|
|
||||||
|
template<> std::string &lex_cast(std::string &); // trivial
|
||||||
|
template<> std::string lex_cast(const std::string &); // trivial
|
||||||
|
template<> std::string_view lex_cast(const std::string_view &); // trivial
|
||||||
|
template<> std::string lex_cast(const string_view &); // trivial
|
||||||
|
template<> long double lex_cast(const string_view &);
|
||||||
|
template<> double lex_cast(const string_view &);
|
||||||
|
template<> ulong lex_cast(const string_view &);
|
||||||
|
template<> long lex_cast(const string_view &);
|
||||||
|
template<> uint lex_cast(const string_view &);
|
||||||
|
template<> int lex_cast(const string_view &);
|
||||||
|
template<> ushort lex_cast(const string_view &);
|
||||||
|
template<> short lex_cast(const string_view &);
|
||||||
|
template<> uint8_t lex_cast(const string_view &);
|
||||||
|
template<> int8_t lex_cast(const string_view &);
|
||||||
|
template<> bool lex_cast(const string_view &);
|
||||||
|
|
||||||
|
template<> string_view lex_cast(const std::string &, char *const &buf, const size_t &max);
|
||||||
|
template<> string_view lex_cast(const std::string_view &, char *const &buf, const size_t &max);
|
||||||
|
template<> string_view lex_cast(const string_view &, char *const &buf, const size_t &max);
|
||||||
|
template<> string_view lex_cast(long double, char *const &buf, const size_t &max);
|
||||||
|
template<> string_view lex_cast(double, char *const &buf, const size_t &max);
|
||||||
|
template<> string_view lex_cast(ulong, char *const &buf, const size_t &max);
|
||||||
|
template<> string_view lex_cast(long, char *const &buf, const size_t &max);
|
||||||
|
template<> string_view lex_cast(uint, char *const &buf, const size_t &max);
|
||||||
|
template<> string_view lex_cast(int, char *const &buf, const size_t &max);
|
||||||
|
template<> string_view lex_cast(ushort, char *const &buf, const size_t &max);
|
||||||
|
template<> string_view lex_cast(short, char *const &buf, const size_t &max);
|
||||||
|
template<> string_view lex_cast(uint8_t, char *const &buf, const size_t &max);
|
||||||
|
template<> string_view lex_cast(int8_t, char *const &buf, const size_t &max);
|
||||||
|
template<> string_view lex_cast(bool, char *const &buf, const size_t &max);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert a native number to a string. The returned value is a view of the
|
||||||
|
/// string in a static ring buffer. There are LEX_CAST_BUFS number of buffers
|
||||||
|
/// so you should not hold on to the returned view for very long.
|
||||||
|
template<class T>
|
||||||
|
ircd::string_view
|
||||||
|
ircd::lex_cast(const T &t)
|
||||||
|
{
|
||||||
|
return lex_cast<T>(t, nullptr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Conversion to an std::string creates a copy when the input is a
|
||||||
|
/// string_view. Note this is not considered an "unnecessary lexical cast"
|
||||||
|
/// even though nothing is being converted, so there will be no warning.
|
||||||
|
template<>
|
||||||
|
inline std::string
|
||||||
|
ircd::lex_cast<std::string>(const string_view &s)
|
||||||
|
{
|
||||||
|
return std::string{s};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Template basis for a string_view input
|
||||||
|
template<class T>
|
||||||
|
T
|
||||||
|
ircd::lex_cast(const string_view &s)
|
||||||
|
{
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Specialization of a string_view to string_view conversion which is just
|
||||||
|
/// a trivial copy of the view.
|
||||||
|
template<>
|
||||||
|
inline std::string_view
|
||||||
|
ircd::lex_cast<std::string_view>(const std::string_view &s)
|
||||||
|
{
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Specialization of a string to string conversion which generates a warning
|
||||||
|
/// because the conversion has to copy the string while no numerical conversion
|
||||||
|
/// has taken place. The developer should remove the offending lex_cast.
|
||||||
|
template<>
|
||||||
|
__attribute__((warning("unnecessary lexical cast")))
|
||||||
|
inline std::string
|
||||||
|
ircd::lex_cast<std::string>(const std::string &s)
|
||||||
|
{
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Template basis for a const std::string input
|
||||||
|
template<class T>
|
||||||
|
T
|
||||||
|
ircd::lex_cast(const std::string &s)
|
||||||
|
{
|
||||||
|
return lex_cast<T>(string_view{s});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Template basis for an lvalue string. If we can get this binding rather
|
||||||
|
/// than the const std::string alternative some trivial conversions are
|
||||||
|
/// easier to make in the specializations.
|
||||||
|
template<class T>
|
||||||
|
T
|
||||||
|
ircd::lex_cast(std::string &s)
|
||||||
|
{
|
||||||
|
return lex_cast<T>(string_view{s});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Specialization of a string to string conversion without a warning because
|
||||||
|
/// we can trivially pass through a reference from input to output.
|
||||||
|
template<>
|
||||||
|
inline std::string &
|
||||||
|
ircd::lex_cast(std::string &s)
|
||||||
|
{
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Specialization of a string to string conversion to user's buffer;
|
||||||
|
/// marked as unnecessary because no numerical conversion takes place yet
|
||||||
|
/// data is still copied. (note: warning may be removed; may be intentional)
|
||||||
|
template<>
|
||||||
|
__attribute__((warning("unnecessary lexical cast")))
|
||||||
|
inline ircd::string_view
|
||||||
|
ircd::lex_cast(const string_view &s,
|
||||||
|
char *const &buf,
|
||||||
|
const size_t &max)
|
||||||
|
{
|
||||||
|
s.copy(buf, max);
|
||||||
|
return { buf, max };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Specialization of a string to string conversion to user's buffer;
|
||||||
|
/// marked as unnecessary because no numerical conversion takes place yet
|
||||||
|
/// data is still copied. (note: warning may be removed; may be intentional)
|
||||||
|
template<>
|
||||||
|
__attribute__((warning("unnecessary lexical cast")))
|
||||||
|
inline ircd::string_view
|
||||||
|
ircd::lex_cast(const std::string_view &s,
|
||||||
|
char *const &buf,
|
||||||
|
const size_t &max)
|
||||||
|
{
|
||||||
|
s.copy(buf, max);
|
||||||
|
return { buf, max };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Specialization of a string to string conversion to user's buffer;
|
||||||
|
/// marked as unnecessary because no numerical conversion takes place yet
|
||||||
|
/// data is still copied. (note: warning may be removed; may be intentional)
|
||||||
|
template<>
|
||||||
|
__attribute__((warning("unnecessary lexical cast")))
|
||||||
|
inline ircd::string_view
|
||||||
|
ircd::lex_cast(const std::string &s,
|
||||||
|
char *const &buf,
|
||||||
|
const size_t &max)
|
||||||
|
{
|
||||||
|
s.copy(buf, max);
|
||||||
|
return { buf, max };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Template basis; if no specialization is matched there is no fallback here
|
||||||
|
template<class T>
|
||||||
|
__attribute__((error("unsupported lexical cast")))
|
||||||
|
ircd::string_view
|
||||||
|
ircd::lex_cast(T t,
|
||||||
|
char *const &buf,
|
||||||
|
const size_t &max)
|
||||||
|
{
|
||||||
|
assert(0);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Template basis; if no specialization is matched there is no fallback here
|
||||||
|
template<class T>
|
||||||
|
__attribute__((error("unsupported lexical cast")))
|
||||||
|
bool
|
||||||
|
ircd::try_lex_cast(const string_view &s)
|
||||||
|
{
|
||||||
|
assert(0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trivial conversion; always returns true
|
||||||
|
template<>
|
||||||
|
inline bool
|
||||||
|
ircd::try_lex_cast<ircd::string_view>(const string_view &)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trivial conversion; always returns true
|
||||||
|
template<>
|
||||||
|
inline bool
|
||||||
|
ircd::try_lex_cast<std::string_view>(const string_view &)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trivial conversion; always returns true
|
||||||
|
template<>
|
||||||
|
inline bool
|
||||||
|
ircd::try_lex_cast<std::string>(const string_view &s)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -192,7 +192,9 @@ namespace ircd
|
||||||
#include "localee.h"
|
#include "localee.h"
|
||||||
#include "life_guard.h"
|
#include "life_guard.h"
|
||||||
#include "color.h"
|
#include "color.h"
|
||||||
#include "lexical.h"
|
#include "lex_cast.h"
|
||||||
|
#include "stringops.h"
|
||||||
|
#include "tokens.h"
|
||||||
#include "params.h"
|
#include "params.h"
|
||||||
#include "iov.h"
|
#include "iov.h"
|
||||||
#include "parse.h"
|
#include "parse.h"
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* charybdis: an advanced ircd.
|
* charybdis: an advanced ircd.
|
||||||
* inline/stringops.h: inlined string operations used in a few places
|
* inline/stringops.h: inlined string operations used in a few places
|
||||||
*
|
*
|
||||||
* Copyright (C) 2005-2016 Charybdis Development Team
|
* Copyright (C) 2005-2017 Charybdis Development Team
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -21,154 +21,13 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#define HAVE_IRCD_LEXICAL_H
|
#define HAVE_IRCD_STRING_H
|
||||||
|
|
||||||
//
|
//
|
||||||
// Lexical conversions
|
// Misc string utilities
|
||||||
//
|
//
|
||||||
namespace ircd
|
namespace ircd
|
||||||
{
|
{
|
||||||
IRCD_EXCEPTION_HIDENAME(ircd::error, bad_lex_cast)
|
|
||||||
|
|
||||||
template<class T> bool try_lex_cast(const string_view &);
|
|
||||||
template<> bool try_lex_cast<std::string>(const string_view &); // stub always true
|
|
||||||
template<> bool try_lex_cast<std::string_view>(const string_view &); // stub always true
|
|
||||||
template<> bool try_lex_cast<string_view>(const string_view &); // stub always true
|
|
||||||
template<> bool try_lex_cast<long double>(const string_view &);
|
|
||||||
template<> bool try_lex_cast<double>(const string_view &);
|
|
||||||
template<> bool try_lex_cast<ulong>(const string_view &);
|
|
||||||
template<> bool try_lex_cast<long>(const string_view &);
|
|
||||||
template<> bool try_lex_cast<uint>(const string_view &);
|
|
||||||
template<> bool try_lex_cast<int>(const string_view &);
|
|
||||||
template<> bool try_lex_cast<ushort>(const string_view &);
|
|
||||||
template<> bool try_lex_cast<short>(const string_view &);
|
|
||||||
template<> bool try_lex_cast<uint8_t>(const string_view &);
|
|
||||||
template<> bool try_lex_cast<int8_t>(const string_view &);
|
|
||||||
template<> bool try_lex_cast<bool>(const string_view &);
|
|
||||||
|
|
||||||
template<class T> T lex_cast(std::string &);
|
|
||||||
template<class T> T lex_cast(const std::string &);
|
|
||||||
template<class T> T lex_cast(const std::string_view &);
|
|
||||||
template<class T> T lex_cast(const string_view &);
|
|
||||||
template<> std::string &lex_cast(std::string &); // trivial
|
|
||||||
template<> std::string lex_cast(const std::string &); // trivial
|
|
||||||
template<> std::string_view lex_cast(const std::string_view &); // trivial
|
|
||||||
template<> std::string lex_cast(const string_view &); // trivial
|
|
||||||
template<> long double lex_cast(const string_view &);
|
|
||||||
template<> double lex_cast(const string_view &);
|
|
||||||
template<> ulong lex_cast(const string_view &);
|
|
||||||
template<> long lex_cast(const string_view &);
|
|
||||||
template<> uint lex_cast(const string_view &);
|
|
||||||
template<> int lex_cast(const string_view &);
|
|
||||||
template<> ushort lex_cast(const string_view &);
|
|
||||||
template<> short lex_cast(const string_view &);
|
|
||||||
template<> uint8_t lex_cast(const string_view &);
|
|
||||||
template<> int8_t lex_cast(const string_view &);
|
|
||||||
template<> bool lex_cast(const string_view &);
|
|
||||||
|
|
||||||
// User supplied destination buffer
|
|
||||||
template<class T> string_view lex_cast(T, char *const &buf, const size_t &max);
|
|
||||||
template<> string_view lex_cast(const std::string &, char *const &buf, const size_t &max);
|
|
||||||
template<> string_view lex_cast(const std::string_view &, char *const &buf, const size_t &max);
|
|
||||||
template<> string_view lex_cast(const string_view &, char *const &buf, const size_t &max);
|
|
||||||
template<> string_view lex_cast(long double, char *const &buf, const size_t &max);
|
|
||||||
template<> string_view lex_cast(double, char *const &buf, const size_t &max);
|
|
||||||
template<> string_view lex_cast(ulong, char *const &buf, const size_t &max);
|
|
||||||
template<> string_view lex_cast(long, char *const &buf, const size_t &max);
|
|
||||||
template<> string_view lex_cast(uint, char *const &buf, const size_t &max);
|
|
||||||
template<> string_view lex_cast(int, char *const &buf, const size_t &max);
|
|
||||||
template<> string_view lex_cast(ushort, char *const &buf, const size_t &max);
|
|
||||||
template<> string_view lex_cast(short, char *const &buf, const size_t &max);
|
|
||||||
template<> string_view lex_cast(uint8_t, char *const &buf, const size_t &max);
|
|
||||||
template<> string_view lex_cast(int8_t, char *const &buf, const size_t &max);
|
|
||||||
template<> string_view lex_cast(bool, char *const &buf, const size_t &max);
|
|
||||||
|
|
||||||
// Circular static thread_local buffer
|
|
||||||
const size_t LEX_CAST_BUFS {256}; // plenty
|
|
||||||
template<class T> string_view lex_cast(const T &t);
|
|
||||||
|
|
||||||
//
|
|
||||||
// Binary / Hex / Base64 conversion suite
|
|
||||||
//
|
|
||||||
|
|
||||||
string_view u2a(const mutable_buffer &out, const const_raw_buffer &in);
|
|
||||||
const_raw_buffer a2u(const mutable_raw_buffer &out, const const_buffer &in);
|
|
||||||
string_view b64encode(const mutable_buffer &out, const const_raw_buffer &in);
|
|
||||||
|
|
||||||
//
|
|
||||||
// String tokenization.
|
|
||||||
//
|
|
||||||
|
|
||||||
// Use the closure for best performance. Note that string_view's
|
|
||||||
// are not required to be null terminated. Construct an std::string from the view to allocate
|
|
||||||
// and copy the token with null termination.
|
|
||||||
using token_view = std::function<void (const string_view &)>;
|
|
||||||
void tokens(const string_view &str, const char &sep, const token_view &);
|
|
||||||
void tokens(const string_view &str, const char *const &sep, const token_view &);
|
|
||||||
size_t tokens(const string_view &str, const char &sep, const size_t &limit, const token_view &);
|
|
||||||
size_t tokens(const string_view &str, const char *const &sep, const size_t &limit, const token_view &);
|
|
||||||
|
|
||||||
// Copies tokens into your buffer and null terminates strtok() style. Returns BYTES of buf consumed.
|
|
||||||
size_t tokens(const string_view &str, const char &sep, char *const &buf, const size_t &max, const token_view &);
|
|
||||||
size_t tokens(const string_view &str, const char *const &sep, char *const &buf, const size_t &max, const token_view &);
|
|
||||||
|
|
||||||
// Receive token view into iterator range
|
|
||||||
template<class it, class sep> it tokens(const string_view &str, const sep &, const it &b, const it &e);
|
|
||||||
|
|
||||||
// Receive token view into array
|
|
||||||
template<size_t N, class sep> size_t tokens(const string_view &str, const sep &, string_view (&buf)[N]);
|
|
||||||
template<size_t N, class sep> size_t tokens(const string_view &str, const sep &, std::array<string_view, N> &);
|
|
||||||
|
|
||||||
// Receive token view into new container (custom allocator)
|
|
||||||
template<template<class, class>
|
|
||||||
class C, //= std::vector,
|
|
||||||
class T = string_view,
|
|
||||||
class A,
|
|
||||||
class sep>
|
|
||||||
C<T, A> tokens(A&& allocator, const string_view &str, const sep &);
|
|
||||||
|
|
||||||
// Receive token view into new container
|
|
||||||
template<template<class, class>
|
|
||||||
class C, //= std::vector,
|
|
||||||
class T = string_view,
|
|
||||||
class A = std::allocator<T>,
|
|
||||||
class sep>
|
|
||||||
C<T, A> tokens(const string_view &str, const sep &);
|
|
||||||
|
|
||||||
// Receive token view into new associative container (custom allocator)
|
|
||||||
template<template<class, class, class>
|
|
||||||
class C,
|
|
||||||
class T = string_view,
|
|
||||||
class Comp = std::less<T>,
|
|
||||||
class A,
|
|
||||||
class sep>
|
|
||||||
C<T, Comp, A> tokens(A&& allocator, const string_view &str, const sep &);
|
|
||||||
|
|
||||||
// Receive token view into new associative container
|
|
||||||
template<template<class, class, class>
|
|
||||||
class C,
|
|
||||||
class T = string_view,
|
|
||||||
class Comp = std::less<T>,
|
|
||||||
class A = std::allocator<T>,
|
|
||||||
class sep>
|
|
||||||
C<T, Comp, A> tokens(const string_view &str, const sep &);
|
|
||||||
|
|
||||||
// Convenience to get individual tokens
|
|
||||||
size_t tokens_count(const string_view &str, const char &sep);
|
|
||||||
size_t tokens_count(const string_view &str, const char *const &sep);
|
|
||||||
string_view token(const string_view &str, const char &sep, const size_t &at);
|
|
||||||
string_view token(const string_view &str, const char *const &sep, const size_t &at);
|
|
||||||
string_view token_last(const string_view &str, const char &sep);
|
|
||||||
string_view token_last(const string_view &str, const char *const &sep);
|
|
||||||
string_view token_first(const string_view &str, const char &sep);
|
|
||||||
string_view token_first(const string_view &str, const char *const &sep);
|
|
||||||
string_view tokens_after(const string_view &str, const char &sep, const size_t &at);
|
|
||||||
string_view tokens_after(const string_view &str, const char *const &sep, const size_t &at);
|
|
||||||
|
|
||||||
//
|
|
||||||
// Misc utils
|
|
||||||
//
|
|
||||||
|
|
||||||
// Simple case insensitive comparison convenience utils
|
// Simple case insensitive comparison convenience utils
|
||||||
struct iless;
|
struct iless;
|
||||||
struct igreater;
|
struct igreater;
|
||||||
|
@ -180,39 +39,66 @@ namespace ircd
|
||||||
size_t strlcpy(char *const &dest, const string_view &src, const size_t &bufmax);
|
size_t strlcpy(char *const &dest, const string_view &src, const size_t &bufmax);
|
||||||
size_t strlcat(char *const &dest, const string_view &src, const size_t &bufmax);
|
size_t strlcat(char *const &dest, const string_view &src, const size_t &bufmax);
|
||||||
|
|
||||||
|
// return view without trailing c
|
||||||
|
string_view rstrip(const string_view &str, const char &c = ' ');
|
||||||
|
string_view rstrip(const string_view &str, const string_view &c);
|
||||||
|
|
||||||
|
// return view without leading c
|
||||||
|
string_view lstrip(const string_view &str, const char &c = ' ');
|
||||||
|
string_view lstrip(const string_view &str, const string_view &c);
|
||||||
|
|
||||||
|
// return view without leading and trailing c
|
||||||
|
string_view strip(const string_view &str, const char &c = ' ');
|
||||||
|
string_view strip(const string_view &str, const string_view &c);
|
||||||
|
|
||||||
|
// split view on first match of delim; delim not included; no delim .second empty
|
||||||
|
std::pair<string_view, string_view> split(const string_view &str, const char &delim = ' ');
|
||||||
|
std::pair<string_view, string_view> split(const string_view &str, const string_view &delim);
|
||||||
|
|
||||||
|
// split view on last match of delim; delim not included; no delim .second empty
|
||||||
|
std::pair<string_view, string_view> rsplit(const string_view &str, const char &delim = ' ');
|
||||||
|
std::pair<string_view, string_view> rsplit(const string_view &str, const string_view &delim);
|
||||||
|
|
||||||
|
// view between first match of delim a and first match of delim b after it
|
||||||
|
string_view between(const string_view &str, const string_view &a, const string_view &b);
|
||||||
|
string_view between(const string_view &str, const char &a = '(', const char &b = ')');
|
||||||
|
|
||||||
|
// test string endswith delim; or any of the delims in iterable
|
||||||
|
bool endswith(const string_view &str, const string_view &val);
|
||||||
|
bool endswith(const string_view &str, const char &val);
|
||||||
|
template<class It> bool endswith_any(const string_view &str, const It &begin, const It &end);
|
||||||
|
|
||||||
|
// test string startswith delim; or any of the delims in iterable
|
||||||
|
bool startswith(const string_view &str, const string_view &val);
|
||||||
|
bool startswith(const string_view &str, const char &val);
|
||||||
|
template<class It> bool startswith_any(const string_view &str, const It &begin, const It &end);
|
||||||
|
|
||||||
|
// test string is surrounded by val (ex. surrounded by quote characters)
|
||||||
|
bool surrounds(const string_view &str, const string_view &val);
|
||||||
|
bool surrounds(const string_view &str, const char &val);
|
||||||
|
|
||||||
|
// pop trailing char from view
|
||||||
|
char chop(string_view &str);
|
||||||
|
|
||||||
|
// remove trailing from view and return num chars removed
|
||||||
|
size_t chomp(string_view &str, const char &c = '\n');
|
||||||
|
size_t chomp(string_view &str, const string_view &c);
|
||||||
|
template<class T, class delim> size_t chomp(iterators<T>, const delim &d);
|
||||||
|
|
||||||
|
// Convenience to strip quotes
|
||||||
|
string_view unquote(const string_view &str);
|
||||||
|
std::string unquote(std::string &&);
|
||||||
|
|
||||||
// Legacy
|
// Legacy
|
||||||
char *strip_colour(char *string);
|
char *strip_colour(char *string);
|
||||||
char *strip_unprintable(char *string);
|
char *strip_unprintable(char *string);
|
||||||
char *reconstruct_parv(int parc, const char **parv);
|
char *reconstruct_parv(int parc, const char **parv);
|
||||||
|
|
||||||
char chop(string_view &str);
|
|
||||||
size_t chomp(string_view &str, const char &c = '\n');
|
|
||||||
size_t chomp(string_view &str, const string_view &c);
|
|
||||||
template<class T, class delim> size_t chomp(iterators<T>, const delim &d);
|
|
||||||
string_view rstrip(const string_view &str, const char &c = ' ');
|
|
||||||
string_view rstrip(const string_view &str, const string_view &c);
|
|
||||||
string_view lstrip(const string_view &str, const char &c = ' ');
|
|
||||||
string_view lstrip(const string_view &str, const string_view &c);
|
|
||||||
string_view strip(const string_view &str, const char &c = ' ');
|
|
||||||
string_view strip(const string_view &str, const string_view &c);
|
|
||||||
std::pair<string_view, string_view> split(const string_view &str, const char &delim = ' ');
|
|
||||||
std::pair<string_view, string_view> split(const string_view &str, const string_view &delim);
|
|
||||||
std::pair<string_view, string_view> rsplit(const string_view &str, const char &delim = ' ');
|
|
||||||
std::pair<string_view, string_view> rsplit(const string_view &str, const string_view &delim);
|
|
||||||
string_view between(const string_view &str, const string_view &a, const string_view &b);
|
|
||||||
string_view between(const string_view &str, const char &a = '(', const char &b = ')');
|
|
||||||
bool endswith(const string_view &str, const string_view &val);
|
|
||||||
bool endswith(const string_view &str, const char &val);
|
|
||||||
template<class It> bool endswith_any(const string_view &str, const It &begin, const It &end);
|
|
||||||
bool startswith(const string_view &str, const string_view &val);
|
|
||||||
bool startswith(const string_view &str, const char &val);
|
|
||||||
template<class It> bool startswith_any(const string_view &str, const It &begin, const It &end);
|
|
||||||
bool surrounds(const string_view &str, const string_view &val);
|
|
||||||
bool surrounds(const string_view &str, const char &val);
|
|
||||||
string_view unquote(string_view str);
|
|
||||||
std::string unquote(std::string &&);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Remove quotes on an std::string. Only operates on an rvalue reference so
|
||||||
|
/// that a copy of the string is not created when no quotes are found, and
|
||||||
|
/// movements can take place if they are. This overload is not needed often;
|
||||||
|
/// use string_view.
|
||||||
inline std::string
|
inline std::string
|
||||||
ircd::unquote(std::string &&str)
|
ircd::unquote(std::string &&str)
|
||||||
{
|
{
|
||||||
|
@ -225,18 +111,71 @@ ircd::unquote(std::string &&str)
|
||||||
return std::move(str);
|
return std::move(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Common convenience to remove quotes around the view of the string
|
||||||
inline ircd::string_view
|
inline ircd::string_view
|
||||||
ircd::unquote(string_view str)
|
ircd::unquote(const string_view &str)
|
||||||
{
|
{
|
||||||
if(startswith(str, '"'))
|
return strip(str, '"');
|
||||||
str = { str.data() + 1, str.data() + str.size() };
|
|
||||||
|
|
||||||
if(endswith(str, '"'))
|
|
||||||
str = { str.data(), str.data() + str.size() - 1 };
|
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Chomps delim from all of the string views in the iterable (iterators<T> are
|
||||||
|
/// the T::iterator pair {begin(t), end(t)} of an iterable T) and returns the
|
||||||
|
/// total number of characters removed from all operations.
|
||||||
|
template<class T,
|
||||||
|
class delim>
|
||||||
|
size_t
|
||||||
|
ircd::chomp(iterators<T> its,
|
||||||
|
const delim &d)
|
||||||
|
{
|
||||||
|
return std::accumulate(begin(its), end(its), size_t(0), [&d]
|
||||||
|
(auto ret, const auto &s)
|
||||||
|
{
|
||||||
|
return ret += chomp(s, d);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Removes all characters from the end of the view starting with the last
|
||||||
|
/// instance of c. Different from rstrip() in that this will remove more than
|
||||||
|
/// just the delim from the end; it removes both the delim and everything after
|
||||||
|
/// it from wherever the last delim may be. Removes nothing if no delim is.
|
||||||
|
inline size_t
|
||||||
|
ircd::chomp(string_view &str,
|
||||||
|
const char &c)
|
||||||
|
{
|
||||||
|
const auto pos(str.find_last_of(c));
|
||||||
|
if(pos == string_view::npos)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
assert(str.size() - pos == 1);
|
||||||
|
str = str.substr(0, pos);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Removes all characters from the end of the view starting with the last
|
||||||
|
/// instance of c. This matches the entire delim string c to chomp it and
|
||||||
|
/// everything after it.
|
||||||
|
inline size_t
|
||||||
|
ircd::chomp(string_view &str,
|
||||||
|
const string_view &c)
|
||||||
|
{
|
||||||
|
const auto pos(str.find_last_of(c));
|
||||||
|
if(pos == string_view::npos)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
assert(str.size() - pos == c.size());
|
||||||
|
str = str.substr(0, pos);
|
||||||
|
return c.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Removes any last character from the view, modifying the view, and returning
|
||||||
|
/// that character.
|
||||||
|
inline char
|
||||||
|
ircd::chop(string_view &str)
|
||||||
|
{
|
||||||
|
return !str.empty()? str.pop_back() : '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Test if a string starts and ends with character
|
||||||
inline bool
|
inline bool
|
||||||
ircd::surrounds(const string_view &str,
|
ircd::surrounds(const string_view &str,
|
||||||
const char &val)
|
const char &val)
|
||||||
|
@ -244,6 +183,7 @@ ircd::surrounds(const string_view &str,
|
||||||
return str.size() >= 2 && str.front() == val && str.back() == val;
|
return str.size() >= 2 && str.front() == val && str.back() == val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Test if a string starts and ends with a string
|
||||||
inline bool
|
inline bool
|
||||||
ircd::surrounds(const string_view &str,
|
ircd::surrounds(const string_view &str,
|
||||||
const string_view &val)
|
const string_view &val)
|
||||||
|
@ -251,6 +191,7 @@ ircd::surrounds(const string_view &str,
|
||||||
return startswith(str, val) && endswith(str, val);
|
return startswith(str, val) && endswith(str, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Test if a string starts with any of the values in the iterable
|
||||||
template<class It>
|
template<class It>
|
||||||
bool
|
bool
|
||||||
ircd::startswith_any(const string_view &str,
|
ircd::startswith_any(const string_view &str,
|
||||||
|
@ -263,6 +204,7 @@ ircd::startswith_any(const string_view &str,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Test if a string starts with a character
|
||||||
inline bool
|
inline bool
|
||||||
ircd::startswith(const string_view &str,
|
ircd::startswith(const string_view &str,
|
||||||
const char &val)
|
const char &val)
|
||||||
|
@ -270,6 +212,7 @@ ircd::startswith(const string_view &str,
|
||||||
return !str.empty() && str[0] == val;
|
return !str.empty() && str[0] == val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Test if a string starts with a string
|
||||||
inline bool
|
inline bool
|
||||||
ircd::startswith(const string_view &str,
|
ircd::startswith(const string_view &str,
|
||||||
const string_view &val)
|
const string_view &val)
|
||||||
|
@ -278,6 +221,7 @@ ircd::startswith(const string_view &str,
|
||||||
return pos == 0;
|
return pos == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Test if a string ends with any of the values in iterable
|
||||||
template<class It>
|
template<class It>
|
||||||
bool
|
bool
|
||||||
ircd::endswith_any(const string_view &str,
|
ircd::endswith_any(const string_view &str,
|
||||||
|
@ -290,6 +234,7 @@ ircd::endswith_any(const string_view &str,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Test if a string ends with character
|
||||||
inline bool
|
inline bool
|
||||||
ircd::endswith(const string_view &str,
|
ircd::endswith(const string_view &str,
|
||||||
const char &val)
|
const char &val)
|
||||||
|
@ -297,6 +242,7 @@ ircd::endswith(const string_view &str,
|
||||||
return !str.empty() && str[str.size()-1] == val;
|
return !str.empty() && str[str.size()-1] == val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Test if a string ends with a string
|
||||||
inline bool
|
inline bool
|
||||||
ircd::endswith(const string_view &str,
|
ircd::endswith(const string_view &str,
|
||||||
const string_view &val)
|
const string_view &val)
|
||||||
|
@ -306,6 +252,8 @@ ircd::endswith(const string_view &str,
|
||||||
return pos == str.size() - vlen;
|
return pos == str.size() - vlen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// View a string between the first match of a and the first match of b
|
||||||
|
/// after a.
|
||||||
inline ircd::string_view
|
inline ircd::string_view
|
||||||
ircd::between(const string_view &str,
|
ircd::between(const string_view &str,
|
||||||
const string_view &a,
|
const string_view &a,
|
||||||
|
@ -314,6 +262,8 @@ ircd::between(const string_view &str,
|
||||||
return split(split(str, a).second, b).first;
|
return split(split(str, a).second, b).first;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// View a string between the first match of a and the first match of b
|
||||||
|
/// after a.
|
||||||
inline ircd::string_view
|
inline ircd::string_view
|
||||||
ircd::between(const string_view &str,
|
ircd::between(const string_view &str,
|
||||||
const char &a,
|
const char &a,
|
||||||
|
@ -322,6 +272,8 @@ ircd::between(const string_view &str,
|
||||||
return split(split(str, a).second, b).first;
|
return split(split(str, a).second, b).first;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Split a string on the last match of delim. Delim not included; no match
|
||||||
|
/// will return original str in pair.first, pair.second empty.
|
||||||
inline std::pair<ircd::string_view, ircd::string_view>
|
inline std::pair<ircd::string_view, ircd::string_view>
|
||||||
ircd::rsplit(const string_view &str,
|
ircd::rsplit(const string_view &str,
|
||||||
const string_view &delim)
|
const string_view &delim)
|
||||||
|
@ -339,6 +291,8 @@ ircd::rsplit(const string_view &str,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Split a string on the last match of delim. Delim not included; no match
|
||||||
|
/// will return original str in pair.first, pair.second empty.
|
||||||
inline std::pair<ircd::string_view, ircd::string_view>
|
inline std::pair<ircd::string_view, ircd::string_view>
|
||||||
ircd::rsplit(const string_view &str,
|
ircd::rsplit(const string_view &str,
|
||||||
const char &delim)
|
const char &delim)
|
||||||
|
@ -356,6 +310,8 @@ ircd::rsplit(const string_view &str,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Split a string on the first match of delim. Delim not included; no match
|
||||||
|
/// will return original str in pair.first, pair.second empty.
|
||||||
inline std::pair<ircd::string_view, ircd::string_view>
|
inline std::pair<ircd::string_view, ircd::string_view>
|
||||||
ircd::split(const string_view &str,
|
ircd::split(const string_view &str,
|
||||||
const string_view &delim)
|
const string_view &delim)
|
||||||
|
@ -373,6 +329,8 @@ ircd::split(const string_view &str,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Split a string on the first match of delim. Delim not included; no match
|
||||||
|
/// will return original str in pair.first, pair.second empty.
|
||||||
inline std::pair<ircd::string_view, ircd::string_view>
|
inline std::pair<ircd::string_view, ircd::string_view>
|
||||||
ircd::split(const string_view &str,
|
ircd::split(const string_view &str,
|
||||||
const char &delim)
|
const char &delim)
|
||||||
|
@ -390,6 +348,7 @@ ircd::split(const string_view &str,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Remove leading and trailing instances of c from the returned view
|
||||||
inline ircd::string_view
|
inline ircd::string_view
|
||||||
ircd::strip(const string_view &str,
|
ircd::strip(const string_view &str,
|
||||||
const string_view &c)
|
const string_view &c)
|
||||||
|
@ -397,6 +356,7 @@ ircd::strip(const string_view &str,
|
||||||
return lstrip(rstrip(str, c), c);
|
return lstrip(rstrip(str, c), c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Remove leading and trailing instances of c from the returned view
|
||||||
inline ircd::string_view
|
inline ircd::string_view
|
||||||
ircd::strip(const string_view &str,
|
ircd::strip(const string_view &str,
|
||||||
const char &c)
|
const char &c)
|
||||||
|
@ -404,6 +364,7 @@ ircd::strip(const string_view &str,
|
||||||
return lstrip(rstrip(str, c), c);
|
return lstrip(rstrip(str, c), c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Remove trailing instances of c from the returned view
|
||||||
inline ircd::string_view
|
inline ircd::string_view
|
||||||
ircd::rstrip(const string_view &str,
|
ircd::rstrip(const string_view &str,
|
||||||
const string_view &c)
|
const string_view &c)
|
||||||
|
@ -412,6 +373,7 @@ ircd::rstrip(const string_view &str,
|
||||||
return pos != string_view::npos? string_view{str.substr(0, pos + 1)} : str;
|
return pos != string_view::npos? string_view{str.substr(0, pos + 1)} : str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Remove trailing instances of c from the returned view
|
||||||
inline ircd::string_view
|
inline ircd::string_view
|
||||||
ircd::rstrip(const string_view &str,
|
ircd::rstrip(const string_view &str,
|
||||||
const char &c)
|
const char &c)
|
||||||
|
@ -420,6 +382,7 @@ ircd::rstrip(const string_view &str,
|
||||||
return pos != string_view::npos? string_view{str.substr(0, pos + 1)} : str;
|
return pos != string_view::npos? string_view{str.substr(0, pos + 1)} : str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Remove leading instances of c from the returned view
|
||||||
inline ircd::string_view
|
inline ircd::string_view
|
||||||
ircd::lstrip(const string_view &str,
|
ircd::lstrip(const string_view &str,
|
||||||
const char &c)
|
const char &c)
|
||||||
|
@ -428,6 +391,7 @@ ircd::lstrip(const string_view &str,
|
||||||
return pos != string_view::npos? string_view{str.substr(pos)} : string_view{};
|
return pos != string_view::npos? string_view{str.substr(pos)} : string_view{};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Remove leading instances of c from the returned view
|
||||||
inline ircd::string_view
|
inline ircd::string_view
|
||||||
ircd::lstrip(const string_view &str,
|
ircd::lstrip(const string_view &str,
|
||||||
const string_view &c)
|
const string_view &c)
|
||||||
|
@ -436,160 +400,7 @@ ircd::lstrip(const string_view &str,
|
||||||
return pos != string_view::npos? string_view{str.substr(pos)} : string_view{};
|
return pos != string_view::npos? string_view{str.substr(pos)} : string_view{};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T,
|
/// Copy a string to dst will guaranteed null terminated output
|
||||||
class delim>
|
|
||||||
size_t
|
|
||||||
ircd::chomp(iterators<T> its,
|
|
||||||
const delim &d)
|
|
||||||
{
|
|
||||||
return std::accumulate(begin(its), end(its), size_t(0), [&d]
|
|
||||||
(auto ret, const auto &s)
|
|
||||||
{
|
|
||||||
return ret += chomp(s, d);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
inline size_t
|
|
||||||
ircd::chomp(string_view &str,
|
|
||||||
const char &c)
|
|
||||||
{
|
|
||||||
const auto pos(str.find_last_of(c));
|
|
||||||
if(pos == string_view::npos)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
assert(str.size() - pos == 1);
|
|
||||||
str = str.substr(0, pos);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline size_t
|
|
||||||
ircd::chomp(string_view &str,
|
|
||||||
const string_view &c)
|
|
||||||
{
|
|
||||||
const auto pos(str.find_last_of(c));
|
|
||||||
if(pos == string_view::npos)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
assert(str.size() - pos == c.size());
|
|
||||||
str = str.substr(0, pos);
|
|
||||||
return c.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline char
|
|
||||||
ircd::chop(string_view &str)
|
|
||||||
{
|
|
||||||
return !str.empty()? str.pop_back() : '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
template<size_t N,
|
|
||||||
class delim>
|
|
||||||
size_t
|
|
||||||
ircd::tokens(const string_view &str,
|
|
||||||
const delim &sep,
|
|
||||||
string_view (&buf)[N])
|
|
||||||
{
|
|
||||||
const auto e(tokens(str, sep, begin(buf), end(buf)));
|
|
||||||
return std::distance(begin(buf), e);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<size_t N,
|
|
||||||
class delim>
|
|
||||||
size_t
|
|
||||||
ircd::tokens(const string_view &str,
|
|
||||||
const delim &sep,
|
|
||||||
std::array<string_view, N> &buf)
|
|
||||||
{
|
|
||||||
const auto e(tokens(str, sep, begin(buf), end(buf)));
|
|
||||||
return std::distance(begin(buf), e);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class it,
|
|
||||||
class delim>
|
|
||||||
it
|
|
||||||
ircd::tokens(const string_view &str,
|
|
||||||
const delim &sep,
|
|
||||||
const it &b,
|
|
||||||
const it &e)
|
|
||||||
{
|
|
||||||
it pos(b);
|
|
||||||
tokens(str, sep, std::distance(b, e), [&pos]
|
|
||||||
(const string_view &token)
|
|
||||||
{
|
|
||||||
*pos = token;
|
|
||||||
++pos;
|
|
||||||
});
|
|
||||||
|
|
||||||
return pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<template<class, class, class>
|
|
||||||
class C,
|
|
||||||
class T,
|
|
||||||
class Comp,
|
|
||||||
class A,
|
|
||||||
class delim>
|
|
||||||
C<T, Comp, A>
|
|
||||||
ircd::tokens(const string_view &str,
|
|
||||||
const delim &sep)
|
|
||||||
{
|
|
||||||
A allocator;
|
|
||||||
return tokens<C, T, Comp, A>(allocator, str, sep);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<template<class, class, class>
|
|
||||||
class C,
|
|
||||||
class T,
|
|
||||||
class Comp,
|
|
||||||
class A,
|
|
||||||
class delim>
|
|
||||||
C<T, Comp, A>
|
|
||||||
ircd::tokens(A&& allocator,
|
|
||||||
const string_view &str,
|
|
||||||
const delim &sep)
|
|
||||||
{
|
|
||||||
C<T, Comp, A> ret(std::forward<A>(allocator));
|
|
||||||
tokens(str, sep, [&ret]
|
|
||||||
(const string_view &token)
|
|
||||||
{
|
|
||||||
ret.emplace(ret.end(), token);
|
|
||||||
});
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<template<class, class>
|
|
||||||
class C,
|
|
||||||
class T,
|
|
||||||
class A,
|
|
||||||
class delim>
|
|
||||||
C<T, A>
|
|
||||||
ircd::tokens(const string_view &str,
|
|
||||||
const delim &sep)
|
|
||||||
{
|
|
||||||
A allocator;
|
|
||||||
return tokens<C, T, A>(allocator, str, sep);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<template<class, class>
|
|
||||||
class C,
|
|
||||||
class T,
|
|
||||||
class A,
|
|
||||||
class delim>
|
|
||||||
C<T, A>
|
|
||||||
ircd::tokens(A&& allocator,
|
|
||||||
const string_view &str,
|
|
||||||
const delim &sep)
|
|
||||||
{
|
|
||||||
C<T, A> ret(std::forward<A>(allocator));
|
|
||||||
tokens(str, sep, [&ret]
|
|
||||||
(const string_view &token)
|
|
||||||
{
|
|
||||||
ret.emplace(ret.end(), token);
|
|
||||||
});
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline size_t
|
inline size_t
|
||||||
ircd::strlcpy(char *const &dst,
|
ircd::strlcpy(char *const &dst,
|
||||||
const string_view &src,
|
const string_view &src,
|
||||||
|
@ -626,6 +437,8 @@ ircd::strlcpy(char *const &dst,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/// Append a string to dst will guaranteed null terminated output; Expects
|
||||||
|
/// dst to have null termination before calling this function.
|
||||||
inline size_t
|
inline size_t
|
||||||
ircd::strlcat(char *const &dst,
|
ircd::strlcat(char *const &dst,
|
||||||
const string_view &src,
|
const string_view &src,
|
||||||
|
@ -655,6 +468,8 @@ ircd::strlcat(char *const &dst,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/// Case insensitive string comparison deciding which string compares 'less'
|
||||||
|
/// than the other.
|
||||||
struct ircd::iless
|
struct ircd::iless
|
||||||
{
|
{
|
||||||
using is_transparent = std::true_type;
|
using is_transparent = std::true_type;
|
||||||
|
@ -713,6 +528,7 @@ const
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Case insensitive string comparison deciding if two strings are equal
|
||||||
struct ircd::iequals
|
struct ircd::iequals
|
||||||
{
|
{
|
||||||
using is_transparent = std::true_type;
|
using is_transparent = std::true_type;
|
||||||
|
@ -771,6 +587,8 @@ const
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Case insensitive string comparison deciding which string compares 'greater'
|
||||||
|
/// than the other.
|
||||||
struct ircd::igreater
|
struct ircd::igreater
|
||||||
{
|
{
|
||||||
using is_transparent = std::true_type;
|
using is_transparent = std::true_type;
|
||||||
|
@ -828,131 +646,3 @@ const
|
||||||
return tolower(a) > tolower(b);
|
return tolower(a) > tolower(b);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
|
||||||
ircd::string_view
|
|
||||||
ircd::lex_cast(const T &t)
|
|
||||||
{
|
|
||||||
return lex_cast<T>(t, nullptr, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
inline std::string
|
|
||||||
ircd::lex_cast<std::string>(const string_view &s)
|
|
||||||
{
|
|
||||||
return std::string{s};
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
T
|
|
||||||
ircd::lex_cast(const string_view &s)
|
|
||||||
{
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
inline std::string_view
|
|
||||||
ircd::lex_cast<std::string_view>(const std::string_view &s)
|
|
||||||
{
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
__attribute__((warning("unnecessary lexical cast")))
|
|
||||||
inline std::string
|
|
||||||
ircd::lex_cast<std::string>(const std::string &s)
|
|
||||||
{
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
T
|
|
||||||
ircd::lex_cast(const std::string &s)
|
|
||||||
{
|
|
||||||
return lex_cast<T>(string_view{s});
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
inline std::string &
|
|
||||||
ircd::lex_cast(std::string &s)
|
|
||||||
{
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
T
|
|
||||||
ircd::lex_cast(std::string &s)
|
|
||||||
{
|
|
||||||
return lex_cast<T>(string_view{s});
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
inline ircd::string_view
|
|
||||||
ircd::lex_cast(const string_view &s,
|
|
||||||
char *const &buf,
|
|
||||||
const size_t &max)
|
|
||||||
{
|
|
||||||
s.copy(buf, max);
|
|
||||||
return { buf, max };
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
inline ircd::string_view
|
|
||||||
ircd::lex_cast(const std::string_view &s,
|
|
||||||
char *const &buf,
|
|
||||||
const size_t &max)
|
|
||||||
{
|
|
||||||
s.copy(buf, max);
|
|
||||||
return { buf, max };
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
inline ircd::string_view
|
|
||||||
ircd::lex_cast(const std::string &s,
|
|
||||||
char *const &buf,
|
|
||||||
const size_t &max)
|
|
||||||
{
|
|
||||||
s.copy(buf, max);
|
|
||||||
return { buf, max };
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
__attribute__((error("unsupported lexical cast")))
|
|
||||||
ircd::string_view
|
|
||||||
ircd::lex_cast(T t,
|
|
||||||
char *const &buf,
|
|
||||||
const size_t &max)
|
|
||||||
{
|
|
||||||
assert(0);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
inline bool
|
|
||||||
ircd::try_lex_cast<ircd::string_view>(const string_view &)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
inline bool
|
|
||||||
ircd::try_lex_cast<std::string_view>(const string_view &)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
inline bool
|
|
||||||
ircd::try_lex_cast<std::string>(const string_view &s)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
__attribute__((error("unsupported lexical cast")))
|
|
||||||
bool
|
|
||||||
ircd::try_lex_cast(const string_view &s)
|
|
||||||
{
|
|
||||||
assert(0);
|
|
||||||
return false;
|
|
||||||
}
|
|
205
include/ircd/tokens.h
Normal file
205
include/ircd/tokens.h
Normal file
|
@ -0,0 +1,205 @@
|
||||||
|
/*
|
||||||
|
* charybdis: an advanced ircd.
|
||||||
|
* inline/stringops.h: inlined string operations used in a few places
|
||||||
|
*
|
||||||
|
* Copyright (C) 2005-2016 Charybdis Development Team
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||||
|
* USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#define HAVE_IRCD_TOKENS_H
|
||||||
|
|
||||||
|
//
|
||||||
|
// String tokenization utils
|
||||||
|
//
|
||||||
|
namespace ircd
|
||||||
|
{
|
||||||
|
// Use the closure for best performance. Note that string_view's are not
|
||||||
|
// required to be null terminated. Construct an std::string from the view
|
||||||
|
// to allocate and copy the token with null termination.
|
||||||
|
using token_view = std::function<void (const string_view &)>;
|
||||||
|
void tokens(const string_view &str, const char &sep, const token_view &);
|
||||||
|
void tokens(const string_view &str, const char *const &sep, const token_view &);
|
||||||
|
size_t tokens(const string_view &str, const char &sep, const size_t &limit, const token_view &);
|
||||||
|
size_t tokens(const string_view &str, const char *const &sep, const size_t &limit, const token_view &);
|
||||||
|
|
||||||
|
// Copies tokens into your buffer and null terminates strtok() style. Returns BYTES of buf consumed.
|
||||||
|
size_t tokens(const string_view &str, const char &sep, char *const &buf, const size_t &max, const token_view &);
|
||||||
|
size_t tokens(const string_view &str, const char *const &sep, char *const &buf, const size_t &max, const token_view &);
|
||||||
|
|
||||||
|
// Receive token view into iterator range
|
||||||
|
template<class it, class sep> it tokens(const string_view &str, const sep &, const it &b, const it &e);
|
||||||
|
|
||||||
|
// Receive token view into array
|
||||||
|
template<size_t N, class sep> size_t tokens(const string_view &str, const sep &, string_view (&buf)[N]);
|
||||||
|
template<size_t N, class sep> size_t tokens(const string_view &str, const sep &, std::array<string_view, N> &);
|
||||||
|
|
||||||
|
// Receive token view into new container (custom allocator)
|
||||||
|
template<template<class, class>
|
||||||
|
class C, //= std::vector,
|
||||||
|
class T = string_view,
|
||||||
|
class A,
|
||||||
|
class sep>
|
||||||
|
C<T, A> tokens(A&& allocator, const string_view &str, const sep &);
|
||||||
|
|
||||||
|
// Receive token view into new container
|
||||||
|
template<template<class, class>
|
||||||
|
class C, //= std::vector,
|
||||||
|
class T = string_view,
|
||||||
|
class A = std::allocator<T>,
|
||||||
|
class sep>
|
||||||
|
C<T, A> tokens(const string_view &str, const sep &);
|
||||||
|
|
||||||
|
// Receive token view into new associative container (custom allocator)
|
||||||
|
template<template<class, class, class>
|
||||||
|
class C,
|
||||||
|
class T = string_view,
|
||||||
|
class Comp = std::less<T>,
|
||||||
|
class A,
|
||||||
|
class sep>
|
||||||
|
C<T, Comp, A> tokens(A&& allocator, const string_view &str, const sep &);
|
||||||
|
|
||||||
|
// Receive token view into new associative container
|
||||||
|
template<template<class, class, class>
|
||||||
|
class C,
|
||||||
|
class T = string_view,
|
||||||
|
class Comp = std::less<T>,
|
||||||
|
class A = std::allocator<T>,
|
||||||
|
class sep>
|
||||||
|
C<T, Comp, A> tokens(const string_view &str, const sep &);
|
||||||
|
|
||||||
|
// Convenience to get individual tokens
|
||||||
|
size_t tokens_count(const string_view &str, const char &sep);
|
||||||
|
size_t tokens_count(const string_view &str, const char *const &sep);
|
||||||
|
string_view token(const string_view &str, const char &sep, const size_t &at);
|
||||||
|
string_view token(const string_view &str, const char *const &sep, const size_t &at);
|
||||||
|
string_view token_last(const string_view &str, const char &sep);
|
||||||
|
string_view token_last(const string_view &str, const char *const &sep);
|
||||||
|
string_view token_first(const string_view &str, const char &sep);
|
||||||
|
string_view token_first(const string_view &str, const char *const &sep);
|
||||||
|
string_view tokens_after(const string_view &str, const char &sep, const size_t &at);
|
||||||
|
string_view tokens_after(const string_view &str, const char *const &sep, const size_t &at);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<size_t N,
|
||||||
|
class delim>
|
||||||
|
size_t
|
||||||
|
ircd::tokens(const string_view &str,
|
||||||
|
const delim &sep,
|
||||||
|
string_view (&buf)[N])
|
||||||
|
{
|
||||||
|
const auto e(tokens(str, sep, begin(buf), end(buf)));
|
||||||
|
return std::distance(begin(buf), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<size_t N,
|
||||||
|
class delim>
|
||||||
|
size_t
|
||||||
|
ircd::tokens(const string_view &str,
|
||||||
|
const delim &sep,
|
||||||
|
std::array<string_view, N> &buf)
|
||||||
|
{
|
||||||
|
const auto e(tokens(str, sep, begin(buf), end(buf)));
|
||||||
|
return std::distance(begin(buf), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class it,
|
||||||
|
class delim>
|
||||||
|
it
|
||||||
|
ircd::tokens(const string_view &str,
|
||||||
|
const delim &sep,
|
||||||
|
const it &b,
|
||||||
|
const it &e)
|
||||||
|
{
|
||||||
|
it pos(b);
|
||||||
|
tokens(str, sep, std::distance(b, e), [&pos]
|
||||||
|
(const string_view &token)
|
||||||
|
{
|
||||||
|
*pos = token;
|
||||||
|
++pos;
|
||||||
|
});
|
||||||
|
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<template<class, class, class>
|
||||||
|
class C,
|
||||||
|
class T,
|
||||||
|
class Comp,
|
||||||
|
class A,
|
||||||
|
class delim>
|
||||||
|
C<T, Comp, A>
|
||||||
|
ircd::tokens(const string_view &str,
|
||||||
|
const delim &sep)
|
||||||
|
{
|
||||||
|
A allocator;
|
||||||
|
return tokens<C, T, Comp, A>(allocator, str, sep);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<template<class, class, class>
|
||||||
|
class C,
|
||||||
|
class T,
|
||||||
|
class Comp,
|
||||||
|
class A,
|
||||||
|
class delim>
|
||||||
|
C<T, Comp, A>
|
||||||
|
ircd::tokens(A&& allocator,
|
||||||
|
const string_view &str,
|
||||||
|
const delim &sep)
|
||||||
|
{
|
||||||
|
C<T, Comp, A> ret(std::forward<A>(allocator));
|
||||||
|
tokens(str, sep, [&ret]
|
||||||
|
(const string_view &token)
|
||||||
|
{
|
||||||
|
ret.emplace(ret.end(), token);
|
||||||
|
});
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<template<class, class>
|
||||||
|
class C,
|
||||||
|
class T,
|
||||||
|
class A,
|
||||||
|
class delim>
|
||||||
|
C<T, A>
|
||||||
|
ircd::tokens(const string_view &str,
|
||||||
|
const delim &sep)
|
||||||
|
{
|
||||||
|
A allocator;
|
||||||
|
return tokens<C, T, A>(allocator, str, sep);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<template<class, class>
|
||||||
|
class C,
|
||||||
|
class T,
|
||||||
|
class A,
|
||||||
|
class delim>
|
||||||
|
C<T, A>
|
||||||
|
ircd::tokens(A&& allocator,
|
||||||
|
const string_view &str,
|
||||||
|
const delim &sep)
|
||||||
|
{
|
||||||
|
C<T, A> ret(std::forward<A>(allocator));
|
||||||
|
tokens(str, sep, [&ret]
|
||||||
|
(const string_view &token)
|
||||||
|
{
|
||||||
|
ret.emplace(ret.end(), token);
|
||||||
|
});
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
143
ircd/lexical.cc
143
ircd/lexical.cc
|
@ -35,6 +35,11 @@
|
||||||
#include <boost/archive/iterators/transform_width.hpp>
|
#include <boost/archive/iterators/transform_width.hpp>
|
||||||
#include <boost/archive/iterators/ostream_iterator.hpp>
|
#include <boost/archive/iterators/ostream_iterator.hpp>
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// ircd/tokens.h
|
||||||
|
//
|
||||||
|
|
||||||
ircd::string_view
|
ircd::string_view
|
||||||
ircd::tokens_after(const string_view &str,
|
ircd::tokens_after(const string_view &str,
|
||||||
const char &sep,
|
const char &sep,
|
||||||
|
@ -243,73 +248,46 @@ ircd::tokens(const string_view &str,
|
||||||
std::for_each(begin(view), end(view), closure);
|
std::for_each(begin(view), end(view), closure);
|
||||||
}
|
}
|
||||||
|
|
||||||
ircd::string_view
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
ircd::b64encode(const mutable_buffer &out,
|
//
|
||||||
const const_raw_buffer &in)
|
// ircd/lex_cast.h
|
||||||
|
//
|
||||||
|
|
||||||
|
namespace ircd
|
||||||
{
|
{
|
||||||
|
/// The static lex_cast ring buffers are each LEX_CAST_BUFSIZE bytes;
|
||||||
|
/// Consider increasing if some lex_cast<T>(str) has more characters.
|
||||||
|
const size_t LEX_CAST_BUFSIZE {64};
|
||||||
|
|
||||||
using transform = boost::archive::iterators::transform_width<unsigned char *, 6, 8>;
|
/// This is a static "ring buffer" to simplify a majority of lex_cast uses.
|
||||||
using b64fb = boost::archive::iterators::base64_from_binary<transform>;
|
/// If the lex_cast has binary input and string output, and no user buffer
|
||||||
using ostream_iterator = boost::archive::iterators::ostream_iterator<char>;
|
/// is supplied, the next buffer here will be used instead. The returned
|
||||||
|
/// string_view of data from this buffer is only valid for several more
|
||||||
|
/// calls to lex_cast before it is overwritten.
|
||||||
|
thread_local char lex_cast_buf[LEX_CAST_BUFS][LEX_CAST_BUFSIZE];
|
||||||
|
thread_local uint lex_cast_cur;
|
||||||
|
|
||||||
std::stringstream ss;
|
template<size_t N, class T> static string_view _lex_cast(const T &i, char *buf, size_t max);
|
||||||
std::copy(b64fb(data(in)), b64fb(data(in) + size(in)), ostream_iterator(ss));
|
template<class T> static T _lex_cast(const string_view &s);
|
||||||
const auto outlen(ss.str().copy(data(out), size(out)));
|
|
||||||
return { data(out), outlen };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ircd::const_raw_buffer
|
/// Internal template providing conversions from a number to a string;
|
||||||
ircd::a2u(const mutable_raw_buffer &out,
|
/// potentially using the ring buffer if no user buffer is supplied.
|
||||||
const const_buffer &in)
|
|
||||||
{
|
|
||||||
const size_t len{size(in) / 2};
|
|
||||||
for(size_t i(0); i < len; ++i)
|
|
||||||
{
|
|
||||||
const char gl[3]
|
|
||||||
{
|
|
||||||
in[i * 2],
|
|
||||||
in[i * 2 + 1],
|
|
||||||
'\0'
|
|
||||||
};
|
|
||||||
|
|
||||||
out[i] = strtol(gl, nullptr, 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
return { data(out), len };
|
|
||||||
}
|
|
||||||
|
|
||||||
ircd::string_view
|
|
||||||
ircd::u2a(const mutable_buffer &out,
|
|
||||||
const const_raw_buffer &in)
|
|
||||||
{
|
|
||||||
char *p(data(out));
|
|
||||||
for(size_t i(0); i < size(in); ++i)
|
|
||||||
p += snprintf(p, size(out) - (p - data(out)), "%02x", in[i]);
|
|
||||||
|
|
||||||
return { data(out), size_t(p - data(out)) };
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace ircd {
|
|
||||||
|
|
||||||
const size_t LEX_CAST_BUFSIZE {64};
|
|
||||||
thread_local char lex_cast_buf[LEX_CAST_BUFS][LEX_CAST_BUFSIZE];
|
|
||||||
|
|
||||||
template<size_t N,
|
template<size_t N,
|
||||||
class T>
|
class T>
|
||||||
static string_view
|
ircd::string_view
|
||||||
_lex_cast(const T &i,
|
ircd::_lex_cast(const T &i,
|
||||||
char *buf,
|
char *buf,
|
||||||
size_t max)
|
size_t max)
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using array = std::array<char, N>;
|
using array = std::array<char, N>;
|
||||||
|
|
||||||
if(!buf)
|
if(!buf)
|
||||||
{
|
{
|
||||||
static thread_local uint cur;
|
buf = lex_cast_buf[lex_cast_cur++];
|
||||||
buf = lex_cast_buf[cur++];
|
|
||||||
max = LEX_CAST_BUFSIZE;
|
max = LEX_CAST_BUFSIZE;
|
||||||
cur %= LEX_CAST_BUFS;
|
lex_cast_cur %= LEX_CAST_BUFS;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(max >= N);
|
assert(max >= N);
|
||||||
|
@ -322,9 +300,11 @@ catch(const boost::bad_lexical_cast &e)
|
||||||
throw ircd::bad_lex_cast("%s", e.what());
|
throw ircd::bad_lex_cast("%s", e.what());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Internal template providing conversions from a string to a number;
|
||||||
|
/// the native object is returned directly; no ring buffer is consumed.
|
||||||
template<class T>
|
template<class T>
|
||||||
static T
|
T
|
||||||
_lex_cast(const string_view &s)
|
ircd::_lex_cast(const string_view &s)
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return boost::lexical_cast<T>(s);
|
return boost::lexical_cast<T>(s);
|
||||||
|
@ -334,8 +314,6 @@ catch(const boost::bad_lexical_cast &e)
|
||||||
throw ircd::bad_lex_cast("%s", e.what());
|
throw ircd::bad_lex_cast("%s", e.what());
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ircd
|
|
||||||
|
|
||||||
template<> ircd::string_view
|
template<> ircd::string_view
|
||||||
ircd::lex_cast(bool i,
|
ircd::lex_cast(bool i,
|
||||||
char *const &buf,
|
char *const &buf,
|
||||||
|
@ -578,6 +556,57 @@ ircd::try_lex_cast<long double>(const string_view &s)
|
||||||
return boost::conversion::try_lexical_convert(s, i);
|
return boost::conversion::try_lexical_convert(s, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// ircd/stringops.h
|
||||||
|
//
|
||||||
|
|
||||||
|
ircd::string_view
|
||||||
|
ircd::b64encode(const mutable_buffer &out,
|
||||||
|
const const_raw_buffer &in)
|
||||||
|
{
|
||||||
|
|
||||||
|
using transform = boost::archive::iterators::transform_width<unsigned char *, 6, 8>;
|
||||||
|
using b64fb = boost::archive::iterators::base64_from_binary<transform>;
|
||||||
|
using ostream_iterator = boost::archive::iterators::ostream_iterator<char>;
|
||||||
|
|
||||||
|
std::stringstream ss;
|
||||||
|
std::copy(b64fb(data(in)), b64fb(data(in) + size(in)), ostream_iterator(ss));
|
||||||
|
const auto outlen(ss.str().copy(data(out), size(out)));
|
||||||
|
return { data(out), outlen };
|
||||||
|
}
|
||||||
|
|
||||||
|
ircd::const_raw_buffer
|
||||||
|
ircd::a2u(const mutable_raw_buffer &out,
|
||||||
|
const const_buffer &in)
|
||||||
|
{
|
||||||
|
const size_t len{size(in) / 2};
|
||||||
|
for(size_t i(0); i < len; ++i)
|
||||||
|
{
|
||||||
|
const char gl[3]
|
||||||
|
{
|
||||||
|
in[i * 2],
|
||||||
|
in[i * 2 + 1],
|
||||||
|
'\0'
|
||||||
|
};
|
||||||
|
|
||||||
|
out[i] = strtol(gl, nullptr, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { data(out), len };
|
||||||
|
}
|
||||||
|
|
||||||
|
ircd::string_view
|
||||||
|
ircd::u2a(const mutable_buffer &out,
|
||||||
|
const const_raw_buffer &in)
|
||||||
|
{
|
||||||
|
char *p(data(out));
|
||||||
|
for(size_t i(0); i < size(in); ++i)
|
||||||
|
p += snprintf(p, size(out) - (p - data(out)), "%02x", in[i]);
|
||||||
|
|
||||||
|
return { data(out), size_t(p - data(out)) };
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* strip_colour - remove colour codes from a string
|
* strip_colour - remove colour codes from a string
|
||||||
* -asuffield (?)
|
* -asuffield (?)
|
||||||
|
|
Loading…
Reference in a new issue