Mixing std::map and std::deque into a convenient container

This may seem a little dumb, but it gets handy when you only know the key of the elements and you are going to access them often, for example, the symbols in a scripting engine.

I called the class ‘index’, but any other name could do.

#include <iostream>
#include <string>
#include <map>
#include <deque>

using namespace std;

template<class name_type, class item_type>
class index
{
    public:
        int32_t add(const name_type& name, const item_type& value)
        {
            if ((item = indexes.find( name ))!= indexes.end())
            {
                return -1;
            }

            indexes.insert(std::make_pair(name, 0));
            item = indexes.find( name );
            names.push_back( const_cast<name_type*>(&((*item).first)) );
            items.push_back(value);
            (*item).second = items.size()-1;

            return (*item).second;
        }

        int32_t get_index(const name_type& name)
        {
            if ((item = indexes.find( name ))!= indexes.end())
            {
                return (*item).second;
            }

            return -1;
        }

        const name_type& get_name(const size_t& index)
        {
            return *names[index];
        }

        item_type& get(const size_t& index)
        {
            return items[index];
        }

        item_type& get(const name_type& name)
        {
            return get(get_index(name));
        }

        const size_t size()
        {
            return items.size();
        }

        void clear()
        {
            indexes.clear();
            names.clear();
            items.clear();
        }

    protected:
        std::map<name_type, size_t> indexes;
        std::deque<name_type*>      names;
        std::deque<item_type>       items;

        typename std::map<name_type, size_t>::iterator item;
};

How to use it:

int main()
{
    index<std::string, std::string> idx;
    idx.add("first", "This is the first element");
    idx.add("second", "This is the second element");
    idx.add("dunno", "Not sure which is the index of this one");

    std::cout << "key: " <<idx.get_name(0) << ", index: " << idx.get_index("first") << ", value: " << idx.get(0) <<std::endl;
    std::cout << "key: " <<idx.get_name(1) << ", index: " << idx.get_index("second") << ", value: " << idx.get(1) <<std::endl;
    std::cout << "key: " <<idx.get_name(2) << ", index: " << idx.get_index("dunno") << ", value: " << idx.get(2) <<std::endl;

    return 0;
}

Output:

key: first, index: 0, value: This is the first element
key: second, index: 1, value: This is the second element
key: dunno, index: 2, value: Not sure which is the index of this one

Leave a Comment

Weird segmentation faults compiling with MinGW, threads and DLLs?

You may be aware that in order to use thread exceptions safely you must compile passing the “-mthreads” option. What I didn’t know was that I also had to pass it to the linker. I realized this when I moved some code from the executable to a separate dll. I started getting segmentation faults in std containers and strings.

If you are experiencing something like this pass the

-mthreads

option to the compiler and

-mthreads

option to the linker.

In Code::Blocks go to “Settings”->“Compiler And Debugger…” menu.
Then “Compiler Settings” tab, “Other Options” sub-tab.
And write: -mthreads

Then go to the “Linker settings” tab, “Other linker options” text area and write:
-mthreads

Re compile your binaries and if that was your problem you should be ready for the next bug.

Good luck!

Leave a Comment

Adding AngelScript scripting to your C++ application

I’ve been using Lua for a while and it was nice until I started having problems with garbage collection and some strange leakage I couldn’t figure out how to solve. Thus, using all the experience I gathered from implementing Lua I jumped into the world of AngelScript and it wasn’t painful at all.

This snippet is intended for AngelScript 2.23.1. As always, you need to download the library, compile it if you must (it comes with handy project files for most IDEs) and link it to your project properly. ALSO note that the includes that lie in the “add_on” folder come with the AngelScript library source code. You must have them somewhere so you can include them properly.

As I did with Lua, I wrapped the library into classes of my own which are engine to handle general stuff, module to handle scripts specific stuff and callback to call functions declared in AngelScript script files.

