-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathexample.doxypage
153 lines (152 loc) · 4.97 KB
/
example.doxypage
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
/*
* This file is part of Lua API++ library (https://github.com/OldFisher/lua-api-pp)
* distributed under MIT License (http://opensource.org/licenses/MIT).
* See license.txt for details.
* (c) 2014 OldFisher
*/
/**
* @page motivational_example Motivational example
* To get a feeling of how the library is used, let's write a simple
* example program. It will be line interpreter working with standard input
* stream, with support of fixed-size numeric arrays.
* We assume that Lua and Lua-API++ are already set up in our project.
*
* First, we start with the interpreter part. The @ref lua::State "State"
* object will create Lua state and interpret strings.
*
* @code{.cpp}
* #include <iostream>
* #include <luapp/lua.hpp>
* using namespace std;
* using namespace lua;
*
* void interpretLine(State& state, const string& line)
* {
* try {
* state.runString(line); // Attempt to execute string
* } catch(exception& e) {
* cerr << e.what() << endl; // Show error message in case of execution failure
* }
* }
*
* void interpretStream(State& state, istream& in)
* {
* string currentLine;
* while(!in.eof()) { // Read and interpret lines from given stream
* getline(in, currentLine);
* interpretLine(state, currentLine);
* }
* }
*
* int main(int argc, const char* argv[])
* {
* State state;
* interpretStream(state, cin);
* }
* @endcode
*
* With this part done, we can add support of arrays. We will use @c vector of <c><b>double</b></c> as
* underlying native type. The simple Lua interface of our arrays will be as follows:
* - global Lua function @c createArray will create array objects of given size;
* - array objects will be accessed with integer indices for reading and writing elements;
* - wrong index will produce an error;
* - length operator will return amount of elements in the array.
*
* We can salvage some of the functions @c vector already has, so we need
* only to register userdata and write a couple of functions.
* @code{.cpp}
* using namespace lua;
*
* #include <vector>
* using dvec = vector<double>; // Nice comfy name for array type
* LUAPP_USERDATA(dvec, "numeric_array") // Register dvec as user data
*
* dvec aCreate(unsigned int size) // Function to create array
* {
* return dvec(size); // Created object gets moved into Lua-allocated storage, no expensive reallocations occur.
* }
*
* void aDestroy(dvec& self) // Destruction function is required because taking destructor address is forbidden
* {
* self.~dvec(); // Explicitly destroy object placed in memory allocated by Lua
* }
*
* void aWrite(dvec& self, unsigned int index, double val) // Write a number into array
* {
* self.at(index) = val; // Use .at() for checked access
* }
* @endcode
*
* Now we are ready for the final step: setting up the environment.
* It will require two things: associate metatable with dvec and define array-creating function.
* The function that does it needs access to Lua state, so it has to be @ref lua::LFunction "LFunction".
* @code{.cpp}
* using namespace lua; // For automatic link generation
* Retval setup(Context& c)
* {
* c.mt<dvec>() = // Context's mt() function gives access to userdata metatable
* Table::records(ctx, // Assign to MT newly created table filled with key-value pairs
* "__index", static_cast<double& (dvec::*)(size_t)>(&dvec::at), // Explicitly select non-const overload
* "__newindex", aWrite, // Checked write
* "__len", dvec::size, // Salvage vector::size for length operator
* "__gc", aDestroy // Salvage vector's destructor for garbage collection
* );
* c.global["createArray"] = aCreate; // Array creation function is a global value
* }
* @endcode
*
* This setup function will have to be called from main() by @ref lua::State "State" object,
* so it will need to be transformed into Lua compatible C function with @ref lua::mkcf "mkcf" template.
* Here is the final result:
* @code{.cpp}
* #include <iostream>
* #include <vector>
* #include <luapp/lua.hpp>
* using namespace lua;
* using namespace std;
*
* using dvec = vector<double>;
* LUAPP_USERDATA(dvec, "Number array")
*
* dvec aCreate(unsigned int size) { return dvec(size); }
* void aDestroy(dvec& self) { self.~dvec(); }
* void aWrite(dvec& self, unsigned int index, double val) { self.at(index) = val; }
*
* Retval setup(Context& c)
* {
* c.mt<dvec>() = Table::records(c,
* "__index", static_cast<double& (dvec::*)(size_t)>(&dvec::at),
* "__newindex", aWrite,
* "__len", dvec::size,
* "__gc", aDestroy
* );
* c.global["createArray"] = aCreate;
* return c.ret();
* }
*
* void interpretLine(State& state, const string& line)
* {
* try {
* state.runString(line);
* } catch(exception& e) {
* cerr << e.what() << endl;
* }
* }
*
* void interpretStream(State& state, istream& in)
* {
* string currentLine;
* while(!in.eof()){
* getline(in, currentLine);
* interpretLine(state, currentLine);
* }
* }
*
* int main()
* {
* State state;
* state.call(mkcf<setup>);
* interpretStream(state, cin);
* }
* @endcode
*/