mirror of
https://github.com/ETLCPP/etl.git
synced 2026-04-30 19:09:10 +08:00
Fixed some menus
Added mode documentation files
This commit is contained in:
parent
a05e870abf
commit
2ececd4fe0
@ -1,5 +1,6 @@
|
||||
---
|
||||
title: "Embedded Template Library"
|
||||
weight: 998
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
47
docs/about.md
Normal file
47
docs/about.md
Normal file
@ -0,0 +1,47 @@
|
||||
---
|
||||
title: "About"
|
||||
weight: 2003
|
||||
---
|
||||
|
||||
*"Do It Once - Do it Right - So you don't have to do it again"*
|
||||
J Wellbelove : 2014
|
||||
|
||||
## Why write this library?
|
||||
I wrote this library, and all the others I have written over the
|
||||
years, because I'm lazy.
|
||||
|
||||
Yes, lazy!
|
||||
|
||||
One of the things I really hate when writing software is having to do the same, or something almost the same, over and over again. The first thing I think when presented with a problem that requires a specific set of functionality is "Is this a specific case of a more generic problem?". Surprisingly, I can say "yes" more often than you would expect. Even if not all of the problem can be seen as generic, there are almost certainly parts that are. In every job I've had I've left an extensive code library behind me.
|
||||
|
||||
Reinventing the wheel every time is daft for many reasons.
|
||||
|
||||
### Code bloat
|
||||
Multiple instances of slight variations of a theme results in an increase in code size due to no commonality of functionality.
|
||||
|
||||
Testing, more testing or no testing
|
||||
Are all the variants tested to the same degree? Are some tested at all?
|
||||
|
||||
### Variable functionality
|
||||
Not all the variants are going to have the same level of functionality, or the same API. Ad-hoc solutions are invariably only going to solve the little bit of the problem that was needed at the time.
|
||||
|
||||
This goes against the YAGNI1 principle so popular in some programming dogmas.
|
||||
I think that YAGNI is often just another way of saying ISEP2.
|
||||
I believe in GIRFT3.
|
||||
I have over three decades of empirical proof.
|
||||
|
||||
### No collective knowledge base
|
||||
Without commonality every new variant has to be learned. The underlying principles may be understood (i.e. Linked list), but each implementation has to be understood separately, along with its particular caveats and foibles.
|
||||
|
||||
Documentation is likely to be patchy, if it exists at all.
|
||||
|
||||
### Octopus code
|
||||
The application is liable to have a close coupling with the solution. For example, I've often seen code using linked lists directly accessing the node pointers. Ad-hoc solutions are liable to have lazy (the bad kind) implementations.
|
||||
|
||||
## About me
|
||||
I have been involved in technology and computer systems for all of my working life and have amassed considerable knowledge of designing and implementing systems that are both performant and correct.
|
||||
My role normally encompasses the entire project life-cycle, from specification to maintenance phase.
|
||||
|
||||
Most systems I have worked on have required high speed and deterministic performance, often within a highly constrained platform. I am experienced in designing and adapting algorithms to solutions that are both space and time efficient, avoiding the normal overheads of standard solutions.
|
||||
|
||||
Acting as a mentor for colleagues has often been a significant, though unofficial, part of my role.
|
||||
@ -1,3 +1,4 @@
|
||||
---
|
||||
title: "Callbacks"
|
||||
weight: 100
|
||||
---
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
---
|
||||
title: "Codecs"
|
||||
weight: 100
|
||||
---
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
---
|
||||
title: "Containers"
|
||||
weight: 100
|
||||
---
|
||||
|
||||
## Containers
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
---
|
||||
title: "Ranges"
|
||||
weight: 100
|
||||
---
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
---
|
||||
title: "Releases"
|
||||
weight: 2002
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
@ -1,3 +1,6 @@
|
||||
---
|
||||
title: "Source"
|
||||
weight: 2000
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
---
|
||||
title: "Strings"
|
||||
weight: 100
|
||||
---
|
||||
|
||||
6
docs/tutorials/_index.md
Normal file
6
docs/tutorials/_index.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
title: "Tutorials"
|
||||
weight: 2001
|
||||
---
|
||||
|
||||
---
|
||||
86
docs/tutorials/message_tutorial.md
Normal file
86
docs/tutorials/message_tutorial.md
Normal file
@ -0,0 +1,86 @@
|
||||
---
|
||||
title: "Messages"
|
||||
---
|
||||
|
||||
A tutorial on how the ETL's messaging framework can be used.
|
||||
|
||||
## Overview
|
||||
|
||||
The messaging framework is designed to allow a powerful, but easy to use, message routing and handling system to be created. It comprises of a collection of messages, message routers, message buses and finite state machines.
|
||||
Routers, buses and state machines share a unified API that allows different parts of the framework to be mixed and matched.
|
||||
|
||||
For example, a message source may pass messages to a message bus. The message bus may then forward messages to a number of other message recipients such as other buses, routers and FSMs. The sender of the message does not need to know the exact type of the receiver, only that it can receive messages.
|
||||
|
||||
## Messages
|
||||
|
||||
```C++
|
||||
etl::message
|
||||
```
|
||||
|
||||
All messages are untimately derived from `etl::imessage`.
|
||||
They are directly derived from the template `etl::message<const etl::message_id_t ID>`.
|
||||
Each message must have an id that is at least unique to the receiver, though normally ids would be unique across the application.
|
||||
|
||||
```C++
|
||||
enum class MessageId : etl::message_id_t
|
||||
{
|
||||
StartMotorId,
|
||||
StopMotorId
|
||||
};
|
||||
|
||||
struct StartMotor : public etl::message<StartMotorId>
|
||||
{
|
||||
};
|
||||
|
||||
struct StopMotor : public etl::message<StopMotorId>
|
||||
{
|
||||
};
|
||||
```
|
||||
|
||||
Messages are normally passed around as `const references` to `etl::imessage`.
|
||||
|
||||
By default, messages are not virtual. This may be changed by defining `ETL_POLYMORPHIC_MESSAGES` either in the project properties or in `etl_profile.h`.
|
||||
|
||||
By default the message id is a `uint_least8_t`. This may be changed by defining `ETL_MESSAGE_ID_TYPE` as the required type.
|
||||
|
||||
## Message Routers
|
||||
|
||||
```C++
|
||||
etl::message_router
|
||||
```
|
||||
Messages routers are defined to handle a specified set of messages. Defining a message router will mandate that a specific set of `on_receive` functions to handle each message type be defined, along with an 'unknown' handler.
|
||||
Failure to define the full set of handler functions will result in a compile error.
|
||||
|
||||
Message routers may either handle the message directly or implement message queues to defer handling.
|
||||
The message router uses a message packet class for implementing heterogeneous message queues.
|
||||
See the `QueuedMessageRouter` project in the `examples` directory.
|
||||
|
||||
## Message Buses
|
||||
|
||||
```C++
|
||||
etl::message_bus
|
||||
```
|
||||
Message buses are a type of message router.
|
||||
Message buses distribute messages to other message recipients. They do not process any messages.
|
||||
Other message recipients (those classes derived from etl::imessage_router) may subscribe to the bus.
|
||||
Messages sent to the bus may either be broadcast or directed only to routers with a specified id.
|
||||
|
||||
## Message Timer
|
||||
|
||||
```C++
|
||||
etl::message_timer
|
||||
```
|
||||
The message timer is a generator of messages. Up to 254 timers may be defined that can be configured to send a message to a router, bus or FSM at periodic intervals.
|
||||
|
||||
## Finite State Machines (FSM & HFSM)
|
||||
|
||||
```C++
|
||||
etl::fsm
|
||||
etl::hfsm
|
||||
```
|
||||
FSMs are also a type of message router.
|
||||
Messages sent to FSMs are handled in on_event handlers in classes derived from `etl::fsm_state`.
|
||||
The states are defined to handle a specified set of messages. Failure to define the full set of event functions will result in a compile error. Messages sent to states that have not been define to handle them will call an 'Unknown' handler.
|
||||
The FSM class uses the state pattern to change message handlers on state changes.
|
||||
|
||||
By default the state id is a `uint_least8_t`. This may be changed by defining `ETL_STATE_ID_TYPE` as the required type.
|
||||
172
docs/tutorials/observer_tutorial.md
Normal file
172
docs/tutorials/observer_tutorial.md
Normal file
@ -0,0 +1,172 @@
|
||||
---
|
||||
title: "Observer"
|
||||
---
|
||||
|
||||
A tutorial on how the ETL's observer pattern can be used.
|
||||
|
||||
## The Classes
|
||||
```C++
|
||||
etl::observer
|
||||
etl::observable
|
||||
```
|
||||
## Example
|
||||
This example shows an observable mouse driver that is observed by two event handlers.
|
||||
|
||||
```C++
|
||||
#include <iostream>
|
||||
|
||||
#include "observer.h"
|
||||
|
||||
// Position data.
|
||||
struct Position
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
};
|
||||
|
||||
// Button data.
|
||||
struct Button
|
||||
{
|
||||
enum
|
||||
{
|
||||
Down,
|
||||
Up
|
||||
};
|
||||
|
||||
int state;
|
||||
};
|
||||
|
||||
// Wheel data.
|
||||
struct Wheel
|
||||
{
|
||||
int delta;
|
||||
};
|
||||
|
||||
// Definition of a mouse observer.
|
||||
typedef etl::observer<const Position&, Button, Wheel> Mouse_Observer;
|
||||
|
||||
// Definition of an event handler for mouse notifications.
|
||||
class Event_Handler1 : public Mouse_Observer
|
||||
{
|
||||
public:
|
||||
|
||||
// Handle a position notification.
|
||||
void notification(const Position& position)
|
||||
{
|
||||
std::cout << "Event_Handler1 : Position = " << position.x << "," << position.y << "\n";
|
||||
}
|
||||
|
||||
// Handle a button notification.
|
||||
void notification(Button button)
|
||||
{
|
||||
std::cout << "Event_Handler1 : Button = " << ((button.state == Button::Up) ? "Up\n" : "Down\n");
|
||||
}
|
||||
|
||||
// Handle a wheel notification.
|
||||
void notification(Wheel wheel)
|
||||
{
|
||||
std::cout << "Event_Handler1 : Wheel delta = " << wheel.delta << "\n";
|
||||
}
|
||||
};
|
||||
|
||||
// Definition of a second event handler for mouse notifications.
|
||||
class Event_Handler2 : public Mouse_Observer
|
||||
{
|
||||
public:
|
||||
|
||||
// Handler a position notification.
|
||||
void notification(const Position& position)
|
||||
{
|
||||
std::cout << "Event_Handler2 : Position = " << position.x << "," << position.y << "\n";
|
||||
}
|
||||
|
||||
// Handle a button notification.
|
||||
void notification(Button button)
|
||||
{
|
||||
std::cout << "Event_Handler2 : Button = " << ((button.state == Button::Up) ? "Up\n" : "Down\n");
|
||||
}
|
||||
|
||||
// Handle a wheel notification.
|
||||
void notification(Wheel wheel)
|
||||
{
|
||||
// Not interested in wheel deltas.
|
||||
}
|
||||
};
|
||||
|
||||
// The observable mouse driver.
|
||||
const int MAX_MOUSE_OBSERVERS = 2;
|
||||
|
||||
class Mouse_Driver : public etl::observable<Mouse_Observer, MAX_MOUSE_OBSERVERS>
|
||||
{
|
||||
public:
|
||||
|
||||
// Notify observers about a position event.
|
||||
void Position_Event()
|
||||
{
|
||||
Position position = { 100, 200 };
|
||||
notify_observers(position);
|
||||
}
|
||||
|
||||
// Notify observers about a button up event.
|
||||
void Button_Event_Up()
|
||||
{
|
||||
Button button = { Button::Up };
|
||||
notify_observers(button);
|
||||
}
|
||||
|
||||
// Notify observers about a button down event.
|
||||
void Button_Event_Down()
|
||||
{
|
||||
Button button = { Button::Down };
|
||||
notify_observers(button);
|
||||
}
|
||||
|
||||
// Notify observers about a wheel up event.
|
||||
void Wheel_Event_Up()
|
||||
{
|
||||
Wheel wheel = { 50 };
|
||||
notify_observers(wheel);
|
||||
}
|
||||
|
||||
// Notify observers about a wheel down event.
|
||||
void Wheel_Event_Down()
|
||||
{
|
||||
Wheel wheel = { -25 };
|
||||
notify_observers(wheel);
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
Mouse_Driver mouse_driver;
|
||||
Event_Handler1 event_handler1;
|
||||
Event_Handler2 event_handler2;
|
||||
|
||||
// Tell the mouse driver about the observers.
|
||||
mouse_driver.add_observer(event_handler1);
|
||||
mouse_driver.add_observer(event_handler2);
|
||||
|
||||
// Generate some events.
|
||||
mouse_driver.Button_Event_Down();
|
||||
mouse_driver.Button_Event_Up();
|
||||
mouse_driver.Position_Event();
|
||||
mouse_driver.Wheel_Event_Down();
|
||||
mouse_driver.Wheel_Event_Up();
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
## Program output
|
||||
|
||||
```
|
||||
Event_Handler1 : Button = Down
|
||||
Event_Handler2 : Button = Down
|
||||
Event_Handler1 : Button = Up
|
||||
Event_Handler2 : Button = Up
|
||||
Event_Handler1 : Position = 100,200
|
||||
Event_Handler2 : Position = 100,200
|
||||
Event_Handler1 : Wheel delta = -25
|
||||
Event_Handler1 : Wheel delta = 50
|
||||
```
|
||||
|
||||
188
docs/tutorials/visitor_tutorial.md
Normal file
188
docs/tutorials/visitor_tutorial.md
Normal file
@ -0,0 +1,188 @@
|
||||
---
|
||||
title: "Visitor"
|
||||
---
|
||||
|
||||
A tutorial on how the ETL's visitor pattern can be used.
|
||||
|
||||
## The Classes
|
||||
```C++
|
||||
etl::visitor
|
||||
etl::visitable
|
||||
```
|
||||
|
||||
## Example
|
||||
I'll use the familiar 'Shape' example.
|
||||
|
||||
First, you create the base for your 'Shape' visitor.
|
||||
|
||||
```C++
|
||||
//*****************************************************************
|
||||
// Pre-declare the shapes.
|
||||
//*****************************************************************
|
||||
class Square;
|
||||
class Circle;
|
||||
class Triangle;
|
||||
|
||||
//*****************************************************************
|
||||
// The shape visitor base class.
|
||||
// Pure virtual 'visit' functions will be defined for the Square,
|
||||
// Circle, and Triangle types.
|
||||
//*****************************************************************
|
||||
class Shape_Visitor : public etl:visitor<Square, Circle, Triangle>
|
||||
{
|
||||
};
|
||||
```
|
||||
|
||||
Then, you define the Shape base class. It derives from the `etl::visitable` class that defines a pure virtual accept function that accepts a `Shape_Visitor`.
|
||||
|
||||
```C++
|
||||
//*****************************************************************
|
||||
// The shape base class.
|
||||
//*****************************************************************
|
||||
class Shape : public etl::visitable<Shape_Visitor>
|
||||
{
|
||||
};
|
||||
```
|
||||
|
||||
Next, you define the shapes `Square`, `Circle`, and `Triangle`. Each overrides the accept function that calls the visitor with itself as a parameter.
|
||||
|
||||
```C++
|
||||
//*****************************************************************
|
||||
// The square class
|
||||
//*****************************************************************
|
||||
class Square : public Shape
|
||||
{
|
||||
void accept(Shape_Visitor &visitor)
|
||||
{
|
||||
visitor.visit(*this);
|
||||
}
|
||||
};
|
||||
|
||||
//*****************************************************************
|
||||
// The circle class
|
||||
//*****************************************************************
|
||||
class Circle : public Shape
|
||||
{
|
||||
void accept(Shape_Visitor &visitor)
|
||||
{
|
||||
visitor.visit(*this);
|
||||
}
|
||||
};
|
||||
|
||||
//*****************************************************************
|
||||
// The triangle class
|
||||
//*****************************************************************
|
||||
class Triangle : public Shape
|
||||
{
|
||||
void accept(Shape_Visitor &visitor)
|
||||
{
|
||||
visitor.visit(*this);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Now that you have the framework in place, you can do something with it. Here's an example that creates `Draw` and `Serialise` visitors and applies them to a vector of `Shape` objects.
|
||||
|
||||
```C++
|
||||
//*****************************************************************
|
||||
// The 'draw' visitor.
|
||||
//*****************************************************************
|
||||
class Draw_Visitor : public Shape_Visitor
|
||||
{
|
||||
public:
|
||||
void visit(Square &square)
|
||||
{
|
||||
std::cout << "Draw the square\n";
|
||||
}
|
||||
|
||||
void visit(Circle &circle)
|
||||
{
|
||||
std::cout << "Draw the circle\n";
|
||||
}
|
||||
|
||||
void visit(Triangle &triangle)
|
||||
{
|
||||
std::cout << "Draw the triangle\n";
|
||||
}
|
||||
};
|
||||
|
||||
//*****************************************************************
|
||||
// The 'serialise' visitor.
|
||||
//*****************************************************************
|
||||
class Serialise_Visitor : public Shape_Visitor
|
||||
{
|
||||
public:
|
||||
void visit(Square &square)
|
||||
{
|
||||
std::cout << "Serialise the square\n";
|
||||
}
|
||||
|
||||
void visit(Circle &circle)
|
||||
{
|
||||
std::cout << "Serialise the circle\n";
|
||||
}
|
||||
|
||||
void visit(Triangle &triangle)
|
||||
{
|
||||
std::cout << "Serialise the triangle\n";
|
||||
}
|
||||
};
|
||||
|
||||
//*****************************************************************
|
||||
// The actual visitors.
|
||||
//*****************************************************************
|
||||
Draw_Visitor draw_visitor;
|
||||
Serialise_Visitor serialise_visitor;
|
||||
|
||||
//*****************************************************************
|
||||
// The list of shapes.
|
||||
//*****************************************************************
|
||||
std::vector<Shape*> shape_list;
|
||||
|
||||
//*****************************************************************
|
||||
// The Apply a visitor.
|
||||
//*****************************************************************
|
||||
void Apply(Shape_Visitor &visitor)
|
||||
{
|
||||
for (auto pShape : shape_list)
|
||||
{
|
||||
// Send the visitor to the shape.
|
||||
pShape->accept(visitor);
|
||||
}
|
||||
}
|
||||
|
||||
//*****************************************************************
|
||||
// Main
|
||||
//*****************************************************************
|
||||
int main()
|
||||
{
|
||||
// Create some shapes.
|
||||
Square square;
|
||||
Circle circle;
|
||||
Triangle triangle;
|
||||
|
||||
// Add them to the vector
|
||||
shape_list.push_back(&square);
|
||||
shape_list.push_back(&circle);
|
||||
shape_list.push_back(&triangle);
|
||||
|
||||
// Apply the visitors.
|
||||
Apply(draw_visitor);
|
||||
Apply(serialise_visitor);
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
## Output
|
||||
The output from the example is as follows.
|
||||
|
||||
```
|
||||
Draw the square
|
||||
Draw the circle
|
||||
Draw the triangle
|
||||
Serialise the square
|
||||
Serialise the circle
|
||||
Serialise the triangle
|
||||
```
|
||||
|
||||
@ -29,7 +29,7 @@ html:not(.dark) h2 {
|
||||
html:not(.dark) h3,
|
||||
html:not(.dark) h4
|
||||
{
|
||||
color: green !important;
|
||||
color: rgb(29, 172, 29) !important;
|
||||
border-bottom: 1px solid darkgrey !important;
|
||||
}
|
||||
|
||||
|
||||
@ -48,4 +48,14 @@ theme = 'hextra'
|
||||
[[menus.main]]
|
||||
name = "Home"
|
||||
pageRef = "/docs"
|
||||
weight = 10
|
||||
weight = 1
|
||||
|
||||
[[menus.main]]
|
||||
name = "About"
|
||||
url = "/about/"
|
||||
weight = 999
|
||||
|
||||
[[menus.main]]
|
||||
name = "Blog"
|
||||
url = "/blog/"
|
||||
weight = 3
|
||||
Loading…
x
Reference in New Issue
Block a user