These snippets are anything but complete. I can foresee them becoming bigger and bloated, so I’ll post what I got till now, so it can be easier for you to see what’s going on under the hood.

So, the engine class:

#include <string>
#include <vector>
#include <boost/smart_ptr.hpp>
#include <angelscript.h>
#include "add_on/scripthandle/scripthandle.h"
#include "add_on/scriptstdstring/scriptstdstring.h"
#include "module.h"
#include "callback.h"

class engine
{
    friend class module;
    friend class callback;

    public:

        engine()
        {
            m_engine = NULL;
            m_has_compile_errors = false;
        }

        virtual ~engine()
        {
            terminate();
            std::cout << "Engine destructor called." <<std::endl;
        }

        bool init()
        {
            if( m_engine )
            {
                return false;
            }

            int r;

            m_engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);

            // Set the message callback to print the human readable messages that the engine gives in case of errors
            r = m_engine->SetMessageCallback(asMETHOD(engine, message_callback), this, asCALL_THISCALL); assert( r >= 0 );

            // Register the string type
            RegisterStdString(m_engine);

            // Register the generic handle type, called 'ref' in the script
            RegisterScriptHandle(m_engine);

            // instance some contexts to have them at hand
            for( unsigned int n = 0; n < 10; n++ )
            {
                contexts.push_back(m_engine->CreateContext());
            }

            m_has_compile_errors = false;

            return true;
        }

        void terminate()
        {
            if( !m_engine )
            {
                return;
            }

            for( unsigned int n = 0; n < contexts.size(); n++ )
            {
                contexts[n]->Release();
            }

            m_engine->Release();

            m_engine = NULL;
        }

        // When we want a new module, we create it through here
        module_ptr new_module(const std::string& module_name = "")
        {
            return module_ptr(new module(this, module_name));
        }

        // There are many ways in AngelScript to register your classes, this is one of them
        template <class class_type>
        bool register_class(const std::string& class_name)
        {
            if (m_engine->RegisterObjectType(class_name.c_str(), sizeof(class_type), asOBJ_VALUE | asOBJ_POD)<0)
            {
                std::cout << "Error - engine::register_class(): Can't register class " + class_name <<std::endl;
                return false;
            }
            return true;
        }

        // This is how you register a C++ class method in AngelScript
        bool register_class_method(const std::string& class_name, const std::string& function_definition, const asSFuncPtr &funcPointer)
        {
            if (m_engine->RegisterObjectMethod(class_name.c_str(), function_definition.c_str(), funcPointer, asCALL_THISCALL)<0)
            {
                std::cout << "Error - engine::register_class(): Can't register class method " + class_name + "::" + function_definition <<std::endl;
                return false;
            }
            return true;
        }

    protected:
        
        // This is used for AngelScript error messages
        void message_callback(const asSMessageInfo &msg)
        {
            const char *type = "ERR ";
            if( msg.type == asMSGTYPE_WARNING )
            {
                type = "WARN";
            }
            else if( msg.type == asMSGTYPE_INFORMATION )
            {
                type = "INFO";
            }

            std::cout << msg.section << " (" << msg.row << ", " << msg.col << ") : " << type << " : " << msg.message << std::endl;

            if( msg.type == asMSGTYPE_ERROR )
            {
                m_has_compile_errors = true;
            }
        }
        
        // Contexts is what you use to call AngelScript functions and methods. They say you must pool them to avoid overhead. So I do as they say.
        asIScriptContext* new_context()
        {
            asIScriptContext *ctx = 0;
            if( contexts.size() )
            {
                ctx = *contexts.rbegin();
                contexts.pop_back();
            }
            else
            {
                ctx = m_engine->CreateContext();
            }

            return ctx;
        }
        
        // After you're done calling your AngelScript function, you get the context back into the pool for re-use
        void free_context(asIScriptContext *ctx)
        {
            contexts.push_back(ctx);
            ctx->Unprepare();
        }
        
        // This is what we will call from the callback class to execute AngelScript Functions and Methods
        int execute_call(asIScriptContext *ctx)
        {
            int r = ctx->Execute();
            if( r != asEXECUTION_FINISHED )
            {
                if( r == asEXECUTION_EXCEPTION )
                {
                    std::cout << "Exception: " << ctx->GetExceptionString() << std::endl;
                    std::cout << "Function: " << ctx->GetExceptionFunction()->GetDeclaration() << std::endl;
                    std::cout << "Line: " << ctx->GetExceptionLineNumber() << std::endl;

                    // It is possible to print more information about the location of the
                    // exception, for example the call stack, values of variables, etc if
                    // that is of interest.
                }
            }

            return r;
        }

        // This should free all scripting that lies into a specific module
        void unload_module(const std::string& module_name = "")
        {
            int r = m_engine->DiscardModule(module_name.c_str());
            if (r<0)
            {
                std::cout << "Error - engine::terminate_module(): Can't DiscardModule " + module_name <<std::endl;
            }
        }

        bool                m_has_compile_errors; // This was in the example I took the code from but serves no purpose here except for writing this comment.
        asIScriptEngine*    m_engine;             // The AngelScript engine instance
        std::vector<asIScriptContext*> contexts;  // The pool of contexts for function calling (it's used by the callback class)
};

