2023-11-04 21:30:42 +02:00

180 lines
3.7 KiB
C++

//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
// Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/url
//
#ifndef BOOST_URL_GRAMMAR_DETAIL_CI_STRING_HPP
#define BOOST_URL_GRAMMAR_DETAIL_CI_STRING_HPP
#include <boost/core/detail/string_view.hpp>
#include <boost/assert.hpp>
#include <cstdint>
#include <iterator>
#include <type_traits>
namespace boost {
namespace urls {
namespace grammar {
namespace detail {
template<class T, class = void>
struct is_char_iter : std::false_type {};
template<class T>
struct is_char_iter<T, void_t<
decltype(std::declval<char&>() =
*std::declval<T const&>()),
decltype(std::declval<T&>() =
++std::declval<T&>()),
decltype(std::declval<bool&>() =
std::declval<T const&>() ==
std::declval<T const&>())
> > : std::integral_constant<bool,
std::is_copy_constructible<T>::value>
{
};
template<class T, class = void>
struct is_char_range : std::false_type {};
template<class T>
struct is_char_range<T, void_t<
decltype(std::declval<T const&>().begin()),
decltype(std::declval<T const&>().end())
> > : std::integral_constant<bool,
is_char_iter<decltype(
std::declval<T const&>(
).begin())>::value &&
is_char_iter<decltype(
std::declval<T const&>(
).end())>::value>
{
};
template<class T>
struct type_id_impl
{
static
constexpr
char cid = 0;
};
template<class T>
constexpr
char
type_id_impl<T>::cid;
template<class T>
constexpr
std::uintptr_t
type_id() noexcept
{
return std::uintptr_t(
&type_id_impl<T>::cid);
}
//------------------------------------------------
constexpr
char
to_lower(char c) noexcept
{
return
(c >= 'A' &&
c <= 'Z')
? c + 'a' - 'A'
: c;
}
constexpr
char
to_upper(char c) noexcept
{
return
(c >= 'a' &&
c <= 'z')
? c - ('a' - 'A')
: c;
}
//------------------------------------------------
template<class S0, class S1>
auto
ci_is_equal(
S0 const& s0,
S1 const& s1) ->
typename std::enable_if<
! std::is_convertible<
S0, core::string_view>::value ||
! std::is_convertible<
S1, core::string_view>::value,
bool>::type
{
/* If you get a compile error here, it
means that a range you passed does
not meet the requirements stated
in the documentation.
*/
static_assert(
is_char_range<S0>::value,
"Type requirements not met");
static_assert(
is_char_range<S1>::value,
"Type requirements not met");
// Arguments are sorted by type to
// reduce the number of function
// template instantiations. This
// works because:
//
// ci_is_equal(s0,s1) == ci_is_equal(s1,s0)
//
BOOST_ASSERT(
detail::type_id<S0>() <=
detail::type_id<S1>());
auto it0 = s0.begin();
auto it1 = s1.begin();
auto const end0 = s0.end();
auto const end1 = s1.end();
for(;;)
{
if(it0 == end0)
return it1 == end1;
if(it1 == end1)
return false;
if( to_lower(*it0) !=
to_lower(*it1))
return false;
++it0;
++it1;
}
}
//------------------------------------------------
BOOST_URL_DECL
bool
ci_is_equal(
core::string_view s0,
core::string_view s1) noexcept;
BOOST_URL_DECL
bool
ci_is_less(
core::string_view s0,
core::string_view s1) noexcept;
} // detail
} // grammar
} // urls
} // boost
#endif