summaryrefslogtreecommitdiff
path: root/src/include/rc_string.hpp
blob: 0d6ab155920152fed82c2edfebe610e948f3c3d4 (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
139
140
141
142
143
/*
 * MRustC - Rust Compiler
 * - By John Hodge (Mutabah/thePowersGang)
 *
 * include/rc_string.hpp
 * - Reference-counted string (used for spans)
 */
#pragma once

#include <cstring>
#include <ostream>
#include "../common.hpp"

class RcString
{
    unsigned int*   m_ptr;
public:
    RcString():
        m_ptr(nullptr)
    {}
    RcString(const char* s, unsigned int len);
    RcString(const char* s):
        RcString(s, ::std::strlen(s))
    {
    }
    explicit RcString(const ::std::string& s):
        RcString(s.data(), s.size())
    {
    }

    static RcString new_interned(const ::std::string& s);
    static RcString new_interned(const char* s);

    RcString(const RcString& x):
        m_ptr(x.m_ptr)
    {
        if( m_ptr ) *m_ptr += 1;
    }
    RcString(RcString&& x):
        m_ptr(x.m_ptr)
    {
        x.m_ptr = nullptr;
    }

    ~RcString();

    RcString& operator=(const RcString& x)
    {
        if( &x != this )
        {
            this->~RcString();
            m_ptr = x.m_ptr;
            if( m_ptr ) *m_ptr += 1;
        }
        return *this;
    }
    RcString& operator=(RcString&& x)
    {
        if( &x != this )
        {
            this->~RcString();
            m_ptr = x.m_ptr;
            x.m_ptr = nullptr;
        }
        return *this;
    }

    const char* begin() const { return c_str(); }
    const char* end() const { return c_str() + size(); }

    size_t size() const { return m_ptr ? m_ptr[1] : 0; }
    const char* c_str() const {
        if( m_ptr )
        {
            return reinterpret_cast<const char*>(m_ptr + 2);
        }
        else
        {
            return "";
        }
    }

    char back() const {
        assert(size() > 0 );
        return *(c_str() + size() - 1);
    }

    Ordering ord(const char* s, size_t l) const;
    Ordering ord(const RcString& s) const {
        if( m_ptr == s.m_ptr )
            return OrdEqual;
        return ord(s.c_str(), s.size());
    }
    bool operator==(const RcString& s) const {
        if(s.size() != this->size())
            return false;
        return this->ord(s) == OrdEqual;
    }
    bool operator!=(const RcString& s) const {
        if(s.size() != this->size())
            return true;
        return this->ord(s) != OrdEqual;
    }
    bool operator<(const RcString& s) const { return this->ord(s) == OrdLess; }
    bool operator>(const RcString& s) const { return this->ord(s) == OrdGreater; }

    Ordering ord(const std::string& s) const { return ord(s.data(), s.size()); }
    bool operator==(const std::string& s) const { return this->ord(s) == OrdEqual; }
    bool operator!=(const std::string& s) const { return this->ord(s) != OrdEqual; }
    bool operator<(const std::string& s) const { return this->ord(s) == OrdLess; }
    bool operator>(const std::string& s) const { return this->ord(s) == OrdGreater; }

    Ordering ord(const char* s) const;
    bool operator==(const char* s) const { return this->ord(s) == OrdEqual; }
    bool operator!=(const char* s) const { return this->ord(s) != OrdEqual; }

    friend ::std::ostream& operator<<(::std::ostream& os, const RcString& x);

    friend bool operator==(const char* a, const RcString& b) {
        return b == a;
    }
    friend bool operator!=(const char* a, const RcString& b) {
        return b != a;
    }

    int compare(size_t o, size_t l, const char* s) const {
        assert(o <= this->size());
        return memcmp(this->c_str() + o, s, l);
    }
};

namespace std {
    static inline bool operator==(const string& a, const ::RcString& b) {
        return b == a;
    }
    static inline bool operator!=(const string& a, const ::RcString& b) {
        return b != a;
    }
    template<> struct hash<RcString>
    {
        size_t operator()(const RcString& s) const noexcept;
    };
}