typedef boost::shared_ptr<engine> engine_ptr; // Declare a shared pointer just in case you ever need it.

The module class. AngelScript arranges scripts into modules for scoping. Script files grouped into a module behave as a big single script.

#include <boost/smart_ptr.hpp>
#include <angelscript.h>

class engine;

class module
{
    friend class engine;

    public:
        module(engine* eng, const std::string& module = "") : m_engine(eng), m_module_name(module_name)
        {
            m_module = m_engine->m_engine->GetModule(m_module_name.c_str(), asGM_CREATE_IF_NOT_EXISTS);
        }
        
        virtual ~module() {}
        
        bool load_script(const std::string& file_path)
        {
            /*
                THE CLASS "file" IS JUST AN UTILITY CLASS THAT LOADS A FILE INTO A BUFFER AND TELLS 
                HOW BIG IT IS (AMONG OTHER STUFF). IT IS QUITE LARGE SO I'M NOT POSTING IT HERE.
            */
            *YOU MUST WRITE THE FILE LOADING YOURSELF*
            
            file script_file;
            if (!script_file.open(file_path))
            {
                std::cout << "Error - engine::load(): Can't load file " + file_path <<std::endl;
                return false;
            }

            return load_script(&script_file);
        }        
        
        bool load_script(file* script_file)
        {
            int r = m_module->AddScriptSection(script_file->file_path().string().c_str(), &script_file->buffer()[0], script_file->size());

            if( r < 0 )
            {
                std::cout << "AddScriptSection() failed" << std::endl;
                return false;
            }

            return true;
        }        

        bool build()
        {
            // Compile the script. If there are any compiler messages they will
            // be written to the message stream that we set right after creating the
            // script engine. If there are no errors, and no warnings, nothing will
            // be written to the stream.
            int r = m_module->Build();
            if( r < 0 )
            {
                std::cout << "Build() failed" << std::endl;
                return false;
            }

            return true;
        }
        
        void unload()
        {
            if (m_module)
            {
                m_engine->unload_module(m_module_name);
            }
        }


        const std::string& name()
        {
            return m_module_name;
        }

    protected:

        engine*             m_engine;
        asIScriptModule*    m_module;
        std::string         m_module_name;
};
typedef boost::shared_ptr<module> module_ptr;

The callback class:

#include <string>
#include <boost/smart_ptr.hpp>
#include <angelscript.h>

class module;
class engine;

class callback
{
    public:
        callback(engine* eng) : m_engine(eng)
        {
            m_function_id = 0;
            m_context = NULL;
            m_object_address = NULL;
        }
        
        virtual ~callback()
        {

        }

