event system optimization - c++

If I have these declarations and definitions:
enum Events
{
INIT,
RENDER
};
struct EventBase
{
typedef void (EventBase::*event_callback_type)();
~EventBase() {}
virtual void init() { assert(0); }
virtual void render() { assert(0); }
};
template <enum Events>
struct EventTraits
{
static EventBase::event_callback_type const event_callback;
};
// in a .cpp file
template <>
EventBase::event_callback_type const
EventTraits<INIT>::event_callback(
&EventBase::init);
template <>
EventBase::event_callback_type const
EventTraits<RENDER>::event_callback(
&EventBase::render);
// in another class *i are pointers to objects that inherit EventBase
template <enum Events event>
inline void EventNotifier::notify()
{
for (events_type::const_iterator i(event_handlers[event].begin());
i != event_handlers[event].begin() + num_event_handlers[event];
++i)
{
((*i)->*EventTraits<event>::event_callback)();
if ((*i)->num_event_handlers[event])
{
(*i)->notify<event>();
}
// else do nothing
}
}
Say, that the event RENDER needs fastest possible handling, do you think it is worthwhile to do a member template specialization:
template <>
inline void EventNotifier::notify<RENDER>()
{
for (events_type::const_iterator i(event_handlers[RENDER].begin());
i != event_handlers[RENDER].begin() + num_event_handlers[RENDER];
++i)
{
(*i)->render();
if ((*i)->num_event_handlers[RENDER])
{
(*i)->notify<RENDER>();
}
// else do nothing
}
}
This would not require the fetching of a static pointer to a member function. Or perhaps I should do this:
template <enum Events>
struct EventTraits
{
static EventBase::event_callback_type event_callback();
};
And specialize the struct template?

