Skip to content

makiolo/design-patterns-cpp14

Repository files navigation

Design patterns C 14

gcc 4.9 / clang 3.6: Build Status

MSVC 2015: Build status

Quality: Codacy Badge codecov

This is a header-only library with some of the most common design patterns implemmented in C 11/14.

Design guidelines in design-patterns-cpp14

  • Can assume variadic templates supported by your compiler.
  • Use perfect forwarding and new features from C 11/14 when possible.
  • Prefer header only code, but it is not a must.
  • Allocations and deallocations of memory are centralized in a allocator selectable by client. (TODO: now allocator is FSBAllocator, and require some change.)

Quality assurance

  • Code tested in travis on gcc (4.7, 4.8, 4.9), clang (3.3, 3.4 and 3.6) and Visual Studio (2013).
  • Test cases relationated with problems crossing boundaries of dynamic libraries.
  • Side dark is optional (no macros, no singletons).

License

Licencia de Creative Commons
design-patterns-cpp14 by Ricardo Marmolejo García is licensed under a Creative Commons Reconocimiento 4.0 Internacional License.

Contributing

The source for design-patterns-cpp14 is held at design-patterns-cpp14 github.com site.

To report an issue, use the design-patterns-cpp14 issue tracker at github.com.

Using design-patterns-cpp14

Compile design-patterns-cpp14

It's a header-only library. Only need an include.

Compile tests

You will need cmake, npm and conan (and a compiler).

$ git clone https://github.com/makiolo/design-patterns-cpp14.git
$ cd design-patterns-cpp14
$ npm install

Naming implementations

  • option 1: use DEFINE_KEY(classname or anything) within the class
  • option 2: use DEFINE_HASH(classname well qualified) outside of class
  • option 3: specialization of std::hash. This is equivalent to option 2 but without use macros:
namespace std {
	template <>
	struct hash<MyClass>
	{
		size_t operator()() const
		{
			return std::hash<std::string>()("MyClass");
		}
	};
}

Example factory

#include <iostream>
#include <assert.h>
#include <dp14/factory.h>

class Base
{
public:
	using factory = dp14::factory<Base, std::string, int>;

	explicit Base(const std::string& name, int q)
		: _name(name)
		, _q(q)
	{
		std::cout << "constructor " << _name << " - " << _q << std::endl;
	}
	virtual ~Base() { std::cout << "destruction" << std::endl; }

protected:
	std::string _name;
	int _q;
};

class A : public Base
{
public:
	DEFINE_KEY(A)
	explicit A(const std::string& name, int q) : Base(name, q) { ; }
	virtual ~A() = default;
};
DEFINE_HASH(A)

// if you dont like macro DEFINE_KEY(class), can use this:
class B : public Base
{
public:
	explicit B(const std::string& name, int q) : Base(name, q) { ; }
	virtual ~B() = default;
};

namespace std {
	template <>
	struct hash<B>
	{
		size_t operator()() const
		{
			return std::hash<std::string>()("B");
		}
	};
}

int main()
{
	Base::factory factory;
	Base::factory::registrator<A> reg1(factory);
	Base::factory::registrator<B> reg2(factory);

	{
		// equivalent ways of create A
		std::shared_ptr<Base> a1 = factory.create<A>("first parameter", 2);
		std::shared_ptr<A> a2 = factory.create<A>("first parameter", 2);
		std::shared_ptr<Base> a3 = factory.create("A", "first parameter", 2);

		// equivalent ways of create B
		std::shared_ptr<Base> b1 = factory.create<B>("first parameter", 2);
		std::shared_ptr<B> b2 = factory.create<B>("first parameter", 2);
		std::shared_ptr<Base> b3 = factory.create("B", "first parameter", 2);

		assert(a1 != a2);
		assert(a3 != b1);
		assert(b1 != b2);
	}

	return(0);
}

Example memoize (factory cache)

#include <iostream>
#include <sstream>
#include <assert.h>
#include <dp14/memoize.h>

class Base
{
public:
	using memoize = dp14::memoize<Base, std::string, int>;

	explicit Base(const std::string& name, int q)
		: _name(name)
		, _q(q)
	{
		std::cout << "constructor " << _name << " - " << _q << std::endl;
	}
	virtual ~Base() { std::cout << "destruction" << std::endl; }

protected:
	std::string _name;
	int _q;
};

class A : public Base
{
public:
	DEFINE_KEY(A)
	explicit A(const std::string& name, int q) : Base(name, q) { ; }
	virtual ~A() = default;
};

class B : public Base
{
public:
	DEFINE_KEY(B)
	explicit B(const std::string& name, int q) : Base(name, q) { ; }
	virtual ~B() = default;
};

int main()
{
	Base::memoize m;
	Base::memoize::registrator<A> reg1(m);
	Base::memoize::registrator<B> reg2(m);

	{
		std::shared_ptr<Base> a1 = m.get<A>("first parameter", 2);
		assert( m.exists<A>("first parameter", 2) == true );
	}
	assert( m.exists<A>("first parameter", 2) == false );

	{
		std::shared_ptr<Base> a1 = m.get<A>("first parameter", 2);
		std::shared_ptr<A> a2 = m.get<A>("first parameter", 2);
		assert(a1 == a2);

		std::shared_ptr<Base> a3 = m.get("A", "first parameter", 4);
		assert(a2 != a3);

		std::shared_ptr<Base> b1 = m.get<B>("first parameter", 2);
		std::shared_ptr<B> b2 = m.get<B>("first parameter", 2);
		assert(b1 == b2);

		std::shared_ptr<Base> b3 = m.get("B", "first parameter", 4);
		assert(b2 != b3);

		assert( m.exists<A>("first parameter", 2) == true );
	}
	assert( m.exists<A>("first parameter", 2) == false );

	return(0);
}