summaryrefslogtreecommitdiff
path: root/src/strings/base.hpp
blob: b1aff3451fed90757b5d5143ccf3a1d5449900b4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
#ifndef TMWA_STRINGS_BASE_HPP
#define TMWA_STRINGS_BASE_HPP
//    strings/base.hpp - CRTP base for string implementations.
//
//    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 "fwd.hpp"
# include "pair.hpp"

# include <cstddef>

# include <iterator>

// It is a common mistake to assume that one string class for everything.
// Because C++ and TMWA have a C legacy, there are a few more here
// than would probably be necessary in an ideal language.
namespace strings
{
    // TODO reimplement some things in terms of Slice and Slice::iterator?

    // simple pointer-wrapping iterator that can be used to get distinct
    // types for different containers.
    template<class Tag>
    class _iterator
    {
        typedef _iterator X;

        const char *_ptr;
    public:
        typedef ptrdiff_t difference_type;
        typedef char value_type;
        typedef const char *pointer;
        typedef const char& reference;
        typedef std::random_access_iterator_tag iterator_category;

        _iterator(const char *p=nullptr) : _ptr(p) {}

        // iterator
        reference operator *() const { return *_ptr; }
        X& operator ++() { ++_ptr; return *this; }
        // equality comparable
        friend bool operator == (X l, X r) { return l._ptr == r._ptr; }
        // input iterator
        friend bool operator != (X l, X r) { return !(l == r); }
        pointer operator->() const { return _ptr; }
        X operator++ (int) { X out = *this; ++*this; return out; }
        // forward iterator is mostly semantical, and the ctor is above
        // bidirectional iterator
        X& operator --() { --_ptr; return *this; }
        X operator-- (int) { X out = *this; --*this; return out; }
        // random access iterator
        X& operator += (difference_type n) { _ptr += n; return *this; }
        friend X operator + (X a, difference_type n) { return a += n; }
        friend X operator + (difference_type n, X a) { return a += n; }
        X& operator -= (difference_type n) { _ptr -= n; return *this; }
        friend X operator - (X a, difference_type n) { return a -= n; }
        friend difference_type operator - (X b, X a) { return b._ptr - a._ptr; }
        reference operator[](difference_type n) const { return _ptr[n]; }
        friend bool operator < (X a, X b) { return a._ptr < b._ptr; }
        friend bool operator > (X a, X b) { return b < a; }
        friend bool operator >= (X a, X b) { return !(a < b); }
        friend bool operator <= (X a, X b) { return !(a > b); }
    };

    /// A helper class that implements all the interesting stuff that can
    /// be done on any constant string, in terms of .begin() and .end().
    template<class T, class O, class P>
    class _crtp_string
    {
        typedef typename P::TailSlice Z;
        typedef typename P::FullSlice X;
    public:
        // this will have to be changed if MString decides to join in.
        typedef _iterator<T> iterator;
        typedef std::reverse_iterator<iterator> reverse_iterator;
    private:
        const T& _ref() const;
        iterator begin() const;
        iterator end() const;
        const RString *base() const;
    public:
        size_t size() const;
        reverse_iterator rbegin() const;
        reverse_iterator rend() const;
        explicit
        operator bool() const;
        bool operator !() const;
        operator P() const;

        // the existence of this has led to bugs
        // it's not really sane from a unicode perspective anyway ...
        // prefer startswith or extract
        __attribute__((deprecated))
        char operator[](size_t i) const;
        char front() const;
        char back() const;
        const char *data();

        Z xslice_t(size_t o) const;
        X xslice_h(size_t o) const;
        Z xrslice_t(size_t no) const;
        X xrslice_h(size_t no) const;
        Z xislice_t(iterator it) const;
        X xislice_h(iterator it) const;
        X xlslice(size_t o, size_t l) const;
        X xpslice(size_t b, size_t e) const;
        X xislice(iterator b, iterator e) const;
        Z lstrip() const;
        X rstrip() const;
        X strip() const;

        bool startswith(XPair x) const;
        bool endswith(XPair x) const;
        bool startswith(char c) const;
        bool endswith(char c) const;

        bool contains(char c) const;
        bool contains_seq(XPair s) const;
        bool contains_any(XPair s) const;

        bool has_print() const;
        bool is_print() const;
        __attribute__((deprecated))
        O to_print() const;

        bool is_graph() const;
        bool has_graph() const;

        bool has_lower() const;
        bool is_lower() const;
        O to_lower() const;

        bool has_upper() const;
        bool is_upper() const;
        O to_upper() const;

        bool has_alpha() const; // equivalent to has_lower || has_upper
        bool is_alpha() const; // NOT equivalent to is_lower || is_upper

        bool has_digit2() const;
        bool is_digit2() const;
        bool has_digit8() const;
        bool is_digit8() const;
        bool has_digit10() const;
        bool is_digit10() const;
        bool has_digit16() const;
        bool is_digit16() const;

        bool has_alnum() const; // equivalent to has_alpha || has_digit10
        bool is_alnum() const; // NOT equivalent to is_alpha || is_digit10
    };

    template<class L, class R>
    class string_comparison_allowed
    {
        constexpr static bool l_is_vstring_exact = std::is_same<VString<sizeof(L) - 1>, L>::value;
        constexpr static bool l_is_vstring_approx = std::is_base_of<VString<sizeof(L) - 1>, L>::value;
        constexpr static bool r_is_vstring_exact = std::is_same<VString<sizeof(R) - 1>, R>::value;
        constexpr static bool r_is_vstring_approx = std::is_base_of<VString<sizeof(R) - 1>, R>::value;

        constexpr static bool l_is_restricted = l_is_vstring_approx && !l_is_vstring_exact;
        constexpr static bool r_is_restricted = r_is_vstring_approx && !r_is_vstring_exact;
    public:
        constexpr static bool value = std::is_same<L, R>::value || (!l_is_restricted && !r_is_restricted);
    };

    // not really intended for public use
    int pair_compare(XPair l, XPair r);

    template<class L, class R, typename=typename std::enable_if<string_comparison_allowed<L, R>::value>::type>
    auto operator == (const L& l, const R& r) -> decltype((pair_compare(l, r), true));
    template<class L, class R, typename=typename std::enable_if<string_comparison_allowed<L, R>::value>::type>
    auto operator != (const L& l, const R& r) -> decltype((pair_compare(l, r), true));
    template<class L, class R, typename=typename std::enable_if<string_comparison_allowed<L, R>::value>::type>
    auto operator < (const L& l, const R& r) -> decltype((pair_compare(l, r), true));
    template<class L, class R, typename=typename std::enable_if<string_comparison_allowed<L, R>::value>::type>
    auto operator <= (const L& l, const R& r) -> decltype((pair_compare(l, r), true));
    template<class L, class R, typename=typename std::enable_if<string_comparison_allowed<L, R>::value>::type>
    auto operator > (const L& l, const R& r) -> decltype((pair_compare(l, r), true));
    template<class L, class R, typename=typename std::enable_if<string_comparison_allowed<L, R>::value>::type>
    auto operator >= (const L& l, const R& r) -> decltype((pair_compare(l, r), true));
} // namespace strings

# include "base.tcc"

#endif // TMWA_STRINGS_BASE_HPP