#include "Channel.h"
#include "Group.h"
#include <string>
#include <iostream>
#include <iomanip>
int main() {
// successfully create
auto a = GroupFactory::create("alsa-source", "source1", 0, 2);
// wrong number of arguments: return nullptr
auto s = GroupFactory::create("square-source", "source2", 2, 2);
// wrong argument type ("foo" is const char*, not std::string): return nullptr
auto s2 = GroupFactory::create("square-source", "source2", 2, 2, "foo");
// successfully create
auto s3 = GroupFactory::create("square-source", "source2", 2, 2, std::string("bar"));
std::cout << std::boolalpha << (a != nullptr) << std::endl;
std::cout << std::boolalpha << (s != nullptr) << std::endl;
std::cout << std::boolalpha << (s2 != nullptr) << std::endl;
std::cout << std::boolalpha << (s3 != nullptr) << std::endl;
Channel c(10, 768);
c.add_handler(a);
c.add_handler(s3);
c.handle();
return 0;
}
#ifndef FACTORY_CHANNEL_H
#define FACTORY_CHANNEL_H
#include <vector>
#include "Group.h"
class Channel {
protected:
std::vector<Group *> handlers;
public:
int samples_in_frame;
int frames_in_period;
int32_t *buff;
Channel(int channels, int bsize);
virtual ~Channel();
inline int32_t get(int f, int s) const {
return buff[f*samples_in_frame+s];
}
inline void set(int f, int s, const int32_t v) const {
buff[f*samples_in_frame+s] = v;
}
bool add_handler(Group * group);
bool handle();
};
#endif //FACTORY_CHANNEL_H
#include "Channel.h"
Channel::Channel(int channels, int bsize)
: samples_in_frame(channels)
, frames_in_period(bsize)
, buff(new int32_t[channels*bsize])
{}
Channel::~Channel() {
delete[] buff;
for (auto handler : handlers)
delete handler;
}
bool Channel::add_handler(Group * group) {
handlers.push_back(group);
return true;
}
bool Channel::handle() {
bool res = true;
for (auto &group : handlers) {
if (!group->handler(*this))
res = false;
}
return res;
}
#ifndef FACTORY_GROUP_H
#define FACTORY_GROUP_H
#include <string>
#include <unordered_map>
#include <vector>
class Channel;
class Group {
protected:
std::string name;
int offset_in_buffer;
int samples_in_frame;
bool is_enabled;
bool is_source;
public:
Group(const char *name, int offset, int width)
: name(name), offset_in_buffer(offset), samples_in_frame(width), is_enabled(true), is_source(false)
{}
virtual ~Group() = default;
virtual bool handler(Channel &channel) = 0;
virtual void enable(bool ok) { is_enabled = ok; }
virtual std::string get_type() const = 0;
};
template <typename Derived, typename... CtorArgs>
class GroupRegistry : public Group {
static bool dummy;
template <typename T, T>
struct dummy_value {};
typedef dummy_value<bool &, dummy>
dummy_value_type; // force dummy to get evaluated*/
public:
GroupRegistry(const char *name, int offset, int width) : Group(name, offset, width) {}
std::string get_type() const override { return Derived::type(); }
};
class GroupFactory {
// note: there will be a different std::unordered_map for each different combination of Args
template<typename... Args>
static std::unordered_map<std::string, Group*(*)(Args...)> &get_factories() {
static std::unordered_map<std::string, Group*(*)(Args...)> factories;
return factories;
}
public:
template<class Derived, typename... Args>
static bool registerType() {
auto &factories = get_factories<Args...>();
factories.template emplace(Derived::type(), [](Args... args) {
return static_cast<Group*>(new Derived(std::forward<Args>(args)...));
});
return true;
}
// note: will return nullptr if `type` wasn't registered OR the arguments are the wrong type
template<typename... Args>
static Group *create(const std::string &type, Args&&... args) {
auto &factories = get_factories<std::decay_t<Args>...>();
auto it = factories.find(type);
return (it != factories.end()) ? it->second(std::forward<Args>(args)...) : nullptr;
}
};
template <typename Derived, typename... CtorArgs>
bool GroupRegistry<Derived, CtorArgs...>::dummy = GroupFactory::registerType<Derived, CtorArgs...>();
#endif //FACTORY_GROUP_H
#include <iostream>
#include "Group.h"
class ALSA_source : public GroupRegistry<ALSA_source, const char *, int, int> {
public:
using GroupRegistry<ALSA_source, const char *, int, int>::GroupRegistry;
static const char* type() { return "alsa-source"; }
bool handler(Channel &channel) override {
std::cout << "type is: " << type() << std::endl;
return true;
}
};
class Square_source : public GroupRegistry<Square_source, const char *, int, int, std::string> { // additional argument
public:
Square_source(const char *name, int offset, int width, std::string foo)
: GroupRegistry<Square_source, const char *, int, int, std::string>(name, offset, width),
foo(foo) {}
static const char* type() { return "square-source"; }
bool handler(Channel &channel) override {
std::cout << "type is: " << type() << std::endl;
return true;
}
std:: string foo;
};
class ALSA_sink : public GroupRegistry<ALSA_sink, const char *, int, int> {
public:
using GroupRegistry<ALSA_sink, const char *, int, int>::GroupRegistry;
static const char* type() { return "alsa-sink"; }
bool handler(Channel &channel) override {
std::cout << "type is: " << type() << std::endl;
return true;
}
};