        void init(module* mod, const std::string& function_declaration)
        {
            m_module = mod;
            m_function_id = m_engine->m_engine->GetModule(m_module->name().c_str())->GetFunctionIdByDecl(function_declaration.c_str());
        }
        
        void call_begin()
        {
            assert( m_function_id > 0 );
            m_context = m_engine->new_context();
            int r = m_context->Prepare(m_function_id); assert( r >= 0 );
            if (m_object_address)
            {
                m_context->SetObject(m_object_address);
            }
        }
        
        void call_end()
        {
            m_engine->execute_call(m_context);
            m_engine->free_context(m_context);
        }

    protected:

        engine*             m_engine;
        module*             m_module;
        void*               m_object_address;
        int                 m_function_id;
        asIScriptContext*   m_context;
};
typedef boost::shared_ptr<callback> callback_ptr;

The AngelScript source code:

// main.as
void main()
{
    console con;
    con.write_line("hola mundo!");
}
// test.as
void test()
{
    console con;
    con.write_line("this comes from test!");
}

And how to use everything:

#include <iostream>
#include "engine.h"

class console
{
    public:
        void write_line(const std::string& text)
        {
            std::cout << text <<std::endl;
        }
};

int main()
{
    engine my_engine;
    my_engine.init();

    // Tell AngelScript to use the class "console" we just declared above
    my_engine.register_class<console>("console");
    my_engine.register_class_method("console", "void write_line(string &in)", asMETHOD(console, write_line));

    module_ptr my_module = engine.new_module();
    my_module->load_script("main.as");
    my_module->load_script("test.as");
    my_module->build();

    {
        callback my_callback(&engine);
        my_callback.init(my_module.get(), "void main()");
        my_callback.call_begin();
        my_callback.call_end();
    }

    {
        callback my_callback(&engine);
        my_callback.init(my_module.get(), "void test()");
        my_callback.call_begin();
        my_callback.call_end();
    }    
    return 0;
}

Output:

hola mundo!
this comes from test!
Engine destructor called.

That’s it. I hope this helps you getting started with this awesome scripting library. There is an entire forum at gamedev.net devoted to discuss this library. You may wanna check it out.

Note: The module and callback classes forward declare stuff. You must separate the declaration and the definition (.h, .cpp) in order for this to compile. Also, don’t forget to implement your own file loading routine.

Bye!

Leave a Comment

Serialize your class to a widechar XML file (with boost::serialization)

This is an old snippet I posted on gamedev.net a while back. If I remember correctly it worked fine at the time so it should still work.

#include <iostream>
#include <fstream>
#include <string>
#include <boost/archive/xml_wiarchive.hpp>
#include <boost/archive/xml_woarchive.hpp>

class user
{
    friend class boost::serialization::access;
    public:
        void set(const std::string& name, const std::string& lastname, int birthday)
        {
            m_name     = name;
            m_lastname = lastname;
            m_birthday = birthday;
        }

        std::string get_name()     { return m_name; }
        std::string get_lastname() { return m_lastname; }
        int         get_birthday() { return m_birthday; }

    private:
        std::string m_name;
        std::string m_lastname;
        int         m_birthday;

        template<class Archive>
        void serialize(Archive& ar, const unsigned int version)
        {
            ar & BOOST_SERIALIZATION_NVP(m_name)
               & BOOST_SERIALIZATION_NVP(m_lastname)
               & BOOST_SERIALIZATION_NVP(m_birthday);
        }
};
BOOST_CLASS_VERSION(user, 1)

Usage:

int main(int argc, char* argv[])
{
    // Save user
    {
        user u1;
        u1.set("Sebastián Ramón", "Perez Azaroño", 19780520);
        std::wofstream ofs("serialize.xml");
        boost::archive::xml_woarchive oa(ofs);
        oa << BOOST_SERIALIZATION_NVP(u1);
    }

    // Load user
    {
        user u2;
        std::wifstream ifs("serialize.xml");
        boost::archive::xml_wiarchive ia(ifs);
        ia >> BOOST_SERIALIZATION_NVP(u2);

        std::cout << u2.get_name() << std::endl;
        std::cout << u2.get_lastname() << std::endl;
        std::cout << u2.get_birthday() << std::endl;
    }

    return 0;
}

