From 6cadf7f1a037ceefd76287912899bb9caa8ca52c Mon Sep 17 00:00:00 2001 From: Daniel Wallin Date: Wed, 25 Feb 2004 11:20:55 +0000 Subject: [PATCH] *** empty log message *** --- doc/docs.rst | 1983 +++++++++++++++++++++++++++++++++++++++++ doc/style.css | 291 +++++- src/class.cpp | 2 - src/class_info.cpp | 2 - src/class_registry.cpp | 2 - src/class_rep.cpp | 2 - src/create_class.cpp | 2 - src/find_best_match.cpp | 2 - src/function.cpp | 2 - src/implicit_cast.cpp | 2 - src/object.cpp | 2 - src/open.cpp | 2 - src/scope.cpp | 2 - src/stack_content_by_name.cpp | 2 - test/Jamfile | 1 + test/main.cpp | 2 + test/test_const.cpp | 90 +- test/test_free_functions.cpp | 401 +++++---- 18 files changed, 2508 insertions(+), 284 deletions(-) create mode 100755 doc/docs.rst rewrite test/test_const.cpp (95%) rewrite test/test_free_functions.cpp (93%) diff --git a/doc/docs.rst b/doc/docs.rst new file mode 100755 index 0000000..f81ffc2 --- /dev/null +++ b/doc/docs.rst @@ -0,0 +1,1983 @@ ++++++++++ + luabind ++++++++++ + +.. _MIT license: http://www.opensource.org/licenses/mit-license.php +.. _Boost: http://www.boost.org + +Note: This library is currently in public beta phase. This documentation +should be considered beta as well. Please report any grammatical +corrections/spelling corrections. + + +.. contents:: +.. section-numbering:: + +Introduction +============ + +Luabind is a library that helps you create bindings between C++ and lua. It has +the ability to expose functions and classes, written in C++, to lua. It will +also supply the functionality to define classes in lua and let them derive from +other lua classes or C++ classes. Lua classes can override virtual functions +from their C++ base classes. It is written towards lua 5.0, and does not work +with lua 4. + +It is implemented utilizing template meta programming. That means that you +don't need an extra preprocess pass to compile your project (it is done by the +compiler). It also means you don't (usually) have to know the exact signatureof +each function you register, since the library will generate code depending on +the compile-time type of the function (which includes the signature). The main +drawback of this approach is that the compilation time will increase for the +file that does the registration, it is therefore recommended that you register +everything in the same cpp-file. + +luabind is released under the terms of the `MIT license`_. + +We are very interested in hearing about projects that use luabind, please let +us know about your project. + + +Features +======== + +Luabind supports: + + - Overloaded free functions + - C++ classes in lua + - Overloaded member functions + - Operators + - Properties + - Enums + - Lua functions in C++ + - Lua classes in C++ + - Lua classes (single inheritance) + - Derives from lua or C++ classes + - O verride virtual functions from C++ classes + - Implicit casts between registered types + - Best match signature matching + - Return value policies and parameter policies + + +Portability +=========== + +Luabind has been tested to work on the following compilers: + + - Visual Studio 7.1 + - Visual Studio 7.0 + - Visual Studio 6.0 (sp 5) + - Intel C++ 6.0 (Windows) + - GCC 2.95.3 (cygwin) + - GCC 3.0.4 (Debian/Linux) + - GCC 3.1 (SunOS 5.8) + - GCC 3.2 (cygwin) + - GCC 3.3.1 (cygwin) + +It has been confirmed not to work with: + + - GCC 2.95.2 (SunOS 5.8) + +Metrowerks 8.3 (Windows) compiles but fails the const-test. This +means that const member functions are treated as non-const member +functions. + +If you have tried luabind with a compiler not listed here, let us know +your result with it. + + +Building luabind +================ + +To keep down the compilation-time luabind is built as a library. This means you +have to either build it and lika against it, or include its source files in +your project. You also have to make sure the luabind directory is somewhere in +your compiler's include path. It requires `Boost`_ 1.31.0 to be installed (only +boost headers). It also requires that lua is installed. + +The official way of building luabind is with `Boost.Build V2`_. To properly build +luabind with Boost.Build you need to set two environment variables: + +BOOST_ROOT + Point this to your Boost installation. + +LUA_PATH + Point this to your lua directory. The build system will assume that the + include and library files are located in ``$(LUA_PATH)/include/`` and + ``$(LUA_PATH)/lib/.`` + +For backward compatibility, there is also a makefile in the root-directory that +will build the library and the test program. If you are using a UNIX-system (or +cygwin) they will make it easy to build luabind as a static library. If you are +using Visual Studio it may be easier to include the files in the src directory +in your project. + +When building luabind you have several options that may streamline the library +to better suit your needs. It is extremely important that your application has +the same settings as the library was built with. The available options are +found in the `Configuration`_ section. + +If you want to change the settings to differ from the default, it's recommended +that you define the settings on the commandline of all your files (in the +project settings in visual studio). + +.. _`Boost.Build V2`: http://www.boost.org/tools/build/v2/index_v2.html + + +Basic usage +=========== + +To use luabind, you must include ``lua.h`` and luabind's main header file:: + + extern "C" + { + #include "lua.h" + } + + #include + +This includes support for both registering classes and functions. If you just +want to have support for functions or classes you can include +``luabind/function.hpp`` and ``luabind/class.hpp`` separately:: + + #include + #include + +The first thing you need to do is to call ``luabind::open(lua_State*)``` which +will register the functions to create classes from lua, and initialize some +state-global structures used by luabind. If you don't call this function you +will hit asserts later in the library. There is no corresponding close function +because once a class has been registered in lua, there really isn't any good +way to remove it. Partly because any remaining instances of that class relies +on the class being there. Everything will be cleaned up when the state is +closed though. + +.. Isn't this wrong? Don't we include lua.h using lua_include.hpp ? + +Note that no luabind header will include ``lua.h``, this is up to you. You have +to include it before any luabind header is included. + + +Hello world +----------- + +:: + + extern "C" + { + #include "lua.h" + } + + #include + + void greet() + { + std::cout << "Hello world!\n"; + } + + int main() + { + using namespace luabind; + + lua_State* L = lua_open(); + + open(L); + + module(L) + [ + def("greet", &greet) + ]; + } + +:: + + Lua 5.0 Copyright (C) 1994-2003 Tecgraf, PUC-Rio + > greet() + Hello world! + > + +Scopes +====== + +Everything that gets registered in lua is registered in a namespace (lua +tables) or in the global scope (called module). All registrations must be +surrounded by its scope. To define a module, the ``luabind::module`` class is +used. It is used like this:: + + module(L) + [ + // declarations + ]; + +This will register all declared functions or classes in the global namespace in +lua. If you want to have a namespace for your module (like the standard +libraries) you can give a name to the constructor, like this:: + + module(L, "my_library") + [ + // declarations + ]; + +Here all declarations will be put in the my_library table. + +If you want nested namespaces you can use the ``luabind::namespace_`` class. It +works exactly as ``luabind::module`` except that it doesn't take a lua_State* +in it's constructor. An example of its usage could look like this:: + + module(L, "my_library") + [ + // declarations + + namespace_("detail") + [ + // library-private declarations + ] + ]; + +As you might have figured out, the following declarations are equivalent:: + + module(L) + [ + namespace_("my_library") + [ + // declarations + ] + + ]; + +:: + + module(L, "my_library") + [ + // declarations + ]; + +Each declaration must be separated by a comma, like this:: + + module(L) + [ + def("f", &f), + def("g", &g), + class_("A") + .def(constructor), + def("h", &h) + ]; + + +More about the actual declarations in the `Binding functions to lua`_ and +`Binding classes to lua`_ sections. + +A word of caution, if you are in really bad need for performance, putting your +functions in tables will increase the lookup time. + + +Binding functions to lua +======================== + +To bind functions to lua you use the function ``luabind::def()``. It has the +following synopsis:: + + template + void def(const char* name, F f, const Policies&); + +- name is the name the function will have within lua. +- F is the function pointer you want to register. +- The Policies parameter is used to describe how parameters and return values + are treated by the function, this is an optional parameter. More on this in + the `policies`_ section. + +An example usage could be if you want to register the function ``float +std::sin(float)``:: + + module(L) + [ + def("sin", &std::sin) + ]; + +Overloaded functions +-------------------- + +If you have more than one function with the same name, and want to register +them in lua, you have to explicitly give the signature. This is to let C++ know +which function you refer to. For example, if you have two functions, ``int +f(const char*)`` and ``void f(int)``. :: + + module(L) + [ + def("f", (int(*)(const char*)) &f), + def("f", (void(*)(int)) &f) + ]; + +Signature matching +------------------ + +luabind will generate code that checks the lua stack to see if the values there +can match your functions' signatures. It will handle implicit typecasts between +derived classes, and it will prefer matches with the least number of implicit +casts. In a function call, if the function is overloaded and there's no +overload that match the parameters better than the other, you have an +ambiguity. This will spawn a run-time error, stating that the function call is +ambiguous. A simple example of this is to register one function that takes an +int and one that takes a float. Since lua don't distinguish between floats and +integers, both will always match. + +Since all overloads are tested, it will always find the best match (not the +first match). This also means that it can handle situations where the only +difference in the signature is that one member function is const and the other +isn't. + +.. sidebar:: Ownership transfer + + To correctly handle ownership transfer, create_a() would need an adopt + return value policy. More on this in the `Policies`_ section. + +For example, if the following function and class is registered: + +:: + + struct A + { + void f(); + void f() const; + }; + + const A* create_a(); + + struct B: A {}; + struct C: B {}; + + void g(A*); + void g(B*); + +And the following lua code is executed:: + + a1 = create_a() + a1:f() -- the const version is called + + a2 = A() + a2:f() -- the non-const version is called + + a = A() + b = B() + c = C() + + g(a) -- calls g(A*) + g(b) -- calls g(B*) + g(c) -- calls g(B*) + + +Calling lua functions +--------------------- + +To call a lua function, you can either use ``call_function()``, +``call_member()``, an ``object`` or ``functor``. + +:: + + template + Ret call_function(lua_State* L, const char* name, ...) + +This calls the global function called name. This function can only call global +lua functions. The ... represents a variable number of parameters that are sent +to the lua function. This function call may throw ``luabind::error`` if the +function call fails. + +The return value isn't actually Ret (the template parameter), but a proxy +object that will do the function call. This enables you to give policies to the +call. You do this with the operator[]. You give the policies within the +brackets, like this:: + + int ret = call_function( + L + , "a_lua_function" + , new complex_class() + )[ adopt(_1) ]; + +:: + + template + Ret call_member(object&, const char* name, ...) + +This treats the given object as an instance of a class. The given name is the +name of a member function to call. The ... represents a variable number of +parameters given to the function. This function may throw ``luabind::error`` if +the function call fails. + +You can give policies to a member function call the same way as you do with +``call_function``. + + +Binding classes to lua +====================== + +To register classes you use a class called ``class_``. Its name is supposed to +resemble the C++ keyword, to make it look more intuitive. It has an overloaded +member function ``def()`` that is used to register member functions, operators, +constructors, enums and properties on the class. It will return its +this-pointer, to let you register more members directly. + +Let's start with a simple example. Consider the following C++ class:: + + class testclass + { + public: + testclass(const std::string& s): m_string(s) {} + void print_string() { std::cout << m_string << "\n"; } + + private: + std::string m_string; + }; + +To register it with a lua environment, write as follows (assuming you are using +namespace luabind):: + + module(L) + [ + class_("testclass") + .def(constructor()) + .def("print_string", &testclass::print_string) + ]; + +This will register the class with the name testclass and constructor that takes +a string as argument and one member function with the name ``print_string``. + +:: + + Lua 5.0 Copyright (C) 1994-2003 Tecgraf, PUC-Rio + > a = testclass('a string') + > a:print_string() + a string + +It is also possible to register free functions as member functions. The +requirement on the function is that it takes a pointer, const pointer, +reference or const reference to the class type as the first parameter. The rest +of the parameters are the ones that are visible in lua, while the object +pointer is given as the first parameter. If we have the following C++ code:: + + struct A + { + int a; + }; + + int plus(A* o, int v) { return o->a + v; } + +You can register ``plus()`` as if it was a member function of A like this:: + + class_("A") + .def("plus", &plus) + +``plus()`` can now be called as a member function on A with one parameter, int. +If the object pointer parameter is const, the function will act as if it was a +const member function (it can be called on const objects). + + +Properties +---------- + +To register a global data member with a class is easily done. Consider the +following class:: + + struct A + { + int a; + }; + +This class is registered like this:: + + module(L) + [ + class_("A") + .def_readwrite("a", &A::a) + ]; + +This gives read and write access to the member variable ``A::a``. It is also +possible to register attributes with read-only access:: + + module(L) + [ + class_("A") + .def_readonly("a", &A::a) + ]; + +You can also register getter and setter functions and make them look as if they +were a public data member. Consider the following class:: + + class A + { + public: + void set_a(int x) { a = x; } + int get_a() const { return a; } + + private: + int a; + }; + +It can be registered as if it had a public data member a like this:: + + class_("A") + .property("a", &A::get_a, &A::set_a) + +This way the ``get_a()`` and ``set_a()`` functions will be called instead of +just writing to the data member. If you want to make it read only you can just +omit the last parameter. + + +Enums +----- + +If your class contains enumerated constants (enums), you can register them as +well to make them available in lua. Note that they will not be type safe, all +enums are integers in lua, and all functions that takes an enum, will accept +any integer. You register them like this:: + + module(L) + [ + class_("A") + .enum_("constants") + [ + value("my_enum", 4), + value("my_2nd_enum", 7), + value("another_enum", 6) + ] + ]; + +In lua they are accessed like any data member, except that they are read-only +and reached on the class itself rather than on an instance of the class. + +:: + + Lua 5.0 Copyright (C) 1994-2003 Tecgraf, PUC-Rio + > print(A.my_enum) + 4 + > print(A.another_enum) + 6 + + +Operators +--------- + +The mechanism for registering operators on your class is pretty simple. You use +a global name ``luabind::self`` to refer to the class itself and then you just +write the operator expression inside the ``def()`` call. This class:: + + struct vec + { + vec operator+(int s); + }; + +Is registered like this:: + + module(L) + [ + class_("vec") + .def(self + int()) + ]; + +This will work regardless if your plus operator is defined inside your class or +as a free function. + +If you operator is const (or, when defined as a free function, takes a const +reference to the class itself) you have to use ``const_self`` instead of +``self``. Like this:: + + module(L) + [ + class_("vec") + .def(const_self + int()) + ]; + +The operators supported are those available in lua: + + - \+ + - \- + - \* + - \/ + + .. more + +This means, no in-place operators. The equality operator (==) has a little +hatch, it will not be called if the references are equal. This means that the +== operator has to do pretty much what's it's expected to do. + +In the above example the other operand type is instantiated by writing +``int()``. If the operand type is a complex type that cannot easily be +instantiated you can wrap the type in a class called ``other<>``. For example: + +To register this class, we don't want to instantiate a string just to register +the operator. + +:: + + struct vec + { + vec operator+(std::string); + }; + +Instead we use the other ``wrapper`` like this:: + + module(L) + [ + class_("vec") + .def(self + other()) + ]; + +To register an application operator:: + + module(L) + [ + class_("vec") + .def( self(int()) ) + ]; + +There's one special operator. In lua it's called ``__tostring``, it's not +really an operator. It is used for converting objects to strings in a standard +way in lua. If you register this functionality, you will be able to use the lua +standard function ``tostring()`` for converting you object to a string. + +To implement this operator in C++ you should supply an ``operator<<`` for +ostream. Like this example:: + + class number {}; + std::ostream& operator<<(std::ostream&, number&); + + ... + + module(L) + [ + class_("number") + .def(tostring(self)) + ]; + + +Nested scopes and static functions +---------------------------------- + +It is possible to add nested scopes to a class. This is useful when you need +to wrap a nested class, or a static function. :: + + class_("foo") + .def(constructor<>() + ... + .static_ + [ + class_("nested"), + def("f", &f) + ]; + +It's also possible to add namespaces to classes using the same syntax. + + +Derived classes +--------------- + +If you want to register classes that derives from other classes, you can +specify a template parameter ``bases<>`` to the ``class_`` instantiation. The +following hierarchy:: + + struct A {}; + struct B : A {}; + +Would be registered like this:: + + module(L) + [ + class_("A"), + class_("B") + ]; + +If you have multiple inheritance you can specify more than one base. If B would +also derive from a class C, it would be registered like this:: + + module(L) + [ + class_ >("B") + ]; + +Note that you can omit ``bases<>`` when using single inheritance. + +.. note:: + If you don't specify that classes derive from each other, luabind will not + be able to implicitly cast pointers between the types. + + +Smart pointers +-------------- + +When you register a class you can tell luabind that all instances of that class +should be held by some kind of smart pointer (boost::shared_ptr for instance). +You do this by giving the holder type as an extra template parameter to +the``class_``your constructing, like this:: + + module(L) + [ + class_ >("A") + ]; + +You also have to supply two functions for your smart pointer. One that returns +the type of const version of the smart pointer type (boost::shared_ptr +in this case). And one function that extracts the raw pointer from the smart +pointer. The first function is needed because luabind has to allow the +non-const -> conversion when passing values from lua to C++. The second +function is needed when lua calls member functions on held types, the this +pointer must be a raw pointer, it is also needed to allow the smart_pointer -> +raw_pointer conversion from lua to C++. They look like this:: + + namespace luabind { + + template + T* get_pointer(boost::shared_ptr& p) + { + return p.get(); + } + + template + boost::shared_ptr* + get_const_holder(boost::shared_ptr*) + { + return 0; + } + } + +The conversion that works are (given that B is a base class of A): + ++----------------------------------------------+ +| From lua to C++ | ++======================+=======================+ +| holder_type | A* | ++----------------------+-----------------------+ +| holder_type | A* | ++----------------------+-----------------------+ +| holder_type | const A* | ++----------------------+-----------------------+ +| holder_type | const B* | ++----------------------+-----------------------+ +| holder_type | holder_type | ++----------------------+-----------------------+ +| holder_type | holder_type | ++----------------------+-----------------------+ +| holder_type | const A* | ++----------------------+-----------------------+ +| holder_type | const B* | ++----------------------+-----------------------+ +| holder_type | holder_type | ++----------------------+-----------------------+ + ++-----------------------------------------------------+ +| From C++ to lua | ++=============================+=======================+ +| holder_type | holder_type | ++-----------------------------+-----------------------+ +| holder_type | holder_type | ++-----------------------------+-----------------------+ +| const holder_type& | holder_type | ++-----------------------------+-----------------------+ +| const holder_type& | holder_type | ++-----------------------------+-----------------------+ + +When using a holder type, it can be useful to know if the pointer is valid. For +example when using std::auto_ptr, the holder will be invalidated when passed as +a parameter to a function. For this purpose there is a member of all object +instances in luabind: ``__ok``. :: + + struct test {}; + void f(std::auto_ptr); + + module(L) + [ + class_("test") + .def(constructor<>()), + + def("f", &f) + ]; + +:: + + Lua 5.0 Copyright (C) 1994-2003 Tecgraf, PUC-Rio + > a = test() + > f(a) + > print a.__ok + false + + +Object +====== + +Since functions have to be able to take lua values (of variable type) we need a +wrapper around them. This wrapper is called ``luabind::object``. If the +function you register takes an object, it will match any lua value. To use it, +you need to include ``luabind/object.hpp``. The object class has the following +synopsis:: + + class object + { + public: + class iterator; + class raw_iterator; + class array_iterator; + + template + object(lua_State*, const T& value); + object(const object&); + object(lua_State*); + object(); + + ~object(); + + iterator begin() const; + iterator end() const; + raw_iterator raw_begin() const; + raw_iterator raw_end() const; + array_iterator abegin() const; + array_iterator aend() const; + + void set(); + lua_State* lua_state() const; + void pushvalue() const; + bool is_valid() const; + operator safe_bool_type() const; + + template + operator[](const Key&); + + template + object at(const Key&) const; + + template + object raw_at(const Key&) const; + + template + object& operator=(const T&); + object& operator=(const object&); + + template + bool operator==(const T&) const; + bool operator==(const object&) const; + bool operator<(const object&) const; + bool operator<=(const object&) const; + bool operator>(const object&) const; + bool operator>=(const object&) const; + bool operator!=(const object&) const; + + void swap(object&); + int type() const; + + operator()(); + + template + operator()(const A0& a0); + + template + operator()(const A0& a0, const A1& a1); + + /* ... */ + + }; + +When you have a lua object, you can assign it a new value with the assignment +operator (=). When you do this, the ``default_policy`` will be used to make the +conversion from C++ value to lua. If your ``luabind::object`` is a table you +can access its members through the operator[] or the iterators. The value +returned from the operator[] is a proxy object that can be used both for +reading and writing values into the table (using operator=). Note that it is +impossible to know if a lua value is indexable or not (lua_gettable doesn't +fail, it succeeds or crashes). This means that if you're trying to index +something that cannot be indexed, you're on your own. Lua will call its +``panic()`` function (you can define your own panic function using +lua_setpanicf). The ``at()`` and ``raw_at()`` functions returns the value at +the given table position (like operator[] but only for reading). + +The ordinary ``object::iterator`` uses lua_gettable to extract the values from +the table, the standard way that will invoke metamethods if any. The +``object::raw_iterator`` uses lua_rawget and ``object::array_iterator`` uses +lua_rawgeti. The latter will only iterate over numberical keys starting at 1 +and continue until the first nil value. + +The ``lua_state()`` function returns the lua state where this object is stored. +If you want to manipulate the object with lua functions directly you can push +it onto the lua stack by calling ``pushvalue()``. And set the object's value by +calling ``set()``, which will pop the top value from the lua stack and assign +it to the object. + +The operator== will call lua_equal() on the operands and return its result. + +The ``type()`` member function will return the lua type of the object. It will +return the same values as lua_type(). + +The ``is_valid()`` function tells you whether the object has been initialized +or not. When created with its default constructor, objects are invalid. To make +an object valid, you can assign it a value. If you want to invalidate an object +you can simply assign it an invalid object. + +.. So what? implementation detail, leave out of docs + isn't really an implicit cast to bool, but an implicit cast + to a member pointer, since member pointers don't have any arithmetic operators + on them (which can cause hard to find errors). The functionality of the cast + operator + +The ``operator safe_bool_type()`` is equivalent to ``is_valid()``. This means +that these snippets are equivalent:: + + object o; + // ... + if (o) + { + // ... + } + + ... + + object o; + // ... + if (o.is_valid()) + { + // ... + } + +The application operator will call the value as if it was a function. You can +give it any number of parameters (currently the ``default_policy`` will be used +for the conversion). The returned object refers to the return value (currently +only one return value is supported). This operator may throw ``luabind::error`` +if the function call fails. If you want to specify policies to your function +call, you can use index-operator (operator[]) on the function call, and give +the policies within the [ and ]. Like this:: + + my_function_object( + 2 + , 8 + , new my_complex_structure(6) + ) [ adopt(_3) ]; + +This tells luabind to make lua adopt the ownership and responsibility for the +pointer passed in to the lua-function. + +It's important that all instances of object have been destructed by the time +the lua state is closed. The object will keep a pointer to the lua state and +release its lua object in its destructor. + +Here's an example of how a function can use a table:: + + void my_function(const object& table) + { + if (table.type() == LUA_TTABLE) + { + table["time"] = std::clock(); + table["name"] = std::rand() < 500 ? "unusual" : "usual"; + + std::cout << object_cast(table[5]) << "\n"; + } + } + +If you take a ``luabind::object`` as a parameter to a function, any lua value +will match that parameter. That's why we have to make sure it's a table before +we index into it. + + +Iterators +--------- + +The iterators, that are returned by ``begin() and ``end()`` (and their +variants) are (almost) models of the ForwardIterator concept. The exceptions +are that operator-> and post increment doesn't exist on them. + +They look like this:: + + class object::iterator + { + iterator(); + iterator(const iterator&); + + iterator& operator++(); + bool operator!=(const iterator&) const; + iterator& operator=(const iterator&); + + object key() const; + + implementation-defined operator*(); + }; + +The implementation defined return value from the dereference operator is a +proxy object that can be used as if it was an object, it can also be used to +assign the specific table entry with a new value. If you want to assign a value +to an entry pointed to by an iterator, just use the assignment operator on the +dereferenced iterator:: + + *iter = 5; + +The ``key()`` member returns the key used by the iterator when indexing the +associated lua table. + + +Related functions +----------------- + +There are a couple of functions related to objects and tables. :: + + T object_cast(const object&); + T object_cast(const object&, const Policies&); + + boost::optional + object_cast_nothrow(const object&); + + boost::optional + object_cast_nothrow(const object&, const Policies&); + + +Functor +------- + +The ``functor`` class is similar to object, with the exception that it can only +be used to store functions. If you take it as a parameter, it will only match +functions. + +To use it you need to include its header:: + + #include + +It takes one template parameter, the return value of the lua function it +represents. Currently the functor can have at most one return value (unlike lua +functions). It has the following synopsis:: + + template + class functor + { + public: + + functor(lua_State*, const char* name); + functor(const functor&); + + ~functor(); + + bool is_valid() const; + operator safe_bool_type() const; + + lua_State* lua_state() const; + void pushvalue() const; + + bool operator==(const functor&); + bool operator!=(const functor&); + + operator()() const; + + template + operator()(const A0&) const; + + template + operator()(const A0&, const A1&) const; + + /* ... */ + }; + +The application operator takes any parameters. The parameters are converted +into lua and the function is called. The return value will act as if it was the +type Ret, with the exception that you can use the return value to give policies +to the call. You do this the same way as you do with objects, using the +operator[], and giving the policies inside the brackets. + +The ``is_valid()`` function works just like the one on object, it tells you if +the functor has been assigned with a valid lua function. The ``operator +safe_bool_type()`` is an alias for this member function and also works just as +the one found in object. + +For example, if you have the following lua function:: + + function f(a, b) + return a + b + end + +You can expose it to C++ like this:: + + functor f(L, "f"); + + std::cout << f(3, 5) << "\n"; + +This will print out the sum of 3 and 5. Note that you can pass any parameters +to the application operator of ``luabind::functor``, this is because lua +doesn't have signatures for its functions. All lua functions take any number of +parameters of any type. + +If we have a C++ function that takes a ``luabind::functor`` and registers it, +it will accept lua functions passed to it. This enables us to expose APIs that +requires you to register callbacks. For example, if your C++ API looks like +this:: + + void set_callback(void(*)(int, int)); + +And you want to expose it to lua, you have to wrap the call to the lua +function inside a real C++ function, like this:: + + functor lua_callback; + + void callback_wrapper(int a, int b) + { + lua_callback(a, b); + } + + void set_callback_wrapper(const functor& f) + { + lua_callback = f; + set_callback(&callback_wrapper); + } + +And then register ``set_callback_wrapper`` instead of registering +``set_callback``. This will have the effect that when one tries to register the +callback from lua, your ``set_callback_wrapper`` will be called instead and +first set the lua functor to the given function. It will then call the real +``set_callback`` with the ``callback_wrapper``. The ``callback_wrapper`` will +be called whenever the callback should be called, and it will simply call the +lua function that we registered. + +You can also use ``object_cast`` to cast an object to a functor. + + +Defining classes in lua +======================= + +In addition to binding C++ functions and classes with lua, luabind also provide +an OO-system in lua. :: + + class 'lua_testclass' + + function lua_testclass:__init(name) + self.name = name + end + + function lua_testclass:print() + print(self.name) + end + + a = lua_testclass('example') + a:print() + + +Inheritance can be used between lua-classes:: + + class 'derived' (lua_testclass) + + function derived:__init() super('derived name') + end + + function derived:print() + print('Derived:print() -> ') + lua_testclass.print(self) + end + +Here the ``super`` keyword is used in the constructor to initialize the base +class. The user is required to call ``super`` first in the constructor. + +As you can see in this example, you can call the base class member functions. +You can find all member functions in the base class, but you will have to give +the this-pointer (``self``) as first argument. + + +Deriving in lua +--------------- + +It is also possible to derive lua classes from C++ classes, and override +virtual functions with lua functions. To do this we have to create a wrapper +class for our C++ base class. This is the class that will hold the lua object +when we instantiate a lua class. + +The wrapper class has to provide the same constructors as the base class, with +the addition of one extra parameter: ``luabind::object``. This is the reference +to the lua object that should be held by the wrapper, and should be stored in a +member variable as done in the sample below. :: + + class base + { + public: + base(const char* s) + { std::cout << s << "\n"; } + + virtual void f(int a) + { std::cout << "f(" << a << ")\n"; } + }; + + struct base_wrapper : base + { + object self; + base_wrapper(object self_, const char* s) + : base(s), self(self_) + {} + + virtual void f(int a) + { + call_member(self, "f", a); + } + + static void f_static(base* ptr, int a) + { + return ptr->base::f(a); + } + }; + + ... + + module(L) + [ + class_("base") + .def(constructor()) + .def("f", &base_wrapper::f_static) + ]; + +Note that if you have both base classes and a base class wrapper, you must give +both bases and the base class wrapper type as template parameter to +´´class_´´. The order in which you specify them is not important. + +If we didn't have a class wrapper, it would not be possible to pass a lua class +back to C++. Since the entry points of the virtual functions would still point +to the C++ base class, and not to the functions defined in lua. That's why we +need one function that calls the base class' real function (used if the lua +class doesn't redefine it) and one virtual function that dispatches the call +into luabind, to allow it to select if a lua function should be called, or if +the original function should be called. If you don't intend to derive from a +C++ class, or if it doesn't have any virtual member functions, you can register +it without a class wrapper. + +You don't need to have a class wrapper in order to derive from a class, but if +it has virtual functions you may have silent errors. + +.. Unnecessary? The rule of thumb is: + If your class has virtual functions, create a wrapper type, if it doesn't + don't create a wrapper type. + + +Overloading operators +--------------------- + +You can overload most operators in lua for your classes. You do this by simply +declaring a member function with the same name as an operator (the name of the +metamethods in lua). The operators you can overload are: + + - __add + - __sub + - __mul + - __div + - __pow + - __lt + - __le + - __eq + - __call + - __unm + - __tostring + +``__tostring`` isn't really an operator, but it's the metamethod that is called +by the standard library's ``tostring()`` function. There's one strange behavior +regarding binary operators. You are not guaranteed that the self pointer you +get actually refers to an instance of your class. This is because lua doesn't +distinguish the two cases where you get the other operand as left hand value or +right hand value. Consider the following examples:: + + class 'my_class' + + function my_class:__init(v) + self.val = v + end + + function my_class:__sub(v) + return my_class(self.val - v.val) + end + + function my_class:__tostring() + return self.val + end + +This will work well as long as you only subtracts instances of my_class with +each other. But If you want to be able to subtract ordinary numbers from your +class too, you have to manually check the type of both operands, including the +self object. :: + + function my_class:__sub(v) + if (type(self) == 'number') then + return my_class(self - v.val) + + elseif (type(v) == 'number') then + return my_class(self.val - v) + + else + -- assume both operands are instances of my_class + return my_class(self.val - v.val) + + end + end + +The reason why ``__sub`` is used as an example is because subtraction is not +commutative (the order of the operands matter). That's why luabind cannot +change order of the operands to make the self reference always refer to the +actual class instance. + +If you have two different lua classes with an overloaded operator, the operator +of the right hand side type will be called. If the other operand is a C++ class +with the same operator overloaded, it will be prioritized over the lua class' +operator. If none of the C++ overloads matches, the lua class operator will be +called. + + +Finalizers +---------- + +If an object needs to perform actions when it's collected we provide a +``__finalize`` function that can be overridden in lua-classes. The +``__finalize`` functions will be called on all classes in the inheritance +chain, starting with the most derived type. :: + + ... + + function lua_testclass:__finalize() + -- called when the an object is collected + end + + +Exceptions +========== + +If any of the functions you register throws an exception when called, that +exception will be caught by luabind and converted to an error string and +``lua_error()`` will be invoked. If the exception is a ``std::exception`` or a +``const char*`` the string that is pushed on the lua stack, as error message, +will be the string returned by ``std::exception::what()`` or the string itself +respectively. If the exception is unknown, a generic string saying that the +function threw an exception will be pushed. + +Exceptions thrown from user defined functions have to be caught by luabind. If +they weren't they would be thrown through lua itself, which is usually compiled +as C code and doesn't support the stack-unwinding that exceptions imply. + +Any function that invokes lua code may throw ``luabind::error``. This exception +means that a lua run-time error occurred. The error message is found on top of +the lua stack. The reason why the exception doesn't contain the error string +itself is because it would then require heap allocation which may fail. If an +exception class throws an exception while it is being thrown itself, the +application will be terminated. + +Error's synopsis is:: + + class error : public std::exception + { + public: + error(lua_State*); + lua_State* state() const throw(); + virtual const char* what() const throw(); + }; + +The state function returns a pointer to the lua state in which the error was +thrown. This pointer may be invalid if you catch this exception after the lua +state is destructed. If the lua state is valid you can use it to retrieve the +error message from the top of the lua stack. + +An example of where the lua state pointer may point to an invalid state +follows:: + + struct lua_state + { + lua_state(lua_State* L): m_L(L) {} + ~lua_state() { lua_close(m_L); } + operator lua_State*() { return m_L; } + lua_State* m_L; + }; + + int main() + { + try + { + lua_state L = lua_open(); + /* ... */ + } + catch(luabind::error& e) + { + lua_State* L = e.state(); + // L will now point to the destructed + // lua state and be invalid + /* ... */ + } + } + +There's another exception that luabind may throw: ``luabind::cast_failed``, +this exception is thrown from ``call_function<>``, ``call_member<>`` or when +``functor<>`` is invoked. It means that the return value from the lua function +couldn't be converted to a C++ value. It is also thrown from ``object_cast<>`` +if the cast cannot be made. + +The synopsis for ``luabind::cast_failed`` is:: + + class cast_failed : public std::exception + { + public: + cast_failed(lua_State*); + lua_State* state() const throw(); + LUABIND_TYPE_INFO info() const throw(); + virtual const char* what() const throw(); + }; + +Again, the state member function returns a pointer to the lua state where the +error occurred. See the example above to see where this pointer may be invalid. + +The info member function returns the user defined ``LUABIND_TYPE_INFO``, which +defaults to a ``const std::type_info*``. This type info describes the type that +we tried to cast a lua value to. + +If you have defined ``LUABIND_NO_EXCEPTIONS`` none of these exceptions will be +thrown, instead you can set two callback functions that are called instead. +These two functions are only defined if ``LUABIND_NO_EXCEPTIONS`` are defined. + +:: + + luabind::set_error_callback(void(*)(lua_State*)) + +The function you set will be called when a runtime-error occur in lua code. You +can find an error message on top of the lua stack. This function is not +expected to return, if it does luabind will call ``std::terminate()``. + +:: + + luabind::set_cast_failed_callback(void(*)(lua_State*, LUABIND_TYPE_INFO)) + +The function you set is called instead of throwing ``cast_failed``. This function +is not expected to return, if it does luabind will call ``std::terminate()``. + + +Policies +======== + +Sometimes it is necessary to control how luabind passes arguments and return +value, to do this we have policies. These are the policies that can be used: + +Copy +---- + +This will make a copy of the parameter. This is the default behavior when +passing parameters by-value. Note that this can only be used when passing from +C++ to lua. This policy requires that the parameter type has a copy +constructor. + +To use this policy you need to include ``luabind/copy_policy.hpp``. + + +Adopt +----- + +This will transfer ownership of the parameter. + +Consider making a factory function in C++ and exposing it to lua:: + + base* create_base() + { + return new base(); + } + + ... + + module(L) + [ + def("create_base", create_base) + ]; + +Here we need to make sure lua understands that it should adopt the pointer +returned by the factory-function. This can be done using the adopt-policy. + +:: + + module(L) + [ + def(L, "create_base", adopt(return_value)) + ]; + +To specify multiple policies we just separate them with '+'. + +:: + + base* set_and_get_new(base* ptr) + { + base_ptrs.push_back(ptr); + return new base(); + } + + module(L) + [ + def("set_and_get_new", &set_and_get_new, + adopt(return_value) + adopt(_1)) + ]; + +When lua adopts a pointer, it will call delete on it. This means that it cannot +adopt pointers allocated with another allocator than new (no malloc for +example). + +To use this policy you need to include ``luabind/adopt_policy.hpp``. + + +Dependency +---------- + +The dependency policy is used to create life-time dependencies between values. +Consider the following example:: + + struct A + { + B member; + + const B& get_member() + { + return member; + } + }; + +When wrapping this class, we would do something like:: + + module(L) + [ + class_("A") + .def(constructor<>()) + .def("get_member", &A::get_member) + ]; + + +However, since the return value of get_member is a reference to a member of A, +this will create some life-time issues. For example:: + + Lua 5.0 Copyright (C) 1994-2003 Tecgraf, PUC-Rio + a = A() + b = a:get_member() -- b points to a member of a + a = nil + collectgarbage(0) -- since there are no references left to a, it is + -- removed + -- at this point, b is pointing into a removed object + +When using the dependency-policy, it is possible to tell luabind to tie the +lifetime of one object to another, like this:: + + module(L) + [ + class_("A") + .def(constructor<>()) + .def("get_member", &A::get_member, dependency(result, self)) + ]; + +This will create a dependency between the return-value of the function, and the +self-object. This means that the self-object will be kept alive as long as the +result is still alive. :: + + Lua 5.0 Copyright (C) 1994-2003 Tecgraf, PUC-Rio + a = A() + b = a:get_member() -- b points to a member of a + a = nil + collectgarbage(0) -- a is dependent on b, so it isn't removed + b = nil + collectgarbage(0) -- all dependencies to a gone, a is removed + +To use this policy you need to include ``luabind/dependency_policy.hpp``. + + +Return reference to +------------------- + +It is very common to return references to arguments or the this-pointer to +allow for chaining in C++. + +:: + + struct A + { + float val; + + A& set(float v) + { + val = v; + return *this; + } + }; + +When luabind generates code for this, it will create a new object for the +return-value, pointing to the self-object. This isn't a problem, but could be a +bit inefficient. When using the return_reference_to-policy we have the ability +to tell luabind that the return-value is already on the lua stack. + +:: + + module(L) + [ + class_("A") + .def(constructor<>()) + .def("set", &A::set, return_reference_to(self)) + ]; + +Instead of creating a new object, luabind will just copy the object that is +already on the stack. + +.. warning:: + This policy ignores all type information and should be used only it + situations where the parameter type is a perfect match to the + return-type (such as in the example). + +To use this policy you need to include ``luabind/return_reference_to_policy.hpp``. + + +Out value +--------- + +This policy makes it possible to wrap functions that take non const references +as its parameters with the intention to write return values to them. + +:: + + void f(float& val) { val = val + 10.f; } + +or + +:: + + void f(float* val) { *val = *val + 10.f; } + +Can be wrapped by doing:: + + module(L) + [ + def("f", &f, out_value(_1)) + ]; + +When invoking this function from lua it will return the value assigned to its +parameter. + +:: + + Lua 5.0 Copyright (C) 1994-2003 Tecgraf, PUC-Rio + > a = f(10) + > print(a) + 20 + +When this policy is used in conjunction with user define types we often need +to do ownership transfers. + +:: + + struct A; + + void f1(A*& obj) { obj = new A(); } + void f2(A** obj) { *obj = new A(); } + +Here we need to make sure luabind takes control over object returned, for +this we use the adopt policy:: + + module(L) + [ + class_("A"), + def("f1", &f1, out_value(_1, adopt(_2))) + def("f2", &f2, out_value(_1, adopt(_2))) + ]; + +Here we are using adopt as an internal policy to out_value. The index +specified, _2, means adopt will be used to convert the value back to lua. +Using _1 means the policy will be used when converting from lua to C++. + +To use this policy you need to include ``luabind/out_value_policy.hpp``. + +Pure out value +-------------- + +This policy works in exactly the same way as out_value, except that it +replaces the parameters with default-constructed objects. + +:: + + void get(float& x, float& y) + { + x = 3.f; + y = 4.f; + } + + ... + + module(L) + [ + def("get", &get, + pure_out_value(_1) + pure_out_value(_2)) + ]; + +:: + + Lua 5.0 Copyright (C) 1994-2003 Tecgraf, PUC-Rio + > x, y = get() + > print(x, y) + 3 5 + +Like out_value, it is possible to specify an internal policy used then +converting the values back to lua. + +:: + + void get(test_class*& obj) + { + obj = new test_class(); + } + + ... + + module(L) + [ + def("get", &get, pure_out_value(_1, adopt(_1))) + ]; + + +Discard result +-------------- + +This is a very simple policy which makes it possible to throw away +the value returned by a C++ function, instead of converting it to +lua. This example makes sure the this reference never gets converted +to lua. + +:: + + struct simple + { + simple& set_name(const std::string& n) + { + name = n; + return *this; + } + + std::string name; + }; + + ... + + module(L) + [ + class_("simple") + .def("set_name", &simple::set_name, discard_result) + ]; + +To use this policy you need to include ``luabind/discard_result_policy.hpp``. + + +Return STL iterator +------------------- + +This policy converts an STL container to a generator function that can be used +in lua to iterate over the container. It works on any container that defines +``begin()`` and ``end()`` member functions (they have to return iterators). It +can be used like this:: + + struct A + { + std::vector names; + }; + + + module(L) + [ + class_("A") + .def_readwrite("names", &A::names, return_stl_iterator) + ]; + +The lua code to iterate over the container:: + + a = A() + + for name in a.names do + print(name) + end + + +To use this policy you need to include ``luabind/iterator_policy.hpp``. + + +Yield +----- + +This policy will cause the function to always yield the current thread when +returning. See the lua manual for restrictions on yield. + + +Splitting up the registration +============================= + +a.cpp:: + + luabind::scope register_a() + { + return + class_("a") + .def("f", &a::f) + ; + } + +b.cpp:: + + luabind::scope register_b() + { + return + class_("b") + .def("g", &b::g) + ; + } + +module_ab.cpp:: + + luabind::scope register_a(); + luabind::scope register_b(); + + void register_module(lua_State* L) + { + module("b", L) + [ + register_a(), + register_b() + ]; + } + + +Configuration +============= + +There are a number of configuration options available when building luabind. +It is very important that your project has the exact same conmfiguration +options as the ones given when the library was build! The exceptions are the +``LUABIND_MAX_ARITY`` and ``LUABIND_MAX_BASES`` which are template-based +options and only matters when you use the library (which means they can +differ from the settings of the library). + +The default settings which will be used if no other settings are given +can be found in ``luabind/config.hpp``. + +If you want to change the settings of the library, you can modify the +config file. It is included and used by all makefiles. You can change paths +to lua and boost in there as well. + +LUABIND_MAX_ARITY + Controls the maximum arity of functions that are registered with luabind. + You can't register functions that takes more parameters than the number + this macro is set to. It defaults to 5, so, if your functions have greater + arity you have to redefine it. A high limit will increase compilation time. + +LUABIND_MAX_BASES + Controls the maximum number of classes one class can derive from in luabind + (the number of classes specified within bases<>). LUABIND_MAX_BASES defaults + to 4. A high limit will increase compilation time. + +LUABIND_NO_ERROR_CHECKING + If this macro is defined, all the lua code is expected only to make legal + calls. If illegal function calls are made (e.g. giving parameters that + doesn't match the function signature) they will not be detected by luabind + and the application will probably crash. Error checking could be disabled + when shipping a release build (given that no end-user has access to write + custom lua code). Note that function parameter matching will be done if a + function is overloaded, since otherwise it's impossible to know which one + was called. Functions will still be able to throw exceptions when error + checking is disabled. + + If a functions throws an exception it will be caught by luabind and + propagated with lua_error(). + +LUABIND_DONT_COPY_STRINGS + If this macro is defined, luabind will expect that all strings given to + the def() methods are static constant strings (given as string constants + for example). luabind will not copy the strings if you enable this + setting, but just keep the char pointers. + This may be especially useful for embedded systems or consoles where + heap allocations should be minimized. + +LUABIND_NO_EXCEPTIONS + This define will disable all usage of try, catch and throw in luabind. + This will in many cases disable run-time errors, when performing invalid + casts or calling lua functions that fails or returns values that cannot + be converted by the given policy. luabind requires that no function called + directly or indirectly by luabind throws an exception (throwing exceptions + through lua has undefined behavior). + + Where exceptions are the only way to get an error report from luabind, + they will be replaced with calls to the callback functions set byt + set_error_callback() and set_cast_failed_callback(). + +LUA_API + If you want to link dynamically against lua, you can set this define to + the import-keyword on your compiler and platform. On windows in devstudio + this should be __declspec(dllimport) if you want to link against lua as + a dll. + +LUABIND_EXPORT, LUABIND_IMPORT + If you want to link against luabind as a dll (in devstudio), you can + define LUABIND_EXPORT to __declspec(dllexport) and LUABIND_IMPORT to + __declspec(dllimport). Note that you have o link against lua as a dll + aswell, to make it work. + +LUABIND_TYPE_INFO, LUABIND_TYPE_INFO_EQUAL(i1,i2), LUABIND_TYPEID(t), LUABIND_INVALID_TYPE_INFO + If you don't want to use the RTTI supplied by C++ you can supply your own + type-info structure with the LUABIND_TYPE_INFO define. Your type-info + structure must be copyable and must be able to compare itself against + other type-info structures. You supply the compare function through the + LUABIND_TYPE_INFO_EQUAL() define. It should compare the two type-info + structures it is given and return true if they represent the same type and + false otherwise. You also have to supply a function to generate your + type-info structure. You do this through the LUABIND_TYPEID() define. + It should return your type-info structure and it takes a type as its + parameter. That is, a compile time parameter. LUABIND_INVALID_TYPE_INFO + macro should be defined to an invalid type. No other type should be able + to produce this type info. To use it you probably have to make a traits + class with specializations for all classes that you have type-info for. + Like this:: + + class A; + class B; + class C; + + template struct typeinfo_trait; + + template<> struct typeinfo_trait { enum { type_id = 0 }; }; + template<> struct typeinfo_trait { enum { type_id = 1 }; }; + template<> struct typeinfo_trait { enum { type_id = 2 }; }; + + If you have set up your own RTTI system like this (by using integers to + identify types) you can have luabind use it with the following defines:: + + #define LUABIND_TYPE_INFO const std::type_info* + #define LUABIND_TYPEID(t) &typeid(t) + #define LUABIND_TYPE_INFO_EQUAL(i1, i2) *i1 == *i2 + #define LUABIND_INVALID_TYPE_INFO &typeid(detail::null_type) + + Currently the type given through LUABIND_TYPE_INFO must be less-than + comparable! + +NDEBUG + This define will disable all asserts and should be defined in a release + build. + + +Implementation notes +==================== + +The classes and objects are implemented as user data in lua. To make sure that +the user data really is the internal structure it is supposed to be, we tag +their metatables. A user data who's metatable contains a boolean member named +``__luabind_classrep`` is expected to be a class exported by luabind. A user +data who's metatable contains a boolean member named ``__luabind_class`` is +expected to be an instantiation of a luabind class. + +This means that if you make your own user data and tags its metatable with the +exact same names, you can very easily fool luabind and crash the application. + +In the lua registry, luabind keeps an entry called ``__luabind_classes``. It +should not be removed or overwritten. + +In the global table, a variable called ``super`` is used every time a +constructor in a lua-class is called. This is to make it easy for that +constructor to call its base class' constructor. So, if you have a global +variable named super it may very well be overwritten. This is probably not the +best solution, and this restriction may very well be removed in the future. + +Luabind uses two upvalues for functions that it registers. The first is a +userdata containing a list of overloads for the function, the other is a light +userdata with the value 0x1337, this last value is used to identify functions +registered by luabind. It should be virtually impossible to have such a pointer +as secondary upvalue by pure chance. This means, if you are trying to replace +an existing function with a luabind function, luabind will see that the +secondary upvalue isn't the magical id number and replaces it. + +Inside the luabind namespace, there's another namespace called detail. This +namespace contains non-public classes and are not supposed to be used directly. + + +Error messages +============== + +sada + + diff --git a/doc/style.css b/doc/style.css index 41b862d..041bcf7 100644 --- a/doc/style.css +++ b/doc/style.css @@ -1,3 +1,240 @@ +.first { + margin-top: 0 } + +.last { + margin-bottom: 0 } + +a.toc-backref { + text-decoration: none ; + color: black } + +dl { + width: 70%; + margin-left: 1.0em; + font-family: Georgia, "Times New Roman", Times, serif; + font-size: 80% +} + +dd { + margin-bottom: 1.0em } + +dt { + font-weight: bold; +} + +div.abstract { + margin: 2em 5em } + +div.abstract p.topic-title { + font-weight: bold ; + text-align: center } + +div.attention, div.caution, div.danger, div.error, div.hint, +div.important, div.note, div.tip, div.warning, div.admonition { + margin: 2em ; + border: medium outset ; + padding: 1em } + +div.attention p.admonition-title, div.caution p.admonition-title, +div.danger p.admonition-title, div.error p.admonition-title, +div.warning p.admonition-title { + color: red ; + font-weight: bold ; + font-family: sans-serif } + +div.hint p.admonition-title, div.important p.admonition-title, +div.note p.admonition-title, div.tip p.admonition-title, +div.admonition p.admonition-title { + font-weight: bold ; + font-family: sans-serif } + +div.dedication { + margin: 2em 5em ; + text-align: center ; + font-style: italic } + +div.dedication p.topic-title { + font-weight: bold ; + font-style: normal } + +div.figure { + margin-left: 2em } + +div.footer, div.header { + font-size: smaller } + +div.sidebar { + border: gray 3pt solid; + padding: 10pt; + +/* margin-left: 1em ;*/ +/* border: 1 ; medium outset ; + padding: 0em 1em ;*/ + background-color: #ffffff ; + width: 30% ; + float: right ; + clear: right ; +} + +div.sidebar p { + font-family: sans-serif ; + font-size: small } + +div.sidebar p.rubric { + font-family: sans-serif ; + font-size: medium } + +div.system-messages { + margin: 5em } + +div.system-messages h1 { + color: red } + +div.system-message { + border: medium outset ; + padding: 1em } + +div.system-message p.system-message-title { + color: red ; + font-weight: bold } + +div.topic { + margin: 2em } + +h1.title { + font-size: 250%; + text-align: center } + +h2.subtitle { + text-align: center } + +hr { + width: 75% } + +ol.simple, ul.simple { + margin-bottom: 1em } + +ol.arabic { + list-style: decimal } + +ol.loweralpha { + list-style: lower-alpha } + +ol.upperalpha { + list-style: upper-alpha } + +ol.lowerroman { + list-style: lower-roman } + +ol.upperroman { + list-style: upper-roman } + +p.attribution { + text-align: right ; + margin-left: 50% } + +p.caption { + font-style: italic } + +p.credits { + font-style: italic ; + font-size: smaller } + +p.label { + white-space: nowrap } + +p.rubric { + font-weight: bold ; + font-size: larger ; + color: maroon ; + text-align: center } + +p.sidebar-title { + font-family: sans-serif ; + font-weight: bold ; + font-size: larger } + +p.sidebar-subtitle { + font-family: sans-serif ; + font-weight: bold } + +p.topic-title { + font-weight: bold } + +pre.address { + margin-bottom: 0 ; + margin-top: 0 ; + font-family: serif ; + font-size: 100% } + +pre.line-block { + font-family: serif ; + font-size: 100% } + +pre.literal-block, pre.doctest-block { + margin-left: 2em ; + margin-right: 2em ; + background-color: #eeeeee } + +span.classifier { + font-family: sans-serif ; + font-style: oblique } + +span.classifier-delimiter { + font-family: sans-serif ; + font-weight: bold } + +span.interpreted { + font-family: sans-serif } + +span.option { + white-space: nowrap } + +span.option-argument { + font-style: italic } + +span.pre { + white-space: pre } + +span.problematic { + color: red } + +table { + margin-top: 0.5em ; + margin-bottom: 0.5em } + +table.citation { + border-left: solid thin gray ; + padding-left: 0.5ex } + +table.docinfo { + margin: 2em 4em } + +table.footnote { + border-left: solid thin black ; + padding-left: 0.5ex } + +td, th { + padding-left: 0.5em ; + padding-right: 0.5em ; + vertical-align: top } + +th.docinfo-name, th.field-name { + font-weight: bold ; + text-align: left ; + white-space: nowrap } + +h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt { + font-size: 100% } + +tt { +/* background-color: #eeeeee */ + color: #102Eb0 +} + +ul.auto-toc { + list-style-type: none } + body { background-color: white; @@ -21,6 +258,18 @@ pre font-size: small } +code +{ + white-space: pre; + border: gray 1pt solid; + padding: 2pt; + + display: block; + font-family: "courier new", courier, monospace; + color: black; + font-size: small +} + tt { display: inline; @@ -43,24 +292,54 @@ ol font-family: Georgia, "Times New Roman", Times, serif } -a +a:link +{ + font-weight: bold; + color: #003366; + text-decoration: none; +} + +a:visited { font-weight: bold; color: #003366; text-decoration: none; } + table { - border: 1px solid black + border: 1px solid black; + border-collapse: collapse; } -td +table td { - border: 1px solid black + padding: 6px; +} + +table th +{ + border: 3px solid black; + padding: 6px; +} + +table.menu +{ + border-style: none; +} + +table.menu td +{ + padding-left: 15px; + padding-right: 15px; + padding-top: 7px; + padding-bottom: 7px; } -a:hover + +td { - color: #8080FF; + border: 1px solid black } + diff --git a/src/class.cpp b/src/class.cpp index b0a9dae..7d8a222 100755 --- a/src/class.cpp +++ b/src/class.cpp @@ -22,8 +22,6 @@ #include -#define LUABIND_BUILDING - #include #include diff --git a/src/class_info.cpp b/src/class_info.cpp index 2d1f52f..ae91b36 100755 --- a/src/class_info.cpp +++ b/src/class_info.cpp @@ -22,8 +22,6 @@ #include -#define LUABIND_BUILDING - #include #include diff --git a/src/class_registry.cpp b/src/class_registry.cpp index 82e0178..afd5305 100755 --- a/src/class_registry.cpp +++ b/src/class_registry.cpp @@ -22,8 +22,6 @@ #include -#define LUABIND_BUILDING - #include #include #include diff --git a/src/class_rep.cpp b/src/class_rep.cpp index f06616d..facd9e1 100755 --- a/src/class_rep.cpp +++ b/src/class_rep.cpp @@ -22,8 +22,6 @@ #include -#define LUABIND_BUILDING - #include #include diff --git a/src/create_class.cpp b/src/create_class.cpp index 599bbe3..5eecc56 100755 --- a/src/create_class.cpp +++ b/src/create_class.cpp @@ -22,8 +22,6 @@ #include -#define LUABIND_BUILDING - #include using namespace luabind::detail; diff --git a/src/find_best_match.cpp b/src/find_best_match.cpp index 2f0cf8f..b0d9963 100755 --- a/src/find_best_match.cpp +++ b/src/find_best_match.cpp @@ -22,8 +22,6 @@ #include -#define LUABIND_BUILDING - #include using namespace luabind::detail; diff --git a/src/function.cpp b/src/function.cpp index f007d1d..e783747 100755 --- a/src/function.cpp +++ b/src/function.cpp @@ -22,8 +22,6 @@ #include -#define LUABIND_BUILDING - #include #include diff --git a/src/implicit_cast.cpp b/src/implicit_cast.cpp index 7665fba..9effb5a 100755 --- a/src/implicit_cast.cpp +++ b/src/implicit_cast.cpp @@ -22,8 +22,6 @@ #include -#define LUABIND_BUILDING - #include #include diff --git a/src/object.cpp b/src/object.cpp index 6f6673c..b990873 100755 --- a/src/object.cpp +++ b/src/object.cpp @@ -22,8 +22,6 @@ #include -#define LUABIND_BUILDING - #include #include diff --git a/src/open.cpp b/src/open.cpp index 15de43b..d575ca4 100755 --- a/src/open.cpp +++ b/src/open.cpp @@ -22,8 +22,6 @@ #include -#define LUABIND_BUILDING - #include #include #include diff --git a/src/scope.cpp b/src/scope.cpp index 4c7f308..ede7a4d 100755 --- a/src/scope.cpp +++ b/src/scope.cpp @@ -22,8 +22,6 @@ #include -#define LUABIND_BUILDING - #include #include diff --git a/src/stack_content_by_name.cpp b/src/stack_content_by_name.cpp index 17b6e9e..e1956c5 100755 --- a/src/stack_content_by_name.cpp +++ b/src/stack_content_by_name.cpp @@ -22,8 +22,6 @@ #include -#define LUABIND_BUILDING - #include using namespace luabind::detail; diff --git a/test/Jamfile b/test/Jamfile index 1c75f30..a65b5e0 100755 --- a/test/Jamfile +++ b/test/Jamfile @@ -1,6 +1,7 @@ import testing ; SOURCES = + test_const.cpp test_object.cpp test_implicit_cast.cpp test_scope.cpp diff --git a/test/main.cpp b/test/main.cpp index 0ef7f87..c4af05c 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -123,6 +123,7 @@ void test_yield(); void test_construction(); void test_type_traits(); void test_implicit_cast(); +void test_const(); void test_object(); // -------------------------------------------------------------------------- @@ -150,6 +151,7 @@ test_suite* init_unit_test_suite( int argc, char* argv[] ) test->add(BOOST_TEST_CASE(&test_yield)); test->add(BOOST_TEST_CASE(&test_type_traits)); test->add(BOOST_TEST_CASE(&test_implicit_cast)); + test->add(BOOST_TEST_CASE(&test_const)); test->add(BOOST_TEST_CASE(&test_object)); return test; diff --git a/test/test_const.cpp b/test/test_const.cpp dissimilarity index 95% index fc8fe79..7bc7a08 100644 --- a/test/test_const.cpp +++ b/test/test_const.cpp @@ -1,53 +1,37 @@ -#include "test.h" - -namespace -{ - LUABIND_ANONYMOUS_FIX int feedback = 0; - - struct A - { - const A* f() { return this; } - - void g() const { feedback = 1; } - void g() { feedback = 2; } - }; - -} // anonymous namespace - -bool test_const() -{ - using namespace luabind; - - lua_State* L = lua_open(); - lua_closer c(L); - int top = lua_gettop(L); - - open(L); - - typedef void(A::*g1_t)(); - typedef void(A::*g2_t)() const; - - g1_t g1 = &A::g; - g2_t g2 = &A::g; - - module(L) - [ - class_("A") - .def(constructor<>()) - .def("f", &A::f) - .def("g", /*(void(A::*)() const) &A::g*/ g1) - .def("g", /*(void(A::*)()) &A::g*/ g2) - ]; - - if (dostring(L, "a = A()")) return false; - if (dostring(L, "a:g()")) return false; - if (feedback != 2) return false; - - if (dostring(L, "a2 = a:f()")) return false; - if (dostring(L, "a2:g()")) return false; - if (feedback != 1) return false; - - if (top != lua_gettop(L)) return false; - - return true; -} +#include "test.hpp" +#include + +namespace { + + struct A + { + const A* f() { return this; } + + int g1() const { return 1; } + int g2() { return 2; } + }; + +} // anonymous namespace + +void test_const() +{ + lua_state L; + + using namespace luabind; + + module(L) + [ + class_("A") + .def(constructor<>()) + .def("f", &A::f) + .def("g", &A::g1) + .def("g", &A::g2) + ]; + + DOSTRING(L, "a = A()"); + DOSTRING(L, "assert(a:g() == 2)"); + + DOSTRING(L, "a2 = a:f()"); + DOSTRING(L, "assert(a2:g() == 1)"); +} + diff --git a/test/test_free_functions.cpp b/test/test_free_functions.cpp dissimilarity index 93% index ce28539..86e5a3b 100644 --- a/test/test_free_functions.cpp +++ b/test/test_free_functions.cpp @@ -1,201 +1,200 @@ -#include "test.h" -#include -#include - -namespace -{ - - LUABIND_ANONYMOUS_FIX int feedback = 0; - - luabind::functor functor_test; - - void set_functor(luabind::functor f) - { - functor_test = f; - } - - struct base - { - ~base() { feedback = 99; } - - void f() - { - feedback = 5; - } - }; - - void f(int x) - { - feedback = x; - } - - void f(int x, int y) - { - feedback = x + y; - } - - int g() { feedback = 3; return 4; } - - base* create_base() - { - return new base(); - } - - void test_functor(const luabind::functor& fun) - { - feedback = fun(5); - } - - void test_value_converter(const std::string str) - { - feedback = 9; - } - - void test_pointer_converter(const char* const str) - { - feedback = 6; - } - - struct copy_me - { - }; - - void take_by_value(copy_me m) - { - } - - int function_should_never_be_called(lua_State*) - { - feedback = -1; - return 0; - } - -} // anonymous namespace - -namespace luabind { namespace converters -{ - yes_t is_user_defined(by_value); - - int convert_lua_to_cpp(lua_State* L, by_value, int index) - { - return static_cast(lua_tonumber(L, index)); - } - - int match_lua_to_cpp(lua_State* L, by_value, int index) - { - if (lua_isnumber(L, index)) return 0; else return -1; - } - - void convert_cpp_to_lua(lua_State* L, const int& v) - { - lua_pushnumber(L, v); - } - -}} - -bool test_free_functions() -{ - using namespace luabind; - { - lua_State* L = lua_open(); - lua_closer c(L); - int top = lua_gettop(L); - - open(L); - - lua_pushstring(L, "f"); - lua_pushcclosure(L, &function_should_never_be_called, 0); - lua_settable(L, LUA_GLOBALSINDEX); - - if (dostring(L, "f()")) return false; - if (feedback != -1) return false; - - module(L) - [ - class_("copy_me") - .def(constructor<>()), - - class_("base") - .def("f", &base::f), - - - def("by_value", &take_by_value), - - def("f", (void(*)(int)) &f), - def("f", (void(*)(int, int)) &f), - def("g", &g), - def("create", &create_base, adopt(return_value)), - def("test_functor", &test_functor), - def("set_functor", &set_functor) - - -#if !(BOOST_MSVC < 1300) - , - def("test_value_converter", &test_value_converter), - def("test_pointer_converter", &test_pointer_converter) -#endif - - ]; - - if (dostring(L, "e = create()")) return false; - if (dostring(L, "e:f()")) return false; - if (feedback != 5) return false; - - if (dostring(L, "f(7)")) return false; - if (feedback != 7) return false; - - if (dostring(L, "f(3, 9)")) return false; - if (feedback != 12) return false; - - if (dostring(L, "a = g()")) return false; - if (feedback != 3) return false; - lua_pushstring(L, "a"); - lua_gettable(L, LUA_GLOBALSINDEX); - if (lua_tonumber(L, -1) != 4) return false; - lua_pop(L, 1); - - if (dostring(L, "test_functor(function(x) return x * 10 end)")) return false; - if (feedback != 50) return false; - - functor test_f(L, "g"); - int a = test_f(); - if (a != 4) return false; - if (feedback != 3) return false; - if (dostring(L, "set_functor(nil)")) return false; - - if (top != lua_gettop(L)) return false; - - if (dostring(L, "function lua_create() return create() end")) return false; - - base* ptr = call_function(L, "lua_create") [ adopt(result) ]; - - delete ptr; - -#if !(BOOST_MSVC < 1300) - dostring(L, "test_value_converter('foobar')"); - if (feedback != 9) return false; - dostring(L, "test_pointer_converter('foobar')"); - if (feedback != 6) return false; -#endif - - if (!dostring2(L, "f('incorrect', 'parameters')")) return false; - std::cout << lua_tostring(L, -1) << "\n"; - lua_pop(L, 1); - - dostring(L, "function functor_test(a) glob = a\n return 'foobar'\nend"); - functor functor_test = object_cast >(get_globals(L)["functor_test"]); - - std::string str = functor_test(6)[detail::null_type()]; - if (str != "foobar") return false; - if (object_cast(get_globals(L)["glob"]) != 6) return false; - - functor functor_test2 = object_cast >(get_globals(L)["functor_test"]); - - if (functor_test != functor_test2) return false; - } - - if (feedback != 99) return false; - - return true; -} - +#include "test.h" +#include +#include + +namespace { + + LUABIND_ANONYMOUS_FIX int feedback = 0; + + luabind::functor functor_test; + + void set_functor(luabind::functor f) + { + functor_test = f; + } + + struct base + { + ~base() { feedback = 99; } + + void f() + { + feedback = 5; + } + }; + + void f(int x) + { + feedback = x; + } + + void f(int x, int y) + { + feedback = x + y; + } + + int g() { feedback = 3; return 4; } + + base* create_base() + { + return new base(); + } + + void test_functor(const luabind::functor& fun) + { + feedback = fun(5); + } + + void test_value_converter(const std::string str) + { + feedback = 9; + } + + void test_pointer_converter(const char* const str) + { + feedback = 6; + } + + struct copy_me + { + }; + + void take_by_value(copy_me m) + { + } + + int function_should_never_be_called(lua_State*) + { + feedback = -1; + return 0; + } + +} // anonymous namespace + +namespace luabind { namespace converters +{ + yes_t is_user_defined(by_value); + + int convert_lua_to_cpp(lua_State* L, by_value, int index) + { + return static_cast(lua_tonumber(L, index)); + } + + int match_lua_to_cpp(lua_State* L, by_value, int index) + { + if (lua_isnumber(L, index)) return 0; else return -1; + } + + void convert_cpp_to_lua(lua_State* L, const int& v) + { + lua_pushnumber(L, v); + } + +}} + +bool test_free_functions() +{ + using namespace luabind; + { + lua_State* L = lua_open(); + lua_closer c(L); + int top = lua_gettop(L); + + open(L); + + lua_pushstring(L, "f"); + lua_pushcclosure(L, &function_should_never_be_called, 0); + lua_settable(L, LUA_GLOBALSINDEX); + + if (dostring(L, "f()")) return false; + if (feedback != -1) return false; + + module(L) + [ + class_("copy_me") + .def(constructor<>()), + + class_("base") + .def("f", &base::f), + + + def("by_value", &take_by_value), + + def("f", (void(*)(int)) &f), + def("f", (void(*)(int, int)) &f), + def("g", &g), + def("create", &create_base, adopt(return_value)), + def("test_functor", &test_functor), + def("set_functor", &set_functor) + + +#if !(BOOST_MSVC < 1300) + , + def("test_value_converter", &test_value_converter), + def("test_pointer_converter", &test_pointer_converter) +#endif + + ]; + + if (dostring(L, "e = create()")) return false; + if (dostring(L, "e:f()")) return false; + if (feedback != 5) return false; + + if (dostring(L, "f(7)")) return false; + if (feedback != 7) return false; + + if (dostring(L, "f(3, 9)")) return false; + if (feedback != 12) return false; + + if (dostring(L, "a = g()")) return false; + if (feedback != 3) return false; + lua_pushstring(L, "a"); + lua_gettable(L, LUA_GLOBALSINDEX); + if (lua_tonumber(L, -1) != 4) return false; + lua_pop(L, 1); + + if (dostring(L, "test_functor(function(x) return x * 10 end)")) return false; + if (feedback != 50) return false; + + functor test_f(L, "g"); + int a = test_f(); + if (a != 4) return false; + if (feedback != 3) return false; + if (dostring(L, "set_functor(nil)")) return false; + + if (top != lua_gettop(L)) return false; + + if (dostring(L, "function lua_create() return create() end")) return false; + + base* ptr = call_function(L, "lua_create") [ adopt(result) ]; + + delete ptr; + +#if !(BOOST_MSVC < 1300) + dostring(L, "test_value_converter('foobar')"); + if (feedback != 9) return false; + dostring(L, "test_pointer_converter('foobar')"); + if (feedback != 6) return false; +#endif + + if (!dostring2(L, "f('incorrect', 'parameters')")) return false; + std::cout << lua_tostring(L, -1) << "\n"; + lua_pop(L, 1); + + dostring(L, "function functor_test(a) glob = a\n return 'foobar'\nend"); + functor functor_test = object_cast >(get_globals(L)["functor_test"]); + + std::string str = functor_test(6)[detail::null_type()]; + if (str != "foobar") return false; + if (object_cast(get_globals(L)["glob"]) != 6) return false; + + functor functor_test2 = object_cast >(get_globals(L)["functor_test"]); + + if (functor_test != functor_test2) return false; + } + + if (feedback != 99) return false; + + return true; +} + -- 2.11.4.GIT