summaryrefslogblamecommitdiff
path: root/src/strings/base.tcc
blob: 47d1d1e8ef750d80cdf8cf80f64570285d95cadb (plain) (tree)


















                                                                           

                  



                    


              


















































































                                                                                              
                                                      


































                                                                                          























































































































                                                                                      
                                                                                                         

















































































































































































                                                                                                                
                   
//    strings/base.tcc - Inline functions for strings/base.hpp
//
//    Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com>
//
//    This file is part of The Mana World (Athena server)
//
//    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 3 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, see <http://www.gnu.org/licenses/>.

#include <cstddef>

#include <algorithm>

#include "pair.hpp"


namespace tmwa
{
namespace strings
{
    namespace detail
    {
        constexpr
        bool is_print(char c)
        {
            return ' ' <= c && c <= '~';
        }
        constexpr
        bool is_graph(char c)
        {
            return is_print(c) && c != ' ';
        }
        constexpr
        bool is_lower(char c)
        {
            return 'a' <= c && c <= 'z';
        }
        constexpr
        bool is_upper(char c)
        {
            return 'A' <= c && c <= 'Z';
        }
        constexpr
        bool is_alpha(char c)
        {
            return is_lower(c) || is_upper(c);
        }
        constexpr
        bool is_digit2(char c)
        {
            return '0' <= c && c <= '1';
        }
        constexpr
        bool is_digit8(char c)
        {
            return '0' <= c && c <= '7';
        }
        constexpr
        bool is_digit10(char c)
        {
            return '0' <= c && c <= '9';
        }
        constexpr
        bool is_digit16(char c)
        {
            return ('0' <= c && c <= '9') || ('A' <= c && c <= 'F') || ('a' <= c && c <= 'f');
        }
        constexpr
        bool is_alnum(char c)
        {
            return is_alpha(c) || is_digit10(c);
        }

        constexpr
        char to_lower(char c)
        {
            return is_upper(c) ? c | ' ' : c;
        }
        constexpr
        char to_upper(char c)
        {
            return is_lower(c) ? c & ~' ' : c;
        }
    } // namespace detail

    template<class T, class O, class P>
    const T& _crtp_string<T, O, P>::_ref() const
    {
        return static_cast<const T&>(*this);
    }
    template<class T, class O, class P>
    typename _crtp_string<T, O, P>::iterator _crtp_string<T, O, P>::begin() const
    {
        return _ref().begin();
    }
    template<class T, class O, class P>
    typename _crtp_string<T, O, P>::iterator _crtp_string<T, O, P>::end() const
    {
        return _ref().end();
    }
    template<class T, class O, class P>
    const RString *_crtp_string<T, O, P>::base() const
    {
        return _ref().base();
    }
    template<class T, class O, class P>
    size_t _crtp_string<T, O, P>::size() const
    {
        return end() - begin();
    }
    template<class T, class O, class P>
    typename _crtp_string<T, O, P>::reverse_iterator _crtp_string<T, O, P>::rbegin() const
    {
        return reverse_iterator(end());
    }
    template<class T, class O, class P>
    typename _crtp_string<T, O, P>::reverse_iterator _crtp_string<T, O, P>::rend() const
    {
        return reverse_iterator(begin());
    }
    template<class T, class O, class P>
    _crtp_string<T, O, P>::operator bool() const
    {
        return size();
    }
    template<class T, class O, class P>
    bool _crtp_string<T, O, P>::operator !() const
    {
        return !size();
    }
    template<class T, class O, class P>
    _crtp_string<T, O, P>::operator P() const
    {
        return {&*begin(), &*end()};
    }

    template<class T, class O, class P>
    char _crtp_string<T, O, P>::operator[](size_t i) const
    {
        return begin()[i];
    }
    template<class T, class O, class P>
    char _crtp_string<T, O, P>::front() const
    {
        return *begin();
    }
    template<class T, class O, class P>
    char _crtp_string<T, O, P>::back() const
    {
        return end()[-1];
    }
    template<class T, class O, class P>
    const char *_crtp_string<T, O, P>::data()
    {
        return &*begin();
    }

