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
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!
Adding AngelScript scripting to your C++ application
Posted by damianpaz in AngelScript, C++, Scripting on April 30, 2012
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!
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
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!
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!
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!