forked from stinos/micropython-wrap
-
Notifications
You must be signed in to change notification settings - Fork 0
/
variable.h
136 lines (119 loc) · 4.09 KB
/
variable.h
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
#ifndef MICROPYTHONWRAP_VARIABLE
#define MICROPYTHONWRAP_VARIABLE
#include "classwrapper.h"
#include <stdexcept>
namespace upywrap
{
using varname = std::vector< std::string >;
namespace detail
{
inline mp_obj_t GetVariable( const char* name )
{
return mp_load_name( qstr_from_str( name ) );
}
inline mp_obj_t GetVariable( mp_obj_t instance, const char* name )
{
return mp_load_attr( instance, qstr_from_str( name ) );
}
inline mp_obj_t GetVariable( const char* instance, const char* name )
{
return GetVariable( GetVariable( instance ), name );
}
template< class... Names >
mp_obj_t GetVariable( const char* instance, const char* name, Names... names )
{
return GetVariable( GetVariable( instance, name ), names... );
}
inline mp_obj_t GetVariable( const varname& names )
{
const auto numNames = names.size();
if( !numNames )
{
throw std::runtime_error( "cannot get variable without a name" );
}
auto var = GetVariable( names[ 0 ].data() );
for( size_t i = 1 ; i < numNames ; ++i )
{
var = GetVariable( var, names[ i ].data() );
}
return var;
}
inline void SetVariable( mp_obj_t value, const char* name )
{
mp_store_name( qstr_from_str( name ), value );
}
inline void SetVariable( mp_obj_t instance, mp_obj_t value, const char* name )
{
mp_store_attr( instance, qstr_from_str( name ), value );
}
template< class... Names, size_t... Indices >
mp_obj_t GetVariableHelper( const std::tuple< Names... >& args, index_sequence< Indices... > )
{
return GetVariable( std::get< Indices >( args )... );
}
template< class... Names >
void SetVariable( mp_obj_t value, const char* instance, Names... names )
{
//get all arguments, then pass all but the last one to GetVariableHelper
const auto args = std::make_tuple( instance, names... );
mp_store_attr( GetVariableHelper( args, make_index_sequence< sizeof...( Names ) >() ), qstr_from_str( split_last( names... ) ), value );
}
inline void SetVariable( mp_obj_t value, const varname& names )
{
const auto numNames = names.size();
if( !numNames )
{
throw std::runtime_error( "cannot get variable without a name" );
}
if( numNames == 1 )
{
SetVariable( value, names[ 0 ].data() );
}
else
{
auto var = GetVariable( names[ 0 ].data() );
for( size_t i = 1 ; i < numNames - 1 ; ++i )
{
var = GetVariable( var, names[ i ].data() );
}
SetVariable( var, value, names[ numNames - 1 ].data() );
}
}
}
/**
* Get the value of any variable in scope, or an (possibly nested) attribute of an object in scope.
* Since this uses mp_store_xxx it uses the lookup rules for it, being: locals/globals/builtins,
* so it depends on the currently active scope which variabls will be found.
* For example:
* @code
auto i = upywrap::GetVariable< int >( "a" ); //get a from scope
auto i = upywrap::GetVariable< int >( "a", "b", "c" ); //get attribute c from attribute b from object a from scope, aka a.b.c
* @endcode
*/
template< class T, class... Names >
T GetVariable( Names... names )
{
return FromPy< T >( detail::GetVariable( names... ) );
}
template< class T >
T GetVariable( const varname& names )
{
return FromPy< T >( detail::GetVariable( names ) );
}
/**
* Set the value of any variable in scope, or an (possibly nested) attribute of an object in scope.
* Adds the variable/attribute if it does not exist, but not nested (so setting a.b.c is an error if a has no member b).
* Uses same lookup as GetVariable.
*/
template< class T, class... Names >
void SetVariable( const T& value, Names... names )
{
detail::SetVariable( ToPy( value ), names... );
}
template< class T >
void SetVariable( const T& value, const varname& names )
{
detail::SetVariable( ToPy( value ), names );
}
}
#endif //#ifndef MICROPYTHONWRAP_VARIABLE