Skip to content

Commit

Permalink
Add case_insensitive_less (issue #81)
Browse files Browse the repository at this point in the history
  • Loading branch information
Morwenn committed Aug 14, 2016
1 parent c6bc5b1 commit 2ce1db8
Show file tree
Hide file tree
Showing 3 changed files with 200 additions and 0 deletions.
130 changes: 130 additions & 0 deletions include/cpp-sort/comparators/case_insensitive_less.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2016 Morwenn
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef CPPSORT_COMPARATORS_CASE_INSENSITIVE_LESS_H_
#define CPPSORT_COMPARATORS_CASE_INSENSITIVE_LESS_H_

////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <algorithm>
#include <iterator>
#include <locale>
#include <type_traits>
#include <utility>
#include <cpp-sort/utility/static_const.h>

namespace cppsort
{
namespace detail
{
////////////////////////////////////////////////////////////
// Case insensitive comparison for char sequences

template<typename CharT>
struct char_less
{
const std::ctype<CharT>& ct;

char_less(const std::ctype<CharT>& ct):
ct(ct)
{}

auto operator()(CharT lhs, CharT rhs) const
-> bool
{
return ct.tolower(lhs) < ct.tolower(rhs);
}
};

template<typename T>
auto case_insensitive_less(const T& lhs, const T& rhs, const std::locale loc)
-> bool
{
using char_type = std::decay_t<decltype(*std::begin(lhs))>;
const auto& ct = std::use_facet<std::ctype<char_type>>(loc);

return std::lexicographical_compare(std::begin(lhs), std::end(lhs),
std::begin(rhs), std::end(rhs),
char_less<char_type>(ct));
}

template<typename T>
auto case_insensitive_less(const T& lhs, const T& rhs)
-> bool
{
std::locale loc;
return case_insensitive_less(lhs, rhs, loc);
}

////////////////////////////////////////////////////////////
// Customization point

class case_insensitive_less_locale_fn
{
private:

const std::locale& loc;

public:

explicit case_insensitive_less_locale_fn(const std::locale& loc):
loc(loc)
{}

template<typename T, typename U>
constexpr auto operator()(T&& lhs, U&& rhs) const
noexcept(noexcept(case_insensitive_less(std::forward<T>(lhs), std::forward<U>(rhs), loc)))
-> decltype(case_insensitive_less(std::forward<T>(lhs), std::forward<U>(rhs), loc))
{
return case_insensitive_less(std::forward<T>(lhs), std::forward<U>(rhs), loc);
}
};

struct case_insensitive_less_fn
{
template<typename T, typename U>
constexpr auto operator()(T&& lhs, U&& rhs) const
noexcept(noexcept(case_insensitive_less(std::forward<T>(lhs), std::forward<U>(rhs))))
-> decltype(case_insensitive_less(std::forward<T>(lhs), std::forward<U>(rhs)))
{
return case_insensitive_less(std::forward<T>(lhs), std::forward<U>(rhs));
}

inline auto operator()(const std::locale& loc) const
-> case_insensitive_less_locale_fn
{
return case_insensitive_less_locale_fn(loc);
}
};
}

namespace
{
constexpr auto&& case_insensitive_less = utility::static_const<
detail::case_insensitive_less_fn
>::value;
}
}

#endif // CPPSORT_COMPARATORS_CASE_INSENSITIVE_LESS_H_
1 change: 1 addition & 0 deletions testsuite/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ set(
set(
COMPARATORS_TESTS

comparators/case_insensitive_less.cpp
comparators/natural_less.cpp
comparators/total_less.cpp
)
Expand Down
69 changes: 69 additions & 0 deletions testsuite/comparators/case_insensitive_less.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2016 Morwenn
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <array>
#include <string>
#include <catch.hpp>
#include <cpp-sort/comparators/case_insensitive_less.h>
#include <cpp-sort/sort.h>

TEST_CASE( "case-insensitive string comparison with case_insensitive_less" )
{
std::array<std::string, 9> array = {
"awry",
"Banana",
"greaTEr",
"bounTy",
"eXpected",
"aROma",
"excellent",
"GreaT",
"aROused"
};

std::array<std::string, 9> expected = {
"aROma",
"aROused",
"awry",
"Banana",
"bounTy",
"excellent",
"eXpected",
"GreaT",
"greaTEr"
};

SECTION( "implicit global locale" )
{
cppsort::sort(array, cppsort::case_insensitive_less);
CHECK( array == expected );
}

SECTION( "explicit global locale" )
{
std::locale locale;
cppsort::sort(array, cppsort::case_insensitive_less(locale));
CHECK( array == expected );
}
}

0 comments on commit 2ce1db8

Please sign in to comment.