ChaiScript / ChaiScript
1
// This file is distributed under the BSD License.
2
// See "license.txt" for details.
3
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
4
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
5
// http://www.chaiscript.com
6

7
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
8
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
9

10

11
#ifndef CHAISCRIPT_BOXED_VALUE_HPP_
12
#define CHAISCRIPT_BOXED_VALUE_HPP_
13

14
#include <map>
15
#include <memory>
16
#include <type_traits>
17

18
#include "../chaiscript_defines.hpp"
19
#include "any.hpp"
20
#include "type_info.hpp"
21

22
namespace chaiscript 
23
{
24

25
  /// \brief A wrapper for holding any valid C++ type. All types in ChaiScript are Boxed_Value objects
26
  /// \sa chaiscript::boxed_cast
27 1
  class Boxed_Value
28
  {
29
    public:
30
      /// used for explicitly creating a "void" object
31
      struct Void_Type
32
      {
33
      };
34

35
    private:
36
      /// structure which holds the internal state of a Boxed_Value
37
      /// \todo Get rid of Any and merge it with this, reducing an allocation in the process
38
      struct Data
39
      {
40 1
        Data(const Type_Info &ti,
41
            chaiscript::detail::Any to,
42
            bool is_ref,
43
            const void *t_void_ptr,
44
            bool t_return_value)
45 1
          : m_type_info(ti), m_obj(std::move(to)), m_data_ptr(ti.is_const()?nullptr:const_cast<void *>(t_void_ptr)), m_const_data_ptr(t_void_ptr),
46 1
            m_is_ref(is_ref), m_return_value(t_return_value)
47
        {
48
        }
49

50 1
        Data &operator=(const Data &rhs)
51
        {
52 1
          m_type_info = rhs.m_type_info;
53 1
          m_obj = rhs.m_obj;
54 1
          m_is_ref = rhs.m_is_ref;
55 1
          m_data_ptr = rhs.m_data_ptr;
56 1
          m_const_data_ptr = rhs.m_const_data_ptr;
57 1
          m_return_value = rhs.m_return_value;
58

59 1
          if (rhs.m_attrs)
60
          {
61 1
            m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>(*rhs.m_attrs);
62
          }
63

64 1
          return *this;
65
        }
66

67
        Data(const Data &) = delete;
68

69
        Data(Data &&) = default;
70
        Data &operator=(Data &&rhs) = default;
71

72

73
        Type_Info m_type_info;
74
        chaiscript::detail::Any m_obj;
75
        void *m_data_ptr;
76
        const void *m_const_data_ptr;
77
        std::unique_ptr<std::map<std::string, std::shared_ptr<Data>>> m_attrs;
78
        bool m_is_ref;
79
        bool m_return_value;
80
      };
81

82
      struct Object_Data
83
      {
84 1
        static auto get(Boxed_Value::Void_Type, bool t_return_value)
85
        {
86
          return std::make_shared<Data>(
87 1
                detail::Get_Type_Info<void>::get(),
88 1
                chaiscript::detail::Any(), 
89 0
                false,
90 1
                nullptr,
91 1
                t_return_value)
92
              ;
93
        }
94

95
        template<typename T>
96
          static auto get(const std::shared_ptr<T> *obj, bool t_return_value)
97
          {
98
            return get(*obj, t_return_value);
99
          }
100

101
        template<typename T>
102 1
          static auto get(const std::shared_ptr<T> &obj, bool t_return_value)
103
          {
104 1
            return std::make_shared<Data>(
105 1
                  detail::Get_Type_Info<T>::get(), 
106
                  chaiscript::detail::Any(obj), 
107 0
                  false,
108
                  obj.get(),
109
                  t_return_value
110 1
                );
111
          }
112

113
        template<typename T>
114 1
          static auto get(std::shared_ptr<T> &&obj, bool t_return_value)
115
          {
116 1
            auto ptr = obj.get();
117
            return std::make_shared<Data>(
118 1
                  detail::Get_Type_Info<T>::get(), 
119 1
                  chaiscript::detail::Any(std::move(obj)), 
120 1
                  false,
121
                  ptr,
122
                  t_return_value
123 1
                );
124
          }
125

126

127

128
        template<typename T>
129 1
          static auto get(T *t, bool t_return_value)
130
          {
131 1
            return get(std::ref(*t), t_return_value);
132
          }
133

134
        template<typename T>
135 1
          static auto get(const T *t, bool t_return_value)
136
          {
137 1
            return get(std::cref(*t), t_return_value);
138
          }
139

140

141
        template<typename T>
142 1
          static auto get(std::reference_wrapper<T> obj, bool t_return_value)
143
          {
144 1
            auto p = &obj.get();
145
            return std::make_shared<Data>(
146 1
                  detail::Get_Type_Info<T>::get(),
147 1
                  chaiscript::detail::Any(std::move(obj)),
148 1
                  true,
149
                  p,
150
                  t_return_value
151 1
                );
152
          }
153

154
        template<typename T>
155 1
          static auto get(std::unique_ptr<T> &&obj, bool t_return_value)
156
          {
157 1
            auto ptr = obj.get();
158
            return std::make_shared<Data>(
159 1
                  detail::Get_Type_Info<T>::get(), 
160 1
                  chaiscript::detail::Any(std::make_shared<std::unique_ptr<T>>(std::move(obj))), 
161 1
                  true,
162
                  ptr,
163
                  t_return_value
164 1
                );
165
          }
166

167
        template<typename T>
168 1
          static auto get(T t, bool t_return_value)
169
          {
170 1
            auto p = std::make_shared<T>(std::move(t));
171 1
            auto ptr = p.get();
172
            return std::make_shared<Data>(
173 1
                  detail::Get_Type_Info<T>::get(), 
174 1
                  chaiscript::detail::Any(std::move(p)),
175 1
                  false,
176
                  ptr,
177
                  t_return_value
178 1
                );
179
          }
180

181 1
        static std::shared_ptr<Data> get()
182
        {
183
          return std::make_shared<Data>(
184 0
                Type_Info(),
185 1
                chaiscript::detail::Any(),
186 0
                false,
187 0
                nullptr,
188 1
                false
189 1
              );
190
        }
191

192
      };
193

194
    public:
195
      /// Basic Boxed_Value constructor
196
        template<typename T,
197
          typename = std::enable_if_t<!std::is_same_v<Boxed_Value, std::decay_t<T>>>>
198 1
        explicit Boxed_Value(T &&t, bool t_return_value = false)
199 1
          : m_data(Object_Data::get(std::forward<T>(t), t_return_value))
200
        {
201
        }
202

203
      /// Unknown-type constructor
204 1
      Boxed_Value() = default;
205

206 1
      Boxed_Value(Boxed_Value&&) = default;
207
      Boxed_Value& operator=(Boxed_Value&&) = default;
208 1
      Boxed_Value(const Boxed_Value&) = default;
209
      Boxed_Value& operator=(const Boxed_Value&) = default;
210

211
      void swap(Boxed_Value &rhs) noexcept
212
      {
213
        std::swap(m_data, rhs.m_data);
214
      }
215

216
      /// Copy the values stored in rhs.m_data to m_data.
217
      /// m_data pointers are not shared in this case
218 1
      Boxed_Value assign(const Boxed_Value &rhs) noexcept
219
      {
220 1
        (*m_data) = (*rhs.m_data);
221 1
        return *this;
222
      }
223

224 1
      const Type_Info &get_type_info() const noexcept
225
      {
226 1
        return m_data->m_type_info;
227
      }
228

229
      /// return true if the object is uninitialized
230 1
      bool is_undef() const noexcept
231
      {
232 1
        return m_data->m_type_info.is_undef();
233
      }
234

235 1
      bool is_const() const noexcept
236
      {
237 1
        return m_data->m_type_info.is_const();
238
      }
239

240 1
      bool is_type(const Type_Info &ti) const noexcept
241
      {
242 1
        return m_data->m_type_info.bare_equal(ti);
243
      }
244

245

246
      template<typename T>
247 1
      auto pointer_sentinel(std::shared_ptr<T> &ptr) const noexcept
248
      {
249
        struct Sentinel {
250 1
          Sentinel(std::shared_ptr<T> &t_ptr, Data &data)
251 1
            : m_ptr(t_ptr), m_data(data)
252
          {
253
          }
254

255 1
          ~Sentinel()
256
          {
257
            // save new pointer data
258 1
            const auto ptr_ = m_ptr.get().get();
259 1
            m_data.get().m_data_ptr = ptr_;
260 1
            m_data.get().m_const_data_ptr = ptr_;
261
          }
262

263
          Sentinel& operator=(Sentinel&&s) = default;
264
          Sentinel(Sentinel &&s) = default;
265

266 1
          operator std::shared_ptr<T>&() const noexcept
267
          {
268 1
            return m_ptr.get();
269
          }
270

271
          Sentinel &operator=(const Sentinel &) = delete;
272
          Sentinel(Sentinel&) = delete;
273

274
          std::reference_wrapper<std::shared_ptr<T>> m_ptr;
275
          std::reference_wrapper<Data> m_data;
276
        };
277

278 1
        return Sentinel(ptr, *(m_data.get()));
279
      }
280

281 1
      bool is_null() const noexcept
282
      {
283 1
        return (m_data->m_data_ptr == nullptr && m_data->m_const_data_ptr == nullptr);
284
      }
285

286 1
      const chaiscript::detail::Any & get() const noexcept
287
      {
288 1
        return m_data->m_obj;
289
      }
290

291 1
      bool is_ref() const noexcept
292
      {
293 1
        return m_data->m_is_ref;
294
      }
295

296 1
      bool is_return_value() const noexcept
297
      {
298 1
        return m_data->m_return_value;
299
      }
300

301 1
      void reset_return_value() const noexcept
302
      {
303 1
        m_data->m_return_value = false;
304
      }
305

306 1
      bool is_pointer() const noexcept
307
      {
308 1
        return !is_ref();
309
      }
310

311 1
      void *get_ptr() const noexcept 
312
      {
313 1
        return m_data->m_data_ptr;
314
      }
315

316 1
      const void *get_const_ptr() const noexcept
317
      {
318 1
        return m_data->m_const_data_ptr;
319
      }
320

321 1
      Boxed_Value get_attr(const std::string &t_name)
322
      {
323 1
        if (!m_data->m_attrs)
324
        {
325 1
          m_data->m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>();
326
        }
327

328 1
        auto &attr = (*m_data->m_attrs)[t_name];
329 1
        if (attr) {
330 0
          return Boxed_Value(attr, Internal_Construction());
331
        } else {
332 1
          Boxed_Value bv; //default construct a new one
333 1
          attr = bv.m_data;
334 1
          return bv;
335
        }
336
      }
337

338 1
      Boxed_Value &copy_attrs(const Boxed_Value &t_obj)
339
      {
340 1
        if (t_obj.m_data->m_attrs)
341
        {
342 1
          m_data->m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>(*t_obj.m_data->m_attrs);
343
        }
344 1
        return *this;
345
      }
346

347 1
      Boxed_Value &clone_attrs(const Boxed_Value &t_obj)
348
      {
349 1
        copy_attrs(t_obj);
350 1
        reset_return_value();
351 1
        return *this;
352
      }
353

354

355
      /// \returns true if the two Boxed_Values share the same internal type
356 1
      static bool type_match(const Boxed_Value &l, const Boxed_Value &r) noexcept
357
      {
358 1
        return l.get_type_info() == r.get_type_info();
359
      }
360

361
    private:
362
      // necessary to avoid hitting the templated && constructor of Boxed_Value
363
      struct Internal_Construction{};
364

365 0
      Boxed_Value(std::shared_ptr<Data> t_data, Internal_Construction)
366 0
        : m_data(std::move(t_data)) {
367
      }
368

369
      std::shared_ptr<Data> m_data = Object_Data::get();
370
  };
371

372
  /// @brief Creates a Boxed_Value. If the object passed in is a value type, it is copied. If it is a pointer, std::shared_ptr, or std::reference_type
373
  ///        a copy is not made.
374
  /// @param t The value to box
375
  ///
376
  /// Example:
377
  ///
378
  /// ~~~{.cpp}
379
  /// int i;
380
  /// chaiscript::ChaiScript chai;
381
  /// chai.add(chaiscript::var(i), "i");
382
  /// chai.add(chaiscript::var(&i), "ip");
383
  /// ~~~
384
  ///
385
  /// @sa @ref adding_objects
386
  template<typename T>
387 1
    Boxed_Value var(T &&t)
388
    {
389 1
      return Boxed_Value(std::forward<T>(t));
390
    }
391

392
  namespace detail {
393
    /// \brief Takes a value, copies it and returns a Boxed_Value object that is immutable
394
    /// \param[in] t Value to copy and make const
395
    /// \returns Immutable Boxed_Value 
396
    /// \sa Boxed_Value::is_const
397
    template<typename T>
398 1
      Boxed_Value const_var_impl(const T &t)
399
      {
400 1
        return Boxed_Value(std::make_shared<typename std::add_const<T>::type >(t));
401
      }
402

403
    /// \brief Takes a pointer to a value, adds const to the pointed to type and returns an immutable Boxed_Value.
404
    ///        Does not copy the pointed to value.
405
    /// \param[in] t Pointer to make immutable
406
    /// \returns Immutable Boxed_Value
407
    /// \sa Boxed_Value::is_const
408
    template<typename T>
409 1
      Boxed_Value const_var_impl(T *t)
410
      {
411 1
        return Boxed_Value( const_cast<typename std::add_const<T>::type *>(t) );
412
      }
413

414
    /// \brief Takes a std::shared_ptr to a value, adds const to the pointed to type and returns an immutable Boxed_Value.
415
    ///        Does not copy the pointed to value.
416
    /// \param[in] t Pointer to make immutable
417
    /// \returns Immutable Boxed_Value
418
    /// \sa Boxed_Value::is_const
419
    template<typename T>
420 1
      Boxed_Value const_var_impl(const std::shared_ptr<T> &t)
421
      {
422 1
        return Boxed_Value( std::const_pointer_cast<typename std::add_const<T>::type>(t) );
423
      }
424

425
    /// \brief Takes a std::reference_wrapper value, adds const to the referenced type and returns an immutable Boxed_Value.
426
    ///        Does not copy the referenced value.
427
    /// \param[in] t Reference object to make immutable
428
    /// \returns Immutable Boxed_Value
429
    /// \sa Boxed_Value::is_const
430
    template<typename T>
431 1
      Boxed_Value const_var_impl(const std::reference_wrapper<T> &t)
432
      {
433 1
        return Boxed_Value( std::cref(t.get()) );
434
      }
435
  }
436

437
  /// \brief Takes an object and returns an immutable Boxed_Value. If the object is a std::reference or pointer type
438
  ///        the value is not copied. If it is an object type, it is copied.
439
  /// \param[in] t Object to make immutable
440
  /// \returns Immutable Boxed_Value
441
  /// \sa chaiscript::Boxed_Value::is_const
442
  /// \sa chaiscript::var
443
  ///
444
  /// Example:
445
  /// \code
446
  /// enum Colors
447
  /// {
448
  ///   Blue,
449
  ///   Green,
450
  ///   Red
451
  /// };
452
  /// chaiscript::ChaiScript chai
453
  /// chai.add(chaiscript::const_var(Blue), "Blue"); // add immutable constant
454
  /// chai.add(chaiscript::const_var(Red), "Red");
455
  /// chai.add(chaiscript::const_var(Green), "Green");
456
  /// \endcode
457
  /// 
458
  /// \todo support C++11 strongly typed enums
459
  /// \sa \ref adding_objects
460
  template<typename T>
461 1
    Boxed_Value const_var(const T &t)
462
    {
463 1
      return detail::const_var_impl(t);
464
    }
465

466 1
  inline Boxed_Value void_var() {
467 1
    static const auto v = Boxed_Value(Boxed_Value::Void_Type());
468 1
    return v;
469
  }
470

471
  inline Boxed_Value const_var(bool b) {
472
    static const auto t = detail::const_var_impl(true);
473
    static const auto f = detail::const_var_impl(false);
474

475
    if (b) {
476
      return t;
477
    } else {
478
      return f;
479
    }
480
  }
481

482
}
483

484
#endif
485

Read our documentation on viewing source code .

Loading