File: any_moveable.hpp

package info (click to toggle)
gridtools 2.0.0-3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye
  • size: 21,728 kB
  • sloc: cpp: 45,263; python: 9,383; javascript: 8,445; ansic: 2,564; sh: 509; f90: 370; makefile: 216
file content (92 lines) | stat: -rw-r--r-- 3,094 bytes parent folder | download | duplicates (3)
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
/*
 * GridTools
 *
 * Copyright (c) 2014-2019, ETH Zurich
 * All rights reserved.
 *
 * Please, refer to the LICENSE file in the root directory.
 * SPDX-License-Identifier: BSD-3-Clause
 */
#pragma once

#include <memory>
#include <type_traits>
#include <typeinfo>
#include <utility>

namespace cpp_bindgen {

    struct bad_any_cast : std::bad_cast {
        const char *what() const noexcept override { return "cpp_bindgen::bad_any_cast"; }
    };

    /**
     *  this class implements the subset of std::any interface and can hold move only objects.
     *
     *  TODO(anstaf): implement missing std::any components: piecewise ctors, emplace, reset, swap, make_any
     */
    class any_moveable {
        struct iface {
            virtual ~iface() = default;
            virtual std::type_info const &type() const noexcept = 0;
        };
        template <class T>
        struct impl : iface {
            T m_obj;
            impl(T const &obj) : m_obj(obj) {}
            impl(T &&obj) : m_obj(std::move(obj)) {}
            std::type_info const &type() const noexcept override { return typeid(T); }
        };
        std::unique_ptr<iface> m_impl;

      public:
        any_moveable() = default;

        template <class Arg, class Decayed = typename std::decay<Arg>::type>
        any_moveable(Arg &&arg) : m_impl(new impl<Decayed>(std::forward<Arg>(arg))) {}
        any_moveable(any_moveable &&) = default;

        template <class Arg, class Decayed = typename std::decay<Arg>::type>
        any_moveable &operator=(Arg &&obj) {
            m_impl.reset(new impl<Decayed>(std::forward<Arg>(obj)));
            return *this;
        }
        any_moveable &operator=(any_moveable &&) = default;

        bool has_value() const noexcept { return !!m_impl; }
        std::type_info const &type() const noexcept { return m_impl->type(); }

        template <class T>
        friend T *any_cast(any_moveable *src) noexcept {
            return src && src->type() == typeid(T) ? &static_cast<impl<T> *>(src->m_impl.get())->m_obj : nullptr;
        }
    };

    template <class T>
    T const *any_cast(any_moveable const *src) noexcept {
        return any_cast<T>(const_cast<any_moveable *>(src));
    }

    template <class T>
    T any_cast(any_moveable &src) {
        auto *ptr = any_cast<typename std::remove_reference<T>::type>(&src);
        if (!ptr)
            throw bad_any_cast{};
        using ref_t = typename std::
            conditional<std::is_reference<T>::value, T, typename std::add_lvalue_reference<T>::type>::type;
        return static_cast<ref_t>(*ptr);
    }

    template <class T>
    T any_cast(any_moveable const &src) {
        return any_cast<T>(const_cast<any_moveable &>(src));
    }

    template <class T>
    T any_cast(any_moveable &&src) {
        static_assert(
            std::is_rvalue_reference<T &&>::value || std::is_const<typename std::remove_reference<T>::type>::value,
            "any_cast shall not be used for getting nonconst references to temporary objects");
        return any_cast<T>(src);
    }
} // namespace cpp_bindgen