File Coverage

/usr/local/lib/perl5/site_perl/5.26.1/x86_64-linux/XS/libpanda.x/i/panda/cast.h
Criterion Covered Total %
statement 17 17 100.0
branch 68 132 51.5
condition n/a
subroutine n/a
pod n/a
total 85 149 57.0


line stmt bran cond sub pod time code
1             #pragma once
2             #include
3             #include
4             #include
5             #include
6             #include
7              
8             namespace panda {
9              
10             namespace detail { namespace cast {
11             typedef std::map DynCastCacheMap;
12              
13             template
14 77           DynCastCacheMap& get_map () {
15             thread_local DynCastCacheMap* map;
16 77 100         if (!map) {
    100          
    100          
    100          
    100          
    0          
17 35 50         thread_local struct { DynCastCacheMap map; } wrp;
    50          
    50          
    50          
    50          
    0          
18 7           map = &wrp.map;
19             }
20 77           return *map;
21             }
22              
23             constexpr const ptrdiff_t INCORRECT_PTRDIFF = PTRDIFF_MAX;
24             }}
25              
26             template
27 402           DERIVED_PTR dyn_cast (BASE* obj) {
28             using namespace detail::cast;
29             using DERIVED = typename std::remove_pointer::type;
30              
31 244           if (std::is_same::value) return (DERIVED_PTR)((void*)obj);
32 79 100         if (!obj) return NULL;
    50          
    50          
    50          
    50          
    0          
33              
34 77 50         intptr_t key = (intptr_t)typeid(*obj).name();
    50          
    50          
    50          
    50          
    0          
35 77           auto& map = get_map();
36             //auto& map = DynCastCache::map;
37 77 50         DynCastCacheMap::iterator it = map.find(key);
    50          
    50          
    50          
    50          
    0          
38 77 100         if (it != map.end())
    100          
    100          
    100          
    100          
    0          
39 67 100         return it->second != INCORRECT_PTRDIFF ? reinterpret_cast((char*)obj - it->second) : NULL;
    50          
    50          
    50          
    50          
    0          
40 10 50         DERIVED* ret = dynamic_cast(obj);
    50          
    50          
    50          
    50          
    0          
41 10 100         if (ret) map[key] = (char*)obj - (char*)ret;
    50          
    50          
    50          
    50          
    50          
    100          
    50          
    100          
    50          
    0          
    0          
42 3 50         else map[key] = INCORRECT_PTRDIFF;
    0          
    0          
    50          
    50          
    0          
43 79           return ret;
44             }
45              
46             template
47             DERIVED_REF dyn_cast (BASE& obj) {
48             using namespace detail::cast;
49             using DERIVED = typename std::remove_reference::type;
50              
51             if (std::is_same::value) return reinterpret_cast(obj);
52              
53             intptr_t key = (intptr_t)typeid(obj).name();
54             auto& map = get_map();
55             DynCastCacheMap::iterator it = map.find(key);
56             if (it != map.end() && it->second != INCORRECT_PTRDIFF)
57             return *(reinterpret_cast((char*)&obj - it->second));
58             // dont cache fails, as exceptions are much slower than dynamic_cast, let it always fall here
59             DERIVED& ret = dynamic_cast(obj);
60             map[key] = (char*)&obj - (char*)&ret;
61             return ret;
62             }
63              
64             }