mirror of
https://github.com/matrix-construct/construct
synced 2024-12-11 08:02:59 +01:00
599 lines
11 KiB
C++
599 lines
11 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.
|
|
|
|
#include <boost/tokenizer.hpp>
|
|
|
|
namespace ircd
|
|
{
|
|
struct string_separator;
|
|
struct char_separator;
|
|
};
|
|
|
|
struct [[gnu::visibility("internal")]]
|
|
ircd::string_separator
|
|
{
|
|
const string_view &delim;
|
|
|
|
template<class iterator,
|
|
class token>
|
|
bool operator()(iterator &next, iterator end, token &ret) const noexcept;
|
|
void reset() noexcept;
|
|
|
|
string_separator(const string_view &delim) noexcept;
|
|
};
|
|
|
|
struct [[gnu::visibility("internal")]]
|
|
ircd::char_separator
|
|
{
|
|
const char &delim;
|
|
|
|
template<class iterator,
|
|
class token>
|
|
bool operator()(iterator &next, iterator end, token &ret) const noexcept;
|
|
void reset() noexcept;
|
|
|
|
char_separator(const char &delim) noexcept;
|
|
};
|
|
|
|
//
|
|
// interface
|
|
//
|
|
|
|
ircd::pair<ircd::string_view>
|
|
ircd::tokens_split(const string_view &str,
|
|
const char sep,
|
|
const size_t at,
|
|
const size_t skip)
|
|
noexcept
|
|
{
|
|
const ssize_t before(at);
|
|
const ssize_t after
|
|
{
|
|
(before - 1) + ssize_t(skip)
|
|
};
|
|
|
|
return pair<string_view>
|
|
{
|
|
tokens_before(str, sep, before),
|
|
tokens_after(str, sep, after)
|
|
};
|
|
}
|
|
|
|
ircd::pair<ircd::string_view>
|
|
ircd::tokens_split(const string_view &str,
|
|
const string_view &sep,
|
|
const size_t at,
|
|
const size_t skip)
|
|
noexcept
|
|
{
|
|
const ssize_t before(at);
|
|
const ssize_t after
|
|
{
|
|
(before - 1) + ssize_t(skip)
|
|
};
|
|
|
|
return pair<string_view>
|
|
{
|
|
tokens_before(str, sep, before),
|
|
tokens_after(str, sep, after)
|
|
};
|
|
}
|
|
|
|
ircd::string_view
|
|
ircd::tokens_before(const string_view &str,
|
|
const char sep,
|
|
const size_t i)
|
|
noexcept
|
|
{
|
|
assert(sep != '\0');
|
|
const char _sep[2]
|
|
{
|
|
sep, '\0'
|
|
};
|
|
|
|
return tokens_before(str, _sep, i);
|
|
}
|
|
|
|
ircd::string_view
|
|
ircd::tokens_before(const string_view &str,
|
|
const string_view &sep,
|
|
const size_t i)
|
|
noexcept
|
|
{
|
|
using type = string_view;
|
|
using iter = typename type::const_iterator;
|
|
using delim = string_separator;
|
|
|
|
const delim d{sep};
|
|
const boost::tokenizer<delim, iter, type> view
|
|
{
|
|
str, d
|
|
};
|
|
|
|
string_view ret;
|
|
auto it(begin(view));
|
|
for(size_t j(0); it != end(view) && j < i; ++it, j++)
|
|
ret =
|
|
{
|
|
begin(view)->data(), it->data() + it->size()
|
|
};
|
|
|
|
return ret;
|
|
}
|
|
|
|
ircd::string_view
|
|
ircd::tokens_after(const string_view &str,
|
|
const char sep,
|
|
const ssize_t i)
|
|
noexcept
|
|
{
|
|
assert(sep != '\0');
|
|
const char _sep[2]
|
|
{
|
|
sep, '\0'
|
|
};
|
|
|
|
return tokens_after(str, _sep, i);
|
|
}
|
|
|
|
ircd::string_view
|
|
ircd::tokens_after(const string_view &str,
|
|
const string_view &sep,
|
|
const ssize_t i)
|
|
noexcept
|
|
{
|
|
using type = string_view;
|
|
using iter = typename type::const_iterator;
|
|
using delim = string_separator;
|
|
|
|
const delim d{sep};
|
|
const boost::tokenizer<delim, iter, type> view
|
|
{
|
|
str, d
|
|
};
|
|
|
|
auto it(begin(view));
|
|
for(ssize_t j(0); it != end(view); ++it, j++)
|
|
if(j > i)
|
|
return string_view
|
|
{
|
|
it->data(), str.data() + str.size()
|
|
};
|
|
|
|
return {};
|
|
}
|
|
|
|
ircd::string_view
|
|
ircd::token_first(const string_view &str,
|
|
const char sep)
|
|
{
|
|
assert(sep != '\0');
|
|
const char _sep[2]
|
|
{
|
|
sep, '\0'
|
|
};
|
|
|
|
return token(str, _sep, 0);
|
|
}
|
|
|
|
ircd::string_view
|
|
ircd::token_first(const string_view &str,
|
|
const string_view &sep)
|
|
{
|
|
return token(str, sep, 0);
|
|
}
|
|
|
|
ircd::string_view
|
|
ircd::token_last(const string_view &str,
|
|
const char sep)
|
|
{
|
|
assert(sep != '\0');
|
|
const char _sep[2]
|
|
{
|
|
sep, '\0'
|
|
};
|
|
|
|
return token_last(str, _sep);
|
|
}
|
|
|
|
ircd::string_view
|
|
ircd::token_last(const string_view &str,
|
|
const string_view &sep)
|
|
{
|
|
using type = string_view;
|
|
using iter = typename type::const_iterator;
|
|
using delim = string_separator;
|
|
|
|
const delim d{sep};
|
|
const boost::tokenizer<delim, iter, type> view
|
|
{
|
|
str, d
|
|
};
|
|
|
|
auto it(begin(view));
|
|
if(it == end(view))
|
|
return str.empty()? str : throw std::out_of_range("token out of range");
|
|
|
|
string_view ret(*it);
|
|
for(++it; it != end(view); ++it)
|
|
ret = *it;
|
|
|
|
return ret;
|
|
}
|
|
|
|
ircd::string_view
|
|
ircd::token(const string_view &str,
|
|
const char sep,
|
|
const size_t i,
|
|
const string_view &def)
|
|
noexcept try
|
|
{
|
|
return token(str, sep, i);
|
|
}
|
|
catch(const std::out_of_range &)
|
|
{
|
|
return def;
|
|
}
|
|
|
|
ircd::string_view
|
|
ircd::token(const string_view &str,
|
|
const string_view &sep,
|
|
const size_t i,
|
|
const string_view &def)
|
|
noexcept try
|
|
{
|
|
return token(str, sep, i);
|
|
}
|
|
catch(const std::out_of_range &)
|
|
{
|
|
return def;
|
|
}
|
|
|
|
ircd::string_view
|
|
ircd::token(const string_view &str,
|
|
const char sep,
|
|
const size_t i)
|
|
{
|
|
using type = string_view;
|
|
using iter = typename type::const_iterator;
|
|
using delim = char_separator;
|
|
|
|
const delim d{sep};
|
|
const boost::tokenizer<delim, iter, type> view
|
|
{
|
|
str, d
|
|
};
|
|
|
|
return *at(begin(view), end(view), i);
|
|
}
|
|
|
|
ircd::string_view
|
|
ircd::token(const string_view &str,
|
|
const string_view &sep,
|
|
const size_t i)
|
|
{
|
|
using type = string_view;
|
|
using iter = typename type::const_iterator;
|
|
using delim = string_separator;
|
|
|
|
const delim d{sep};
|
|
const boost::tokenizer<delim, iter, type> view
|
|
{
|
|
str, d
|
|
};
|
|
|
|
return *at(begin(view), end(view), i);
|
|
}
|
|
|
|
bool
|
|
ircd::token_exists(const string_view &str,
|
|
const char sep,
|
|
const string_view &tok)
|
|
noexcept
|
|
{
|
|
using type = string_view;
|
|
using iter = typename type::const_iterator;
|
|
using delim = char_separator;
|
|
|
|
const delim d{sep};
|
|
const boost::tokenizer<delim, iter, type> view
|
|
{
|
|
str, d
|
|
};
|
|
|
|
return std::find(begin(view), end(view), tok) != end(view);
|
|
}
|
|
|
|
bool
|
|
ircd::token_exists(const string_view &str,
|
|
const string_view &sep,
|
|
const string_view &tok)
|
|
noexcept
|
|
{
|
|
using type = string_view;
|
|
using iter = typename type::const_iterator;
|
|
using delim = string_separator;
|
|
|
|
const delim d{sep};
|
|
const boost::tokenizer<delim, iter, type> view
|
|
{
|
|
str, d
|
|
};
|
|
|
|
return std::find(begin(view), end(view), tok) != end(view);
|
|
}
|
|
|
|
size_t
|
|
ircd::token_count(const string_view &str,
|
|
const char sep)
|
|
noexcept
|
|
{
|
|
using type = string_view;
|
|
using iter = typename type::const_iterator;
|
|
using delim = char_separator;
|
|
|
|
const delim d{sep};
|
|
const boost::tokenizer<delim, iter, type> view
|
|
{
|
|
str, d
|
|
};
|
|
|
|
return std::distance(begin(view), end(view));
|
|
}
|
|
|
|
size_t
|
|
ircd::token_count(const string_view &str,
|
|
const string_view &sep)
|
|
noexcept
|
|
{
|
|
using type = string_view;
|
|
using iter = typename type::const_iterator;
|
|
using delim = string_separator;
|
|
|
|
const delim d{sep};
|
|
const boost::tokenizer<delim, iter, type> view
|
|
{
|
|
str, d
|
|
};
|
|
|
|
return std::distance(begin(view), end(view));
|
|
}
|
|
|
|
size_t
|
|
ircd::tokens(const string_view &str,
|
|
const char sep_,
|
|
const mutable_buffer &buf,
|
|
const token_view &closure)
|
|
{
|
|
assert(sep_ != '\0');
|
|
const char _sep[2]
|
|
{
|
|
sep_, '\0'
|
|
};
|
|
|
|
const string_view sep
|
|
{
|
|
_sep
|
|
};
|
|
|
|
return tokens(str, sep, buf, closure);
|
|
}
|
|
|
|
size_t
|
|
ircd::tokens(const string_view &str,
|
|
const string_view &sep,
|
|
const mutable_buffer &buf,
|
|
const token_view &closure)
|
|
{
|
|
char *ptr(data(buf));
|
|
char *const stop(data(buf) + size(buf));
|
|
tokens(str, sep, [&closure, &ptr, &stop]
|
|
(const string_view &token) -> bool
|
|
{
|
|
const size_t terminated_size(token.size() + 1);
|
|
const size_t remaining(std::distance(ptr, stop));
|
|
if(remaining < terminated_size)
|
|
return false;
|
|
|
|
char *const dest(ptr);
|
|
ptr += strlcpy(dest, token.data(), terminated_size);
|
|
return closure(string_view(dest, token.size()));
|
|
});
|
|
|
|
return std::distance(data(buf), ptr);
|
|
}
|
|
|
|
size_t
|
|
ircd::tokens(const string_view &str,
|
|
const char sep,
|
|
const size_t limit,
|
|
const token_view &closure)
|
|
{
|
|
using type = string_view;
|
|
using iter = typename type::const_iterator;
|
|
using delim = char_separator;
|
|
|
|
const delim d{sep};
|
|
const boost::tokenizer<delim, iter, type> view
|
|
{
|
|
str, d
|
|
};
|
|
|
|
size_t i(0);
|
|
for(auto it(begin(view)); i < limit && it != end(view); ++it, i++)
|
|
if(!closure(*it))
|
|
break;
|
|
|
|
return i;
|
|
}
|
|
|
|
size_t
|
|
ircd::tokens(const string_view &str,
|
|
const string_view &sep,
|
|
const size_t limit,
|
|
const token_view &closure)
|
|
{
|
|
using type = string_view;
|
|
using iter = typename type::const_iterator;
|
|
using delim = string_separator;
|
|
|
|
const delim d{sep};
|
|
const boost::tokenizer<delim, iter, type> view
|
|
{
|
|
str, d
|
|
};
|
|
|
|
size_t i(0);
|
|
for(auto it(begin(view)); i < limit && it != end(view); ++it, i++)
|
|
if(!closure(*it))
|
|
break;
|
|
|
|
return i;
|
|
}
|
|
|
|
bool
|
|
ircd::tokens(const string_view &str,
|
|
const char sep,
|
|
const token_view &closure)
|
|
{
|
|
using type = string_view;
|
|
using iter = typename type::const_iterator;
|
|
using delim = char_separator;
|
|
|
|
const delim d{sep};
|
|
const boost::tokenizer<delim, iter, type> view
|
|
{
|
|
str, d
|
|
};
|
|
|
|
for(auto it(begin(view)); it != end(view); ++it)
|
|
if(!closure(*it))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
ircd::tokens(const string_view &str,
|
|
const string_view &sep,
|
|
const token_view &closure)
|
|
{
|
|
using type = string_view;
|
|
using iter = typename type::const_iterator;
|
|
using delim = string_separator;
|
|
|
|
const delim d{sep};
|
|
const boost::tokenizer<delim, iter, type> view
|
|
{
|
|
str, d
|
|
};
|
|
|
|
for(auto it(begin(view)); it != end(view); ++it)
|
|
if(!closure(*it))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
//
|
|
// string_separator
|
|
//
|
|
|
|
ircd::string_separator::string_separator(const string_view &delim)
|
|
noexcept
|
|
:delim
|
|
{
|
|
delim
|
|
}
|
|
{
|
|
}
|
|
|
|
void
|
|
ircd::string_separator::reset()
|
|
noexcept
|
|
{
|
|
//TODO: ???
|
|
}
|
|
|
|
template<class iterator,
|
|
class token>
|
|
bool
|
|
ircd::string_separator::operator()(iterator &start,
|
|
iterator stop,
|
|
token &ret)
|
|
const noexcept
|
|
{
|
|
do
|
|
{
|
|
if(start == stop)
|
|
return false;
|
|
|
|
const string_view input
|
|
{
|
|
start, stop
|
|
};
|
|
|
|
string_view remain;
|
|
std::tie(ret, remain) = ircd::split(input, delim);
|
|
start = remain?
|
|
begin(remain):
|
|
stop;
|
|
}
|
|
while(!ret);
|
|
return true;
|
|
}
|
|
|
|
//
|
|
// char_separator
|
|
//
|
|
|
|
ircd::char_separator::char_separator(const char &delim)
|
|
noexcept
|
|
:delim
|
|
{
|
|
delim
|
|
}
|
|
{
|
|
}
|
|
|
|
void
|
|
ircd::char_separator::reset()
|
|
noexcept
|
|
{
|
|
//TODO: ???
|
|
}
|
|
|
|
template<class iterator,
|
|
class token>
|
|
bool
|
|
ircd::char_separator::operator()(iterator &start,
|
|
iterator stop,
|
|
token &ret)
|
|
const noexcept
|
|
{
|
|
do
|
|
{
|
|
if(start == stop)
|
|
return false;
|
|
|
|
const string_view input
|
|
{
|
|
start, stop
|
|
};
|
|
|
|
string_view remain;
|
|
std::tie(ret, remain) = ircd::split(input, delim);
|
|
start = remain?
|
|
begin(remain):
|
|
stop;
|
|
}
|
|
while(!ret);
|
|
return true;
|
|
}
|