summaryrefslogtreecommitdiffhomepage
path: root/vendor/toml++/impl/parse_result.hpp
blob: ca0e3f56e3f268ecebecee2470dc86b2aef68dc6 (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
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
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
// # This file is a part of toml++ and is subject to the the terms of the MIT license.
// # Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
// # See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
//  SPDX-License-Identifier: MIT
#pragma once

#include "preprocessor.hpp"
#if TOML_DOXYGEN || (TOML_ENABLE_PARSER && !TOML_EXCEPTIONS)

#include "header_start.hpp"
#include "parse_error.hpp"
#include "table.hpp"

TOML_NAMESPACE_START {
  TOML_ABI_NAMESPACE_START(noex);

  /// \brief	The result of a parsing operation.
  ///
  /// \availability <strong>This type only exists when exceptions are disabled.</strong>
  /// 		 Otherwise parse_result is just an alias for toml::table: \cpp
  /// #if TOML_EXCEPTIONS
  ///		using parse_result = table;
  /// #else
  ///		class parse_result { // ...
  ///	#endif
  /// \ecpp
  ///
  /// \detail A parse_result is effectively a discriminated union containing either a toml::table
  /// 		or a toml::parse_error. Most member functions assume a particular one of these two states,
  /// 		and calling them when in the wrong state will cause errors (e.g. attempting to access the
  /// 		error object when parsing was successful). \cpp
  /// toml::parse_result result = toml::parse_file("config.toml");
  /// if (result)
  ///		do_stuff_with_a_table(result); //implicitly converts to table&
  ///	else
  ///		std::cerr << "Parse failed:\n"sv << result.error() << "\n";
  /// \ecpp
  ///
  /// \out
  /// example output:
  ///
  /// Parse failed:
  /// Encountered unexpected character while parsing boolean; expected 'true', saw 'trU'
  ///		(error occurred at line 1, column 13 of 'config.toml')
  /// \eout
  ///
  /// Getting node_views (`operator[]`, `at_path()`) and using the iterator accessor functions
  /// (`begin()`, `end()` etc.) are unconditionally safe; when parsing fails these just return
  /// 'empty' values. A ranged-for loop on a failed parse_result is also safe since `begin()` and
  /// `end()` return the same iterator and will not lead to any dereferences and iterations.
  class parse_result {
   private:
    struct storage_t {
      static constexpr size_t size =
          (sizeof(toml::table) < sizeof(parse_error) ? sizeof(parse_error) : sizeof(toml::table));
      static constexpr size_t align =
          (alignof(toml::table) < alignof(parse_error) ? alignof(parse_error)
                                                       : alignof(toml::table));

      alignas(align) unsigned char bytes[size];
    };

    alignas(storage_t::align) mutable storage_t storage_;
    bool err_;

    template <typename Type>
    TOML_NODISCARD TOML_ALWAYS_INLINE static Type* get_as(storage_t& s) noexcept {
      return TOML_LAUNDER(reinterpret_cast<Type*>(s.bytes));
    }

    void destroy() noexcept {
      if (err_)
        get_as<parse_error>(storage_)->~parse_error();
      else
        get_as<toml::table>(storage_)->~table();
    }

   public:
    /// \brief Default constructs an 'error' result.
    TOML_NODISCARD_CTOR
    parse_result() noexcept  //
        : err_{true} {
      ::new (static_cast<void*>(storage_.bytes)) parse_error{std::string{}, source_region{}};
    }

    TOML_NODISCARD_CTOR
    explicit parse_result(toml::table&& tbl) noexcept  //
        : err_{false} {
      ::new (static_cast<void*>(storage_.bytes)) toml::table{std::move(tbl)};
    }

    TOML_NODISCARD_CTOR
    explicit parse_result(parse_error&& err) noexcept  //
        : err_{true} {
      ::new (static_cast<void*>(storage_.bytes)) parse_error{std::move(err)};
    }

    /// \brief	Move constructor.
    TOML_NODISCARD_CTOR
    parse_result(parse_result&& res) noexcept  //
        : err_{res.err_} {
      if (err_)
        ::new (static_cast<void*>(storage_.bytes)) parse_error{std::move(res).error()};
      else
        ::new (static_cast<void*>(storage_.bytes)) toml::table{std::move(res).table()};
    }

    /// \brief	Move-assignment operator.
    parse_result& operator=(parse_result&& rhs) noexcept {
      if (err_ != rhs.err_) {
        destroy();
        err_ = rhs.err_;
        if (err_)
          ::new (static_cast<void*>(storage_.bytes)) parse_error{std::move(rhs).error()};
        else
          ::new (static_cast<void*>(storage_.bytes)) toml::table{std::move(rhs).table()};
      } else {
        if (err_)
          error() = std::move(rhs).error();
        else
          table() = std::move(rhs).table();
      }
      return *this;
    }

    /// \brief	Destructor.
    ~parse_result() noexcept { destroy(); }

    /// \name Result state
    /// @{

    /// \brief	Returns true if parsing succeeeded.
    TOML_NODISCARD
    bool succeeded() const noexcept { return !err_; }

    /// \brief	Returns true if parsing failed.
    TOML_NODISCARD
    bool failed() const noexcept { return err_; }

    /// \brief	Returns true if parsing succeeded.
    TOML_NODISCARD
    explicit operator bool() const noexcept { return !err_; }

    /// @}

    /// \name Successful parses
    /// \warning It is undefined behaviour to call these functions when the result respresents a
    /// failed parse. Check #failed(), #succeeded or #operator bool() to determine the result's
    /// state.
    /// @{

    /// \brief	Returns the internal toml::table.
    TOML_NODISCARD
    toml::table& table() & noexcept {
      TOML_ASSERT_ASSUME(!err_);
      return *get_as<toml::table>(storage_);
    }

    /// \brief	Returns the internal toml::table (rvalue overload).
    TOML_NODISCARD
    toml::table&& table() && noexcept {
      TOML_ASSERT_ASSUME(!err_);
      return static_cast<toml::table&&>(*get_as<toml::table>(storage_));
    }

    /// \brief	Returns the internal toml::table (const lvalue overload).
    TOML_NODISCARD
    const toml::table& table() const& noexcept {
      TOML_ASSERT_ASSUME(!err_);
      return *get_as<const toml::table>(storage_);
    }

    /// \brief	Returns the internal toml::table.
    TOML_NODISCARD
    /* implicit */ operator toml::table&() noexcept { return table(); }

    /// \brief	Returns the internal toml::table (rvalue overload).
    TOML_NODISCARD
    /* implicit */ operator toml::table&&() noexcept { return std::move(table()); }

    /// \brief	Returns the internal toml::table (const lvalue overload).
    TOML_NODISCARD
    /* implicit */ operator const toml::table&() const noexcept { return table(); }

    /// @}

    /// \name Failed parses
    /// \warning It is undefined behaviour to call these functions when the result respresents a
    /// successful parse. Check #failed(), #succeeded or #operator bool() to determine the result's
    /// state.
    /// @{

    /// \brief	Returns the internal toml::parse_error.
    TOML_NODISCARD
    parse_error& error() & noexcept {
      TOML_ASSERT_ASSUME(err_);
      return *get_as<parse_error>(storage_);
    }

    /// \brief	Returns the internal toml::parse_error (rvalue overload).
    TOML_NODISCARD
    parse_error&& error() && noexcept {
      TOML_ASSERT_ASSUME(err_);
      return static_cast<parse_error&&>(*get_as<parse_error>(storage_));
    }

    /// \brief	Returns the internal toml::parse_error (const lvalue overload).
    TOML_NODISCARD
    const parse_error& error() const& noexcept {
      TOML_ASSERT_ASSUME(err_);
      return *get_as<const parse_error>(storage_);
    }

    /// \brief	Returns the internal toml::parse_error.
    TOML_NODISCARD
    explicit operator parse_error&() noexcept { return error(); }

    /// \brief	Returns the internal toml::parse_error (rvalue overload).
    TOML_NODISCARD
    explicit operator parse_error&&() noexcept { return std::move(error()); }

    /// \brief	Returns the internal toml::parse_error (const lvalue overload).
    TOML_NODISCARD
    explicit operator const parse_error&() const noexcept { return error(); }

    /// @}

    /// \name Iteration
    /// @{

    /// \brief A BidirectionalIterator for iterating over key-value pairs in a wrapped toml::table.
    using iterator = table_iterator;

    /// \brief A BidirectionalIterator for iterating over const key-value pairs in a wrapped
    /// toml::table.
    using const_iterator = const_table_iterator;

    /// \brief	Returns an iterator to the first key-value pair in the wrapped table.
    /// \remarks Always returns the same value as #end() if parsing failed.
    TOML_NODISCARD
    table_iterator begin() noexcept { return err_ ? table_iterator{} : table().begin(); }

    /// \brief	Returns an iterator to the first key-value pair in the wrapped table.
    /// \remarks Always returns the same value as #end() if parsing failed.
    TOML_NODISCARD
    const_table_iterator begin() const noexcept {
      return err_ ? const_table_iterator{} : table().begin();
    }

    /// \brief	Returns an iterator to the first key-value pair in the wrapped table.
    /// \remarks Always returns the same value as #cend() if parsing failed.
    TOML_NODISCARD
    const_table_iterator cbegin() const noexcept {
      return err_ ? const_table_iterator{} : table().cbegin();
    }

    /// \brief	Returns an iterator to one-past-the-last key-value pair in the wrapped table.
    TOML_NODISCARD
    table_iterator end() noexcept { return err_ ? table_iterator{} : table().end(); }

    /// \brief	Returns an iterator to one-past-the-last key-value pair in the wrapped table.
    TOML_NODISCARD
    const_table_iterator end() const noexcept {
      return err_ ? const_table_iterator{} : table().end();
    }

    /// \brief	Returns an iterator to one-past-the-last key-value pair in the wrapped table.
    TOML_NODISCARD
    const_table_iterator cend() const noexcept {
      return err_ ? const_table_iterator{} : table().cend();
    }

    /// @}

    /// \name Node views
    /// @{

    /// \brief Returns a view of the subnode matching a fully-qualified "TOML path".
    ///
    /// \see #toml::node::at_path(std::string_view)
    TOML_NODISCARD
    node_view<node> at_path(std::string_view path) noexcept {
      return err_ ? node_view<node>{} : table().at_path(path);
    }

    /// \brief Returns a const view of the subnode matching a fully-qualified "TOML path".
    ///
    /// \see #toml::node::at_path(std::string_view)
    TOML_NODISCARD
    node_view<const node> at_path(std::string_view path) const noexcept {
      return err_ ? node_view<const node>{} : table().at_path(path);
    }

    /// \brief Returns a view of the subnode matching a fully-qualified "TOML path".
    ///
    /// \see #toml::node::at_path(const toml::path&)
    TOML_NODISCARD
    node_view<node> at_path(const toml::path& path) noexcept {
      return err_ ? node_view<node>{} : table().at_path(path);
    }

    /// \brief Returns a const view of the subnode matching a fully-qualified "TOML path".
    ///
    /// \see #toml::node::at_path(const toml::path&)
    TOML_NODISCARD
    node_view<const node> at_path(const toml::path& path) const noexcept {
      return err_ ? node_view<const node>{} : table().at_path(path);
    }

#if TOML_ENABLE_WINDOWS_COMPAT

    /// \brief Returns a view of the subnode matching a fully-qualified "TOML path".
    ///
    /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
    ///
    /// \see #toml::node::at_path(std::string_view)
    TOML_NODISCARD
    node_view<node> at_path(std::wstring_view path) {
      return err_ ? node_view<node>{} : table().at_path(path);
    }

    /// \brief Returns a const view of the subnode matching a fully-qualified "TOML path".
    ///
    /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
    ///
    /// \see #toml::node::at_path(std::string_view)
    TOML_NODISCARD
    node_view<const node> at_path(std::wstring_view path) const {
      return err_ ? node_view<const node>{} : table().at_path(path);
    }

#endif

    /// \brief Returns a view of the subnode matching a fully-qualified "TOML path".
    ///
    /// \see #toml::node::operator[](const toml::path&)
    TOML_NODISCARD
    node_view<node> operator[](const toml::path& path) noexcept {
      return err_ ? node_view<node>{} : table()[path];
    }

    /// \brief Returns a const view of the subnode matching a fully-qualified "TOML path".
    ///
    /// \see #toml::node::operator[](const toml::path&)
    TOML_NODISCARD
    node_view<const node> operator[](const toml::path& path) const noexcept {
      return err_ ? node_view<const node>{} : table()[path];
    }

    /// \brief	Gets a node_view for the selected key-value pair in the wrapped table.
    ///
    /// \param 	key The key used for the lookup.
    ///
    /// \returns	A view of the value at the given key if parsing was successful and a matching key
    /// existed, 			or an empty node view.
    ///
    /// \see toml::node_view
    TOML_NODISCARD
    node_view<node> operator[](std::string_view key) noexcept {
      return err_ ? node_view<node>{} : table()[key];
    }

    /// \brief	Gets a node_view for the selected key-value pair in the wrapped table (const
    /// overload).
    ///
    /// \param 	key The key used for the lookup.
    ///
    /// \returns	A view of the value at the given key if parsing was successful and a matching key
    /// existed, 			or an empty node view.
    ///
    /// \see toml::node_view
    TOML_NODISCARD
    node_view<const node> operator[](std::string_view key) const noexcept {
      return err_ ? node_view<const node>{} : table()[key];
    }

#if TOML_ENABLE_WINDOWS_COMPAT

    /// \brief	Gets a node_view for the selected key-value pair in the wrapped table.
    ///
    /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
    ///
    /// \param 	key The key used for the lookup.
    ///
    /// \returns	A view of the value at the given key if parsing was successful and a matching key
    /// existed, 			or an empty node view.
    ///
    /// \see toml::node_view
    TOML_NODISCARD
    node_view<node> operator[](std::wstring_view key) {
      return err_ ? node_view<node>{} : table()[key];
    }

    /// \brief	Gets a node_view for the selected key-value pair in the wrapped table (const
    /// overload).
    ///
    /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
    ///
    /// \param 	key The key used for the lookup.
    ///
    /// \returns	A view of the value at the given key if parsing was successful and a matching key
    /// existed, 			or an empty node view.
    ///
    /// \see toml::node_view
    TOML_NODISCARD
    node_view<const node> operator[](std::wstring_view key) const {
      return err_ ? node_view<const node>{} : table()[key];
    }

#endif  // TOML_ENABLE_WINDOWS_COMPAT

    /// @}

#if TOML_ENABLE_FORMATTERS

    /// \brief Prints the held error or table object out to a text stream.
    ///
    /// \availability This operator is only available when #TOML_ENABLE_FORMATTERS is enabled.
    friend std::ostream& operator<<(std::ostream& os, const parse_result& result) {
      return result.err_ ? (os << result.error()) : (os << result.table());
    }

#endif
  };

  TOML_ABI_NAMESPACE_END;
}
TOML_NAMESPACE_END;

#include "header_end.hpp"
#endif  // TOML_ENABLE_PARSER && !TOML_EXCEPTIONS