    template<class T, class O, class P>
    typename P::TailSlice _crtp_string<T, O, P>::xslice_t(size_t o) const
    {
        return typename P::TailSlice(&begin()[o], &*end(), base());
    }
    template<class T, class O, class P>
    typename P::FullSlice _crtp_string<T, O, P>::xslice_h(size_t o) const
    {
        return typename P::FullSlice(&*begin(), &begin()[o], base());
    }
    template<class T, class O, class P>
    typename P::TailSlice _crtp_string<T, O, P>::xrslice_t(size_t no) const
    {
        return typename P::TailSlice(&end()[-no], &*end(), base());
    }
    template<class T, class O, class P>
    typename P::FullSlice _crtp_string<T, O, P>::xrslice_h(size_t no) const
    {
        return typename P::FullSlice(&*begin(), &end()[-no], base());
    }
    template<class T, class O, class P>
    typename P::TailSlice _crtp_string<T, O, P>::xislice_t(iterator it) const
    {
        return typename P::TailSlice(&*it, &*end(), base());
    }
    template<class T, class O, class P>
    typename P::FullSlice _crtp_string<T, O, P>::xislice_h(iterator it) const
    {
        return typename P::FullSlice(&*begin(), &*it, base());
    }
    template<class T, class O, class P>
    typename P::FullSlice _crtp_string<T, O, P>::xlslice(size_t o, size_t l) const
    {
        return typename P::FullSlice(&begin()[o], &begin()[o + l], base());
    }
    template<class T, class O, class P>
    typename P::FullSlice _crtp_string<T, O, P>::xpslice(size_t b, size_t e) const
    {
        return typename P::FullSlice(&begin()[b], &begin()[e], base());
    }
    template<class T, class O, class P>
    typename P::FullSlice _crtp_string<T, O, P>::xislice(iterator b, iterator e) const
    {
        return typename P::FullSlice(&*b, &*e, base());
    }
    template<class T, class O, class P>
    typename P::TailSlice _crtp_string<T, O, P>::lstrip() const
    {
        typename P::TailSlice z = _ref();
        while (z.startswith(' '))
            z = z.xslice_t(1);
        return z;
    }
    template<class T, class O, class P>
    typename P::FullSlice _crtp_string<T, O, P>::rstrip() const
    {
        typename P::FullSlice x = _ref();
        while (x.endswith(' '))
            x = x.xrslice_h(1);
        return x;
    }
    template<class T, class O, class P>
    typename P::FullSlice _crtp_string<T, O, P>::strip() const
    {
        return lstrip().rstrip();
    }

    template<class T, class O, class P>
    bool _crtp_string<T, O, P>::startswith(XPair x) const
    {
        return size() >= x.size() && pair_compare(xslice_h(x.size()), x) == 0;
    }
    template<class T, class O, class P>
    bool _crtp_string<T, O, P>::endswith(XPair x) const
    {
        return size() > x.size() && pair_compare(xrslice_t(x.size()), x) == 0;
    }
    template<class T, class O, class P>
    bool _crtp_string<T, O, P>::startswith(char c) const
    {
        return size() && front() == c;
    }
    template<class T, class O, class P>
    bool _crtp_string<T, O, P>::endswith(char c) const
    {
        return size() && back() == c;
    }
    template<class T, class O, class P>
    bool _crtp_string<T, O, P>::contains(char c) const
    {
        return std::find(begin(), end(), c) != end();
    }
    template<class T, class O, class P>
    bool _crtp_string<T, O, P>::contains_seq(XPair s) const
    {
        return std::search(begin(), end(), s.begin(), s.end()) != end();
    }
    template<class T, class O, class P>
    bool _crtp_string<T, O, P>::contains_any(XPair s) const
    {
        return std::find_if(s.begin(), s.end(), [this](char c) { return this->contains(c); }) != s.end();
    }

    template<class T, class O, class P>
    bool _crtp_string<T, O, P>::has_print() const
    {
        return std::find_if(begin(), end(), detail::is_print) != end(); }
    template<class T, class O, class P>
    bool _crtp_string<T, O, P>::is_print() const
    {
        return std::find_if_not(begin(), end(), detail::is_print) == end(); }
    template<class T, class O, class P>
    O _crtp_string<T, O, P>::to_print() const
    {
        if (is_print()) return _ref();
        char buf[size()];
        char *const b = buf;
        char *const e = std::transform(begin(), end(), b, [](char c) { return detail::is_print(c) ? c : '_'; });
        return XPair(b, e);
    }

    template<class T, class O, class P>
    bool _crtp_string<T, O, P>::has_graph() const
    {
        return std::find_if(begin(), end(), detail::is_graph) != end();
    }
    template<class T, class O, class P>
    bool _crtp_string<T, O, P>::is_graph() const
    {
        return std::find_if_not(begin(), end(), detail::is_graph) == end();
    }

    template<class T, class O, class P>
    bool _crtp_string<T, O, P>::has_lower() const
    {
        return std::find_if(begin(), end(), detail::is_lower) != end();
    }
    template<class T, class O, class P>
    bool _crtp_string<T, O, P>::is_lower() const
    {
        return std::find_if_not(begin(), end(), detail::is_lower) == end();
    }
    template<class T, class O, class P>
    O _crtp_string<T, O, P>::to_lower() const
    {
        if (!has_upper()) return _ref();
        char buf[size()];
        char *const b = buf;
        char *const e = std::transform(begin(), end(), b, detail::to_lower);
        return XPair(b, e);
    }

