File: refid.cpp

package info (click to toggle)
openmw 0.49.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 33,992 kB
  • sloc: cpp: 372,479; xml: 2,149; sh: 1,403; python: 797; makefile: 26
file content (250 lines) | stat: -rw-r--r-- 7,370 bytes parent folder | download
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
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
#include "refid.hpp"

#include "serializerefid.hpp"

#include "components/misc/strings/lower.hpp"

#include <charconv>
#include <ostream>
#include <sstream>
#include <stdexcept>
#include <system_error>
#include <variant>

namespace ESM
{
    namespace
    {
        const std::string emptyString;

        struct GetRefString
        {
            const std::string& operator()(EmptyRefId /*v*/) const { return emptyString; }

            const std::string& operator()(StringRefId v) const { return v.getValue(); }

            template <class T>
            const std::string& operator()(const T& v) const
            {
                std::ostringstream stream;
                stream << "RefId is not a string: " << v;
                throw std::runtime_error(stream.str());
            }
        };

        struct IsEqualToString
        {
            const std::string_view mRhs;

            bool operator()(StringRefId v) const noexcept { return v == mRhs; }

            template <class T>
            bool operator()(const T& /*v*/) const noexcept
            {
                return false;
            }
        };

        struct IsLessThanString
        {
            const std::string_view mRhs;

            bool operator()(StringRefId v) const noexcept { return v < mRhs; }

            template <class T>
            bool operator()(const T& /*v*/) const noexcept
            {
                return false;
            }
        };

        struct IsGreaterThanString
        {
            const std::string_view mLhs;

            bool operator()(StringRefId v) const noexcept { return mLhs < v; }

            template <class T>
            bool operator()(const T& /*v*/) const noexcept
            {
                return true;
            }
        };

        struct StartsWith
        {
            const std::string_view mPrefix;

            bool operator()(StringRefId v) const { return v.startsWith(mPrefix); }

            template <class T>
            bool operator()(const T& /*v*/) const
            {
                return false;
            }
        };

        struct EndsWith
        {
            const std::string_view mSuffix;

            bool operator()(StringRefId v) const { return v.endsWith(mSuffix); }

            template <class T>
            bool operator()(const T& /*v*/) const
            {
                return false;
            }
        };

        struct Contains
        {
            const std::string_view mSubString;

            bool operator()(StringRefId v) const { return v.contains(mSubString); }

            template <class T>
            bool operator()(const T& /*v*/) const
            {
                return false;
            }
        };

        struct SerializeText
        {
            std::string operator()(ESM::EmptyRefId /*v*/) const { return std::string(); }

            std::string operator()(ESM::StringRefId v) const { return Misc::StringUtils::lowerCase(v.getValue()); }

            std::string operator()(ESM::FormId v) const { return v.toString(formIdRefIdPrefix); }

            template <class T>
            std::string operator()(const T& v) const
            {
                return v.toDebugString();
            }
        };
    }

    bool RefId::operator==(std::string_view rhs) const
    {
        return std::visit(IsEqualToString{ rhs }, mValue);
    }

    bool operator<(RefId lhs, std::string_view rhs)
    {
        return std::visit(IsLessThanString{ rhs }, lhs.mValue);
    }

    bool operator<(std::string_view lhs, RefId rhs)
    {
        return std::visit(IsGreaterThanString{ lhs }, rhs.mValue);
    }

    RefId RefId::stringRefId(std::string_view value)
    {
        if (value.empty())
            return RefId();
        return RefId(StringRefId(value));
    }

    const std::string& RefId::getRefIdString() const
    {
        return std::visit(GetRefString{}, mValue);
    }

    std::string RefId::toString() const
    {
        return std::visit([](auto v) { return v.toString(); }, mValue);
    }

    std::string RefId::toDebugString() const
    {
        return std::visit(
            [](auto v) {
                if constexpr (std::is_same_v<decltype(v), FormId>)
                    return v.toString(formIdRefIdPrefix);
                else
                    return v.toDebugString();
            },
            mValue);
    }

    bool RefId::startsWith(std::string_view prefix) const
    {
        return std::visit(StartsWith{ prefix }, mValue);
    }

    bool RefId::endsWith(std::string_view suffix) const
    {
        return std::visit(EndsWith{ suffix }, mValue);
    }

    bool RefId::contains(std::string_view subString) const
    {
        return std::visit(Contains{ subString }, mValue);
    }

    std::string RefId::serialize() const
    {
        std::string result(sizeof(mValue), '\0');
        std::memcpy(result.data(), &mValue, sizeof(mValue));
        return result;
    }

    ESM::RefId RefId::deserialize(std::string_view value)
    {
        if (value.size() != sizeof(ESM::RefId::mValue))
            throw std::runtime_error("Invalid value size to deserialize: " + std::to_string(value.size()));
        ESM::RefId result;
        std::memcpy(&result.mValue, value.data(), sizeof(result.mValue));
        return result;
    }

    std::string RefId::serializeText() const
    {
        return std::visit(SerializeText{}, mValue);
    }

    ESM::RefId RefId::deserializeText(std::string_view value)
    {
        if (value.empty())
            return ESM::RefId();

        if (value.starts_with(formIdRefIdPrefix))
        {
            uint64_t v = deserializeHexIntegral<uint64_t>(formIdRefIdPrefix.size(), value);
            uint32_t index = static_cast<uint32_t>(v) & 0xffffff;
            int contentFile = static_cast<int>(v >> 24);
            return ESM::FormId{ index, contentFile };
        }

        if (value.starts_with(generatedRefIdPrefix))
            return ESM::RefId::generated(deserializeHexIntegral<std::uint64_t>(generatedRefIdPrefix.size(), value));

        if (value.starts_with(indexRefIdPrefix))
        {
            ESM::RecNameInts recordType{};
            std::memcpy(&recordType, value.data() + indexRefIdPrefix.size(), sizeof(recordType));
            return ESM::RefId::index(recordType,
                deserializeHexIntegral<std::uint32_t>(indexRefIdPrefix.size() + sizeof(recordType) + 1, value));
        }

        if (value.starts_with(esm3ExteriorCellRefIdPrefix))
        {
            if (value.size() < esm3ExteriorCellRefIdPrefix.size() + 3)
                throw std::runtime_error("Invalid ESM3ExteriorCellRefId format: not enough size");
            const std::size_t separator = value.find(':', esm3ExteriorCellRefIdPrefix.size() + 1);
            if (separator == std::string_view::npos)
                throw std::runtime_error("Invalid ESM3ExteriorCellRefId format: coordinates separator is not found");
            const std::int32_t x
                = deserializeDecIntegral<std::int32_t>(esm3ExteriorCellRefIdPrefix.size(), separator, value);
            const std::int32_t y = deserializeDecIntegral<std::int32_t>(separator + 1, value.size(), value);
            return ESM::ESM3ExteriorCellRefId(x, y);
        }

        if (auto id = ESM::StringRefId::deserializeExisting(value))
            return *id;
        return {};
    }
}