Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Named pankus #9

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ CMakeFiles/
CMakeCache.txt
build/
tags
*swp
44 changes: 23 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
### PANKU

Panku is a header-only library designed to help with static initialisation of
multiple devices, in cases where there are complex order dependencies between
multiple objects, in cases where there are complex order dependencies between
them.

As an embedded project grows, there is a pattern that keeps repeating itself: a
monolithic file, usually named some variant of "InitialiseDevices", which
contains all the code necessary to construct and interconnect elements of the
system of varying abstraction levels, such as the scheduler, terminal, UART and
Flash drivers, etc.
It was created for an embedded use case. As an embedded project grows, there is
a pattern that keeps repeating itself: a monolithic file, usually named some
variant of "InitialiseDevices", which contains all the code necessary to construct
and interconnect elements of the system of varying abstraction levels, such as the
scheduler, terminal, UART and Flash drivers, etc.

This file can easily grow out of control and become a maintenance burden.
Furthermore, anyone wanting to add a new object to the static initialisation
Expand All @@ -21,24 +21,25 @@ codebase.

## How to use

To integrate Panku in your project, include the file "panku.h"
To integrate Panku in your project, include the file "named_panku.h"
and use the following macro:
* **PANKU_LIST**: Declares the list of classes that Panku will be in charge of
initialising. Each class is introduced as a dependency list, followed by the
classes it depends on. Example:
* **NAMED_PANKU_LIST**: Declares a panku name and the list of classes that panku
will be in charge of initialising. Each class is introduced as a dependency list,
followed by the classes it depends on. Example:
```c++
#include "panku.h"
#include "named_panku.h"
#include "UART.h"
#include "Flash.h"
#include "FileSystem.h"
#include "Terminal.h

PANKU_LIST
NAMED_PANKU_LIST
(
INSTANCE(FileSystem, Flash), // File system depends on a flash driver
INSTANCE(Flash), // Flash driver has no dependencies
INSTANCE(Terminal, UART, Flash), // Terminal depends on both drivers
INSTANCE(UART) // UART is also dependency free
devices,
NAMED_INSTANCE(FileSystem, Flash), // File system depends on a flash driver
NAMED_INSTANCE(Flash), // Flash driver has no dependencies
NAMED_INSTANCE(Terminal, UART, Flash), // Terminal depends on both drivers
NAMED_INSTANCE(UART) // UART is also dependency free
);
```
Note that this list can be defined in any order, the dependency graph will
Expand All @@ -52,11 +53,12 @@ and use the following macro:
possible to skip "Initialise", in which case it will be called lazily in the
first use of "Get".
```c++
Panku devices;
panku_devices devices;
devices.Get<Flash>(); // Returns a reference to the Flash instance
```
**Important:** There must be only one Panku object! We are working on removing
this limitation
* **Important:** As a panku grows, it takes more resources to solve the
"dependency puzzle". It is recommended that you split large pankus up to
avoid excessive RAM and CPU use at compile-time.