Output:

Sebastián Ramón
Perez Azaroño
19780520

Leave a Comment

Errors passing std::string among DLLs – GCC/MinGW32

This isn’t really a snippet but an advice to those who want to pass std::string to functions/methods lying on a dll. This also applies for classes that make use of std::string like boost::filesystem::path which might cause random break-points when debugging with gdb.

If you want to avoid runtime errors you need to use MinGW compiled with –enable-fully-dynamic-string.

One place to get it already compiled is here:


http://code.google.com/p/mingw-builds/downloads/detail?name=mingw32-gcc-4.6.1-release-20110830.7z

Good Luck!

Leave a Comment

Avoid application freezing when doing multithreading on win32

I’ve been experiencing difficulties when rendering a window on a different thread (Windows 7). The application wouldn’t stop getting ghosted (not responding).

I found out that just calling:

    MSG		msg;
    if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

in each thread loop that is using too much cpu time solves the problem.

Hope that helps!

Leave a Comment

Adding Lua scripting to C++ with SWIG

For this you need to download the following libraries:

- lua 5.1.4
- swig 2.0.2

You need to add the directory where you installed swig to your PATH environment variable and link your project to the lua library.

Then you’ll have to add this pre-build step in your project’s build options. If you use Code::Blocks it should be done like this:

cmd /c "swig -c++ -lua mylua.i"

That command will take your interface file “mylua.i” and generate a file called “mylua_wrap.cxx” that you should add to your project so it will get compiled along with your own code.

The following header file declares the script class to load a Lua script, the callback class to call a function declared in your Lua script, the myclass class that is the class that we are going to access from the Lua script and a function get_myclass() that will return a pointer to the instance of myclass defined in c++.

The line “extern int luaopen_mylua(lua_State* L);” is a function that swig generates based on the name we gave to the module declared in the interface file. (.i)

// File: myclass.h

extern "C" {
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
extern int luaopen_mylua(lua_State* L);
}
#include <iostream>
#include <string>
#include <boost/smart_ptr.hpp>

// Forward declaration of class callback
class callback;
// Helper class to load a Lua script
class script
{
    friend class callback;
    public:
        bool init()
        {
            // Initialize lua
            L = lua_open();
            luaL_openlibs(L);
            luaopen_mylua(L);	// load the wrappered module
            return true;
        }

        bool load(const std::string& file_path)
        {
            // Load script
            int s = luaL_loadfile(L, file_path.c_str());

            // execute Lua program
            if ( s==0 )
            {
                s=lua_pcall(L, 0, LUA_MULTRET, 0);

                if (s!=0)
                {
                    report_errors(L);
                    return false;
                }
            }
            else
            {
                report_errors(L);
                return false;
            }

            return true;
        }

        void close()
        {
            std::cout << "Calling lua_close... ";
            lua_close(L);
            std::cout << "done." <<std::endl;
        }

    protected:
        void report_errors(lua_State *L)
        {
            std::cout << "-- " << lua_tostring(L, -1) << std::endl;
            lua_pop(L, 1); // remove error message
        }

        lua_State *L;
};
typedef boost::shared_ptr<script> script_ptr;
// Helper class to call a function declared in a Lua script
class callback
{
    public:
        callback():r_obj(0), r_func(0), L(NULL), num_params(0), num_return(0) {}

        void init(script_ptr& s, const std::string& func, int n_params=0, int n_ret=0)
        {
            L = s->L;
            num_params = n_params;
            num_return = n_ret;

            lua_getglobal(L, func.c_str());    // Get the function
            r_func = luaL_ref(L, LUA_REGISTRYINDEX);
            if ( (LUA_REFNIL == r_func) || (LUA_NOREF == r_func) )
                r_func = 0;

            lua_pop(L, 1);
        }

