summaryrefslogtreecommitdiff
path: root/src/mongo/base/string_data.h
blob: 2bef8d032580220c094f18d61a014c2a91729065 (plain)
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
/*    Copyright 2010 10gen Inc.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

#pragma once

#include <algorithm>  // for min
#include <cstring>
#include <string>

namespace mongo {

    using std::string;

    /**
     * A StringData object wraps a 'const string&' or a 'const char*' without copying its
     * contents. The most common usage is as a function argument that takes any of the two
     * forms of strings above. Fundamentally, this class tries go around the fact that string
     * literals in C++ are char[N]'s.
     *
     * Notes:
     *
     *  + The object StringData wraps around must be alive while the StringData is.
     *
     *  + Because strings accept null characters, we allow them in StringData. But this use is
     *    *strongly* discouraged. One problem this case may encounter is when asking for data()
     *    out of a StringData that was feed with, say "a\0b". If interpreted as a c-string,
     *    the null character would cut the original string short.
     */
    class StringData {
    public:

        /**
         * Constructs a StringData, for the case where the length of string is not known. 'c'
         * must be a pointer to a null-terminated string.
         */
        StringData( const char* c )
            : _data(c), _size(string::npos){}

        /**
         * Constructs a StringData explicitly, for the case where the length of the string is
         * already known. 'c' must be a pointer to a null-terminated string, and strlenOfc must
         * be the length that strlen(c) would return, a.k.a the index of the terminator in c.
         */
        StringData( const char* c, size_t len )
            : _data(c), _size(len) {}

        /** Constructs a StringData, for the case of a string. */
        StringData( const std::string& s )
            : _data(s.c_str()), _size(s.size()) {}

        /**
         * Constructs a StringData explicitly, for the case of a literal whose size is known at
         * compile time.
         */
        struct LiteralTag {};
        template<size_t N>
        StringData( const char (&val)[N], LiteralTag )
            : _data(&val[0]), _size(N-1) {}

        /**
         * Returns -1, 0, or 1 if 'this' is less, equal, or greater than 'other' in
         * lexicographical order.
         */
        int compare(const StringData& other) const {
            // Sizes might not have been computed yet.
            size();
            other.size();

            int res = memcmp(_data, other._data, std::min(_size, other._size));
            if (res != 0) {
                return res > 0 ? 1 : -1;
            }
            else if (_size == other._size) {
                return 0;
            }
            else {
                return _size > other._size ? 1 : -1;
            }
        }

        //
        // accessors
        //

        const char* data() const { return _data; }
        size_t size() const { fillSize(); return _size; }
        bool empty() const { return size() == 0; }
        string toString() const { return string(_data, _size); }

        string toStdString() const { return string(data(), size()); }
    private:
        const char* const _data;  // is always null terminated, but see "notes" above
        mutable size_t _size;     // 'size' does not include the null terminator

        void fillSize() const {
            if (_size == string::npos) {
                _size = strlen(_data);
            }
        }
    };

    inline bool operator==(const StringData& lhs, const StringData& rhs) {
        return lhs.compare(rhs) == 0;
    }

    inline bool operator!=(const StringData& lhs, const StringData& rhs) {
        return lhs.compare(rhs) != 0;
    }

    inline bool operator<(const StringData& lhs, const StringData& rhs) {
        return lhs.compare(rhs) < 0 ;
    }

    inline bool operator<=(const StringData& lhs, const StringData& rhs) {
        return lhs.compare(rhs) <= 0;
    }

    inline bool operator>(const StringData& lhs, const StringData& rhs) {
        return lhs.compare(rhs) > 0;
    }

    inline bool operator>=(const StringData& lhs, const StringData& rhs) {
        return lhs.compare(rhs) >= 0;
    }

} // namespace mongo