Just additional 5 cents. EventNotifier::notify() looks completely thread-unsafe. Futhermore, if any event handler generates new event bad things can happen. I suggest doing notification this way (C++ 11, just don't know all of your types):
template <> inline void EventNotifier::notify<RENDER>()
{
decltype(event_handlers[RENDER]) local;
decltype(num_event_handlers[RENDER]) local_num;
{
std::lock_guard<std::mutex> guard(my_mutex);
local = event_handlers[RENDER];
local_num = num_event_handlers[RENDER];
}
for (events_type::const_iterator i(local.begin()); i != local.begin() + local_num; ++i)
{
(*i)->render();
if ((*i)->num_event_handlers[RENDER]) (*i)->notify<RENDER>();
}
}

The member specialisation won't make any difference in it's current form as the code you have written in identical to the code the compiler will generate for you.
Here's a small improvement:
template <enum Events event>
inline void EventNotifier::notify()
{
for (events_type::const_iterator i(event_handlers[event].begin()),
end (event_handlers[event].begin() + num_event_handlers[event]);
i != end; ++i)
{
((*i)->*EventTraits<event>::event_callback)();
if ((*i)->num_event_handlers[event])
{
(*i)->notify<event>();
}
// else do nothing
}
}

Related

Variadic template class containing array of another template class

I'm creating my own RDBMS to practice C++. I came up with a solution where each column can have a type and is a template. This is what a row looks like, but it doesn't work
template <typename... col_types>
struct row {
row(std::tuple<std::function<bool(col_types)>, bool, col_types>...col_data){
int i = 0;
([&]{
columns[i] = std::make_unique<column_impl<decltype(std::get<2>(col_data))>>(std::get<0>(col_data), std::get<1>(col_data), std::get<2>(col_data));
i++;
}(), ...);
}
std::array<std::unique_ptr<column_impl<col_types>>, sizeof...(col_types)> columns;
};
And here is a column_impl
template <typename data_t>
struct column_impl {
column_impl<data_t>() {}
column_impl<data_t>(std::function<bool(data_t)> _constraint) : constraint(_constraint) {}
column_impl<data_t>(std::function<bool(data_t)> _constraint, bool _is_nullable)
: constraint(_constraint), is_nullable(_is_nullable) {}
// This constructor requires to validate whether provided data
// satisfies provided constraint. If constraint isn't satisfied
// an exception gets thrown. It needs to be handled
column_impl<data_t>(std::function<bool(data_t)> _constraint, bool _is_nullable, data_t _value)
: constraint(_constraint), is_nullable(_is_nullable) {
if (validate_data()) {
value = _value;
} else {
throw std::invalid_argument("Provived data couldn't satisfy column's constraint");
}
}
std::function<bool(data_t)> constraint = [](data_t) { return true; };
bool is_nullable = false;
data_t value;
auto get_column_type_variant() { return std::variant<data_t>(); }
bool validate_data() { return constraint(value); }
template <typename T>
bool validate_type(T) {
return std::is_nothrow_convertible<T, data_t>();
}
};
Any ideas how to create a container for columns inside of a row and create a constructor that unpacks tuples into a row? I can't get it working. I know this array is not supposed to work, but I have no idea how to write it better. And also I don't want a vector. I could write a polymorphic wrapper like
struct column{some_type_containing_column_impls column_obj;},
but I have no idea how to do it.
And how to properly unpack those tuples into column_impl obj?
Using only non-type template arguments can do the thing.
template<class T>
bool default_constraint(T) {
return true;
}
template<class T, bool nullable = true, bool(constraint)(T) = default_constraint>
class column {
T data;
bool is_null;
public:
column() : data(), is_null(true) { ///< T must be DefaultConstructable
if (!validate())
throw std::invalid_argument("Provided data couldn't satisfy column's constraint");
}
column(T data) : data(data), is_null(false) {
if (!validate())
throw std::invalid_argument("Provided data couldn't satisfy column's constraint");
}
bool validate() {
return nullable || is_null || constraint(data);
}
T get() {
return data;
}
};
template<class... C>
struct row {
std::tuple<C...> columns;
row(C&&... c) : columns(std::forward<C>(c)...) {}
template<int index>
auto get() {
return std::get<index>(columns).get();
}
};
bool require_positive(int i) {
return i >= 0;
}
int main() {
typedef row<column<int>, column<float>, column<bool>> MyRow;
MyRow r{1, 2.3f, true};
using MyRow2 = row<column<int, false, require_positive>, column<float>>;
MyRow2 r2{-1, 2.5}; ///< exception thrown
}
I know maybe you only want the "idea" of how to implement, but I just post the code here for clarity.

In C++, how can one map between enum values and data types, so the types can be used in templates?

How can one do this, which is obviously impossible C++, in real C++?:
Type decodeUiEnum(UiEnum myEnum) { // impossible: cannot return a data type
// one switch statement to rule them all
switch(myEnum) {
case USER_SELECTED_GREYSCALE: return GreyscalePixel;
case USER_SELECTED_RGB: return RgbPixel;
...
}
}
void doSomeGraphicsMagic1(UiEnum myEnum) {
...
Foo<decodeUiEnum(myEnum)> a(...); // impossible: type not available at compile
// time
...
}
void doSomeGraphicsMagic2(UiEnum myEnum, int blah) {
...
Bar<int, decodeUiEnum(myEnum)> b(...); // impossible
...
}
and the like, so you can just add new types to the top switch statement and not have to modify the other code below it, so long as that code is suitably generic of course? As otherwise, you would need a switch statement within each function to do the necessary type mapping into the templates, which is not as much maintainable code, and lots of duplication. So more generally - if this is approaching it the wrong way, how do we fulfill that intended property of the code?
That is, what I want to do is, in a function taking an enum as parameter, instantiate a template type where the template parameter depends on the enum, without having a switch-on-enum in every function.
Yes it is actually possible.
Trick is based on partial template specification, this approach used by std::get
For example:
#include <iostream>
// specify an enumeration we will use as type index and related data types
enum class UiEnum {
GRAY_SCALE,
RGB_PIXEL
};
struct GreyscalePixel;
struct RgbPixel;
// make base template class
template<UiEnum _EV>
struct ui_enum_type {
};
// do partial type specification trick
// insert typedefs with data type we need for each enumeration value
template<>
struct ui_enum_type<UiEnum::GRAY_SCALE> {
typedef GreyscalePixel pixel_type;
};
template<>
struct ui_enum_type<UiEnum::RGB_PIXEL> {
typedef RgbPixel pixel_type;
};
// demo classes to demonstrate how trick is working at runtime
template<typename T>
struct demo_class {
};
template <>
struct demo_class<GreyscalePixel> {
demo_class()
{
std::cout << "GreyscalePixel" << std::endl;
}
};
template <>
struct demo_class<RgbPixel> {
demo_class()
{
std::cout << "RgbPixel" << std::endl;
}
};
// use swithc trick
static void swich_trick(std::size_t runtimeValue)
{
switch( static_cast<UiEnum>(runtimeValue) ) {
case UiEnum::GRAY_SCALE: {
demo_class< ui_enum_type<UiEnum::GRAY_SCALE>::pixel_type > demo1;
}
break;
case UiEnum::RGB_PIXEL: {
demo_class< ui_enum_type<UiEnum::RGB_PIXEL>::pixel_type > demo2;
}
break;
}
}
int main(int argc, const char** argv)
{
// Do runtime based on the trick, use enum instead of data type
for(std::size_t i=0; i < 2; i++) {
swich_trick(i);
}
return 0;
}
In any case my suggestion - use classic polymorphism instead of template meta-programming over complication. Most modern compilers doing de-virtualization during optimization. For example:
#include <iostream>
#include <memory>
#include <unordered_map>
enum class UiEnum {
GRAY_SCALE,
RGB_PIXEL
};
class GraphicsMagic {
GraphicsMagic(const GraphicsMagic&) = delete;
GraphicsMagic& operator=(const GraphicsMagic&) = delete;
protected:
GraphicsMagic() = default;
public:
virtual ~GraphicsMagic( ) = default;
virtual void doSome() = 0;
};
class GreyscaleGraphicsMagic final: public GraphicsMagic {
public:
GreyscaleGraphicsMagic():
GraphicsMagic()
{
}
virtual void doSome() override
{
std::cout << "GreyscalePixel" << std::endl;
}
};
class RgbGraphicsMagic final: public GraphicsMagic {
public:
RgbGraphicsMagic():
GraphicsMagic()
{
}
virtual void doSome() override
{
std::cout << "RgbPixel" << std::endl;
}
};
int main(int argc, const char** argv)
{
std::unordered_map< UiEnum, std::shared_ptr< GraphicsMagic > > handlers;
handlers.emplace(UiEnum::GRAY_SCALE, new GreyscaleGraphicsMagic() ) ;
handlers.emplace(UiEnum::RGB_PIXEL, new RgbGraphicsMagic() );
for(std::size_t i=0; i < 2; i++) {
handlers.at( static_cast<UiEnum>(i) )->doSome();
}
return 0;
}
You could use std::variant, and then have consuming code std::visit that variant.
First we want a template for "pass a type as a parameter"
template <typename T>
struct tag {
using type = T;
};
Then we define our variant and the factory for it.
using PixelType = std::variant<tag<GreyscalePixel>, tag<RgbPixel>>;
PixelType decodeUiEnum(UiEnum myEnum) {
switch(myEnum) {
case USER_SELECTED_GREYSCALE: return tag<GreyscalePixel>{};
case USER_SELECTED_RGB: return tag<RgbPixel>{};
...
}
}
Now our methods can be written as visitors over PixelType
void doSomeGraphicsMagic1(UiEnum myEnum) {
std::visit([](auto t){
using Pixel = decltype(t)::type;
Foo<Pixel> a(...);
}, decodeUiEnum(myEnum));
}
int doSomeGraphicsMagic2(UiEnum myEnum, int blah) {
return std::visit([blah](auto t){
using Pixel = decltype(t)::type;
Bar<int, Pixel> a(...);
return a.frob();
}, decodeUiEnum(myEnum));
}

C++ Vector of template class, Polymorphism

Every time that I create a object, I store the pointer of that object in a vector, which is a static member of the class of the object, in order to monitor its state, something like this:
class A {
private:
static std::vector<A *> as;
STATE state = NONE; //<- enum
void doSomething();
public:
A() {
as.push_back(this);
}
static void monitor() {
auto end = as.end();
for (auto obj = as.begin(); obj != end; obj++) {
switch ((*obj)->state) {
//process it
(*obj)->doSomething();
}
}
}
}
//// recurrent call in other part of the program or even in other thread
A::monitor();
The above code is obviously incomplete, lacks an appropriately destructor, to remove the pointer of the vector that is being deleted.
the problem now is that I have to do the same with a template class
template <typename T>
class A {
void doSomething(); //<--independent, no template
....
}
Is there any way to do the same?, applying the independent type method "doSomething()" for every object?
If the function "doSomething()" was dependent type, there would be a way to accomplish the same?
You can do the same:
template <typename T>
class A {
private:
static std::vector<A<T>*> as;
STATE state = NONE; //<- enum
void doSomething()
public:
A() { as.push_back(this); }
static void monitor() {
auto end = as.end();
for (auto obj = as.begin(); obj != end; obj++) {
switch ((*obj)->state) {
//process it
(*obj)->doSomething();
}
}
}
}
template <typename T>
std::vector<A<T>*> as;
You just have to call
A<MyType>::monitor();

Storage of function pointer in polymorphic class without explicit template specialization

I am trying to create a helper class to abstract invoking function pointers. With feedback from others on SO, I am using a polymorphic class to achieve this (shown below). Templates are also used to reduce code duplication.
typedef void(*PFNFOO1) (int);
typedef void(*PFNFOO2) (double);
typedef void(*PFNBAR1) (long);
typedef void(*PFNBAR2) (float);
typedef struct FOO_TABLE
{
PFNFOO1 pfnFoo1;
PFNFOO2 pfnFoo2;
} FOO_TABLE;
typedef struct BAR_TABLE
{
PFNBAR1 pfnBar1;
PFNBAR2 pfnBar2;
} BAR_TABLE;
enum TABLE_TYPE
{
TYPE_FOO = 0,
TYPE_BAR = 1,
};
template <typename T>
class FooBarImpl : public FooBarBase
{
public:
// GetFunc is created to centralize needed validation before function is invoked
void* GetFunc(size_t funcOffset)
{
// do some validation
return reinterpret_cast<void*>(m_FooBarTable + funcOffset);
}
void* GetpfnFoo1() { return GetFunc(offsetof(T, pfnFoo1)); }
void* GetpfnFoo2() { return GetFunc(offsetof(T, pfnFoo2)); }
void* GetpfnBar1() { return GetFunc(offsetof(T, pfnBar1)); }
void* GetpfnBar2() { return GetFunc(offsetof(T, pfnBar2)); }
T* m_FooBarTable;
};
class FooBarBase
{
public:
static FooBarBase* CreateFooBar(TABLE_TYPE tableType)
{
switch(tableType)
{
case (TYPE_FOO) :
{
return new FooBarImpl<FOO_TABLE>();
}
break;
case (TYPE_BAR) :
{
return new FooBarImpl<BAR_TABLE>();
}
break;
}
}
virtual void* GetpfnFoo1() = 0;
virtual void* GetpfnFoo2() = 0;
virtual void* GetpfnBar1() = 0;
virtual void* GetpfnBar2() = 0;
};
int _tmain(int argc, _TCHAR* argv[])
{
{
FooBarBase *pFooBar = FooBarBase::CreateFooBar(TYPE_FOO);
// Initialize Foo table
auto p = reinterpret_cast<PFNFOO1>(pFooBar->GetpfnFoo1());
int parameter = 1;
p(parameter);
}
{
FooBarBase *pFooBar = FooBarBase::CreateFooBar(TYPE_FOO);
// Initialize Bar table
auto p = reinterpret_cast<PFNBAR2>(pFooBar->GetpfnBar2());
float parameter = 1.0f;
p(parameter);
}
return 0;
}
This is currently giving me complication errors as "C2039: 'pfnBar1' : is not a member of 'FOO_TABLE'" which makes sense because one of the implicit template specialization will try to do "offsetof(FOO_TABLE, pfnBar1)," which isn't allowed. I have two questions. First, I am wondering what's the best way to address this error. I think I can possibly address this by providing explicit template specializations for FooBarImpl and FooBarImpl, but I'd like to avoid doing that because it means that if I were to add a new table type later, I'd have to add another specialization. Also, it increases code duplication. Therefore, if there's a way to fix this issue without explicit template specialization, please let m know.
For my second question, if explicit template specialization cannot be avoided, I have also tried this:
class FooBarBase;
template <typename T>
class FooBarImpl : public FooBarBase
{
};
template <>
class FooBarImpl<FOO_TABLE> : public FooBarBase
{
public:
typedef FOO_TABLE T;
// GetFunc is created to centralize needed validation before function is invoked
void* GetFunc(size_t funcOffset)
{
// do some validation
return reinterpret_cast<void*>(m_FooBarTable + funcOffset);
}
void* GetpfnFoo1() { return GetFunc(offsetof(T, pfnFoo1)); }
void* GetpfnFoo2() { return GetFunc(offsetof(T, pfnFoo2)); }
T* m_FooBarTable;
};
template<>
class FooBarImpl<BAR_TABLE> : public FooBarBase
{
public:
typedef BAR_TABLE T;
// GetFunc is created to centralize needed validation before function is invoked
void* GetFunc(size_t funcOffset)
{
// do some validation
return reinterpret_cast<void*>(m_FooBarTable + funcOffset);
}
void* GetpfnBar1() { return GetFunc(offsetof(T, pfnBar1)); }
void* GetpfnBar2() { return GetFunc(offsetof(T, pfnBar2)); }
T* m_FooBarTable;
};
But for some reason, I keep getting this error "error C2504: 'FooBarBase' : base class undefined" even if it was working fine before I specialized the templates.
If anyone has ideas about these 2 questions, I'd really appreciate your feedback. Thanks.

Macro to return the 'this' pointer, or NULL when it's not available

Is it possible to access the this pointer in non-static context and use something else in static context automatically? Do you know any macro or template magic?
#define LOG std::cout << _is_the_this_pointer_available_ ? this : 0
class Foo {
void test() {
LOG;
}
};
void staticTest() {
LOG;
}
Do you know any macro or template magic?
Honestly, I wouldn't do this with a macro. When something can be done without macros, I'd suggest to prefer avoiding them. Here is a possible solution based on overloading, CRTP, and inheritance (no macros):
int get_this() { return 0; }
template<typename T>
struct get_this_helper
{
T* get_this() { return static_cast<T*>(this); }
};
The only overhead is that you have to make your classes derive from the proper specialization of get_this_helper<>, as shown below:
#include <iostream>
#define LOG std::cout << get_this() << std::endl;
class Foo : public get_this_helper<Foo> {
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// This is the only thing that requires
// being changed wrt your version of Foo
public:
void test() {
LOG;
}
};
void staticTest() {
LOG;
}
Here is a simple test program:
int main()
{
Foo f;
f.test();
staticTest();
}
And a live example.
I am using the following technique to write this pointer to a log:
#define GET_THIS() __if_exists(this) { this; } __if_not_exists(this) { nullptr; }
However it is Microsoft specific.
#define LOG std::cout << isThisAvailable()
bool isThisAvailable() { return false; }
struct X
{
bool isThisAvailable() { return true; }
void test() { LOG; }
};
void staticTest()
{
LOG;
}
Calling isThisAvailable inside the class will return true. Calling outside the class context will call the free function and return false.