Finally, even though Panku can figure out in which order to initialise your
devices, it has no way to know what constructor arguments you want. To specify
Expand All @@ -72,8 +74,8 @@ MyClass& ConstructAndInitialise<MyClass&>() {

## Multiple object instances:
If you require multiple instances of the same class, you can use
COLLECTION(N, Class, Deps...) in place of INSTANCE(Class, Deps...). You will
have to supply N constructor functions of the form:
NAMED_COLLECTION(N, Class, Deps...) in place of NAMED_INSTANCE(Class, Deps...).
You will have to supply N constructor functions of the form:

```c++
Class& ConstructAndInitialise<Class&, 0>;
Expand Down
24 changes: 24 additions & 0 deletions example/Devices.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,30 @@ Gamma& ConstructAndInitialise<Gamma&>() {
return gamma;
}

template<>
Delta& ConstructAndInitialise<Delta&>() {
static Delta delta;
return delta;
}

template<>
Epsilon& ConstructAndInitialise<Epsilon&>() {
static Epsilon epsilon;
return epsilon;
}

template<>
Zeta& ConstructAndInitialise<Zeta&>() {
static Zeta zeta;
return zeta;
}

template<>
Eta& ConstructAndInitialise<Eta&>() {
static Eta eta(devices2.Get<Zeta>());
return eta;
}

template<>
NamedObject& ConstructAndInitialise<NamedObject&, 0>() {
static NamedObject namedObjectZero("Zero");
Expand Down
31 changes: 26 additions & 5 deletions example/Devices.h
Original file line number Diff line number Diff line change
@@ -1,14 +1,35 @@
#pragma once

#include "named_panku.h"
#include "panku.h"
#include "ExampleDeviceClasses.h"

NAMED_PANKU_LIST
(
one,
NAMED_INSTANCE(Beta, Alpha),
NAMED_INSTANCE(Alpha),
NAMED_INSTANCE(Gamma, Alpha, Beta),
NAMED_COLLECTION(2, NamedObject)
);

NAMED_PANKU_LIST
(
two,
NAMED_INSTANCE(Delta),
NAMED_INSTANCE(Epsilon),
NAMED_INSTANCE(Zeta),
NAMED_INSTANCE(Eta, Zeta)
);

PANKU_LIST
(
INSTANCE(Beta, Alpha),
INSTANCE(Alpha),
INSTANCE(Gamma, Alpha, Beta),
COLLECTION(2, NamedObject)
NAMED_INSTANCE(Alpha),
NAMED_INSTANCE(Zeta)
);

extern panku devices;
extern panku_one devices;
extern panku_two devices2;
extern panku noname;


45 changes: 45 additions & 0 deletions example/ExampleDeviceClasses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,29 @@ Gamma::Gamma(Alpha& alpha, Beta& beta):
printf("\n\n");
}

Delta::Delta()
{
printf("Hi! I'm Delta and I'm being initialised. I don't know anyone yet!\n\n\n");
}

Epsilon::Epsilon()
{
printf("Hi! I'm Epsilon and I'm being initialised. I don't know anyone yet!\n\n\n");
}

Zeta::Zeta()
{
printf("Hi! I'm Zeta and I'm being initialised. I don't know anyone yet!\n\n\n");
}

Eta::Eta(Zeta& zeta)
{
printf("I'm Eta reading zeta on initialisation, say hi, Zeta:\n");
zeta.Talk();
printf("\n\n");
}


NamedObject::NamedObject(const char* name):
name(name)
{
Expand All @@ -47,3 +70,25 @@ void NamedObject::Talk()
{
printf("I'm a named object, and my name is %s\n", name);
}

void Delta::Talk()
{
printf("Hi! I'm Delta\n");
}

void Epsilon::Talk()
{
printf("Hi! I'm Epsilon\n");
}

void Zeta::Talk()
{
printf("Hi! I'm Zeta\n");
}

void Eta::Talk()
{
printf("Hi! I'm Eta\n");
}


38 changes: 38 additions & 0 deletions example/ExampleDeviceClasses.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,41 @@ class NamedObject: public MultiParent {
private:
const char* name;
};

class Delta: public MultiParent {
public:
void Talk();
Delta();
private:
Delta(const Delta&);
const Delta& operator=(const Delta&);
};

class Epsilon: public MultiParent {
public:
void Talk();
Epsilon();
private:
Epsilon(const Epsilon&);
const Epsilon& operator=(const Epsilon&);
};

class Zeta: public MultiParent {
public:
void Talk();
Zeta();
private:
Zeta(const Zeta&);
const Zeta& operator=(const Zeta&);
};

class Eta: public MultiParent {
public:
void Talk();
Eta(Zeta&);
private:
Eta(const Eta&);
const Eta& operator=(const Eta&);
};


22 changes: 19 additions & 3 deletions example/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@
#include <iostream>
#include <tuple>

panku devices;
panku_one devices;
panku_two devices2;

panku notypename;

using namespace ::std;

int main(void) {
// This is optional. In its absence, user classes will be initialised
Expand All @@ -13,14 +18,25 @@ int main(void) {
devices.Get<Beta>().Talk();
devices.Get<Gamma>().Talk();

std::cout << "Now we will test entry collections (in this case, two different instances of NamedObject);" << std::endl;
cout << "Now we will test entry collections (in this case, two different instances of NamedObject);" << endl;

devices.Get<NamedObject,0>().Talk();
devices.Get<NamedObject,1>().Talk();

std::cout << "Now we will test iteration by parent class, for Alpha, Beta and the named objects in a collection" << std::endl;
cout << "Now we will test iteration by parent class, for Alpha, Beta and the named objects in a collection" << endl;
// It is possible to iterate by base or derived class as well.
devices.ForEach<MultiParent>([](MultiParent& parent) {
parent.Talk();
});

devices2.Initialise();
devices2.Get<Delta>().Talk();
devices2.Get<Epsilon>().Talk();
devices2.Get<Zeta>().Talk();
devices2.Get<Eta>().Talk();

cout << "Now we will create a simple panku that has no distinct type name. This use case is maintained for backward compatibility" << endl;
notypename.Initialise();
notypename.Get<Alpha>().Talk();
notypename.Get<Zeta>().Talk();
}
4 changes: 4 additions & 0 deletions named_panku.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#pragma once
#include "private/NamedMetaprogram.h"

// Check out README.md for instructions.
Loading