    template<class T, class O, class P>
    bool _crtp_string<T, O, P>::has_upper() const
    {
        return std::find_if(begin(), end(), detail::is_upper) != end();
    }
    template<class T, class O, class P>
    bool _crtp_string<T, O, P>::is_upper() const
    {
        return std::find_if_not(begin(), end(), detail::is_upper) == end();
    }
    template<class T, class O, class P>
    O _crtp_string<T, O, P>::to_upper() const
    {
        if (!has_lower()) return _ref();
        char buf[size()];
        char *const b = buf;
        char *const e = std::transform(begin(), end(), b, detail::to_upper);
        return XPair(b, e);
    }

    template<class T, class O, class P>
    bool _crtp_string<T, O, P>::has_alpha() const
    {
        return std::find_if(begin(), end(), detail::is_alpha) != end();
    }
    template<class T, class O, class P>
    bool _crtp_string<T, O, P>::is_alpha() const
    {
        return std::find_if_not(begin(), end(), detail::is_alpha) == end();
    }

    template<class T, class O, class P>
    bool _crtp_string<T, O, P>::has_digit2() const
    {
        return std::find_if(begin(), end(), detail::is_digit2) != end();
    }
    template<class T, class O, class P>
    bool _crtp_string<T, O, P>::is_digit2() const
    {
        return std::find_if_not(begin(), end(), detail::is_digit2) == end();
    }
    template<class T, class O, class P>
    bool _crtp_string<T, O, P>::has_digit8() const
    {
        return std::find_if(begin(), end(), detail::is_digit8) != end();
    }
    template<class T, class O, class P>
    bool _crtp_string<T, O, P>::is_digit8() const
    {
        return std::find_if_not(begin(), end(), detail::is_digit8) == end();
    }
    template<class T, class O, class P>
    bool _crtp_string<T, O, P>::has_digit10() const
    {
        return std::find_if(begin(), end(), detail::is_digit10) != end();
    }
    template<class T, class O, class P>
    bool _crtp_string<T, O, P>::is_digit10() const
    {
        return std::find_if_not(begin(), end(), detail::is_digit10) == end();
    }
    template<class T, class O, class P>
    bool _crtp_string<T, O, P>::has_digit16() const
    {
        return std::find_if(begin(), end(), detail::is_digit16) != end();
    }
    template<class T, class O, class P>
    bool _crtp_string<T, O, P>::is_digit16() const
    {
        return std::find_if_not(begin(), end(), detail::is_digit16) == end();
    }

    template<class T, class O, class P>
    bool _crtp_string<T, O, P>::has_alnum() const
    {
        return std::find_if(begin(), end(), detail::is_alnum) != end();
    }
    template<class T, class O, class P>
    bool _crtp_string<T, O, P>::is_alnum() const
    {
        return std::find_if_not(begin(), end(), detail::is_alnum) == end();
    }

    // not really intended for public use
    inline
    int pair_compare(XPair l, XPair r)
    {
        bool less = std::lexicographical_compare(
                l.begin(), l.end(),
                r.begin(), r.end());
        bool greater = std::lexicographical_compare(
                r.begin(), r.end(),
                l.begin(), l.end());
        return greater - less;
    }

    template<class L, class R, typename>
    auto operator == (const L& l, const R& r) -> decltype((pair_compare(l, r), true))
    {
        return pair_compare(l, r) == 0;
    }
    template<class L, class R, typename>
    auto operator != (const L& l, const R& r) -> decltype((pair_compare(l, r), true))
    {
        return pair_compare(l, r) != 0;
    }
    template<class L, class R, typename>
    auto operator < (const L& l, const R& r) -> decltype((pair_compare(l, r), true))
    {
        return pair_compare(l, r) < 0;
    }
    template<class L, class R, typename>
    auto operator <= (const L& l, const R& r) -> decltype((pair_compare(l, r), true))
    {
        return pair_compare(l, r) <= 0;
    }
    template<class L, class R, typename>
    auto operator > (const L& l, const R& r) -> decltype((pair_compare(l, r), true))
    {
        return pair_compare(l, r) > 0;
    }
    template<class L, class R, typename>
    auto operator >= (const L& l, const R& r) -> decltype((pair_compare(l, r), true))
    {
        return pair_compare(l, r) >= 0;
    }
} // namespace strings
} // namespace tmwa