        virtual ~callback()
        {
            if (r_obj) luaL_unref(L, LUA_REGISTRYINDEX, r_obj);
            if (r_func) luaL_unref(L, LUA_REGISTRYINDEX, r_func);
        }

        void call()
        {
            call_begin();
            call_end();
        }

        void call_begin()
        {
            if (!r_func) return;
            lua_rawgeti(L, LUA_REGISTRYINDEX, r_func);
        }

        void call_end()
        {
            if( lua_pcall(L,num_params,num_return,0) != 0)
            {
                report_errors();
            }
        }

        void set_parameter(const int32_t& val) {lua_pushnumber(L, val);}
        void set_parameter(const std::string& val) {lua_pushstring(L, val.c_str());}

    protected:
        void report_errors()
        {
            std::cout << "-- " << lua_tostring(L, -1) << std::endl;
            lua_pop(L, 1); // remove error message
        }

        int r_obj;
        int r_func;
        lua_State *L;
        int num_params;
        int num_return;
};
// Class that we are going to access from the Lua script
class myclass
{
    public:
        void init()
        {
            my_script = script_ptr(new script());
            my_script->init();
            my_script->load("main.lua");
        }

        void print(const std::string& text)
        {
            std::cout << "std::cout: " << text <<std::endl;
        }

        void call_lua_function(const std::string& function_name)
        {
            lua_function.init(my_script, function_name, 1);
        }

        script_ptr    my_script;
        callback      lua_function;
};
// Function that give us a pointer to the myclass instance. It's defined in main.cpp
myclass* get_myclass();

The following is the interface file swig needs to generate proper c++ code. Remember that you must execute “swig -c++ -lua mylua.i” in order to get the file “mylua_wrap.cxx” generated. Note the line “%module mylua”. It declares the namespace all your c++ code exported through this interface will lie into from your Lua script.

// File: mylua.i

%module mylua
%{
#include "myclass.h"
%}
%include <std_string.i>
%include <typemaps.i>

namespace boost
{
    template<class T>
    class shared_ptr
    {
        public:
            T *     operator-> () const;
            void    reset();
            T *     get() const;
    };
}

typedef int          int32_t;
typedef unsigned int uint32_t;

%include "myclass.h"

This is the Lua script we are going to load from c++. Note that we call c++ code from the mylua namespace.

-- File: main.lua

myclass = mylua.get_myclass()           -- Get the instance of myclass

function show_text(text)                -- Declare a function to print stuff
    print("lua function:"..text)
end

myclass:call_lua_function("show_text")  -- Init c++ callback to a lua function

myclass:print("calling c++ function")   -- Call a myclass methods declared in c++

Finally in main.cpp we include myclass.h and define the get_myclass function, we declare a global instance of myclass, we intialize it and call a lua function with one parameter:

// File: main.cpp

#include "myclass.h"

myclass my_class_instance; // global instance of myclass

myclass* get_myclass()  // Definition of get_myclass declared in myclass.h
{
    return &my_class_instance;
}

int main()
{
    my_class_instance.init();
    my_class_instance.lua_function.call_begin();
    my_class_instance.lua_function.set_parameter("Calling Lua Function");
    my_class_instance.lua_function.call_end();

    return 0;
}

Output:

std::cout: calling c++ function
lua function:Calling Lua Function

So, it looks complicated at first, but once you have your interface file properly declared and the resulting .cxx file added to your project, accesing your c++ objects from Lua is really easy.

The c++ project should only include these files:
main.cpp
myclass.h
mylua_wrap.cxx

The file main.lua is where the Lua code should lie in and will get loaded from myclass.
The file mylua.i is needed only by swig.exe.

Have fun!

Leave a Comment

Follow

Get every new post delivered to your Inbox.