mirror of
https://github.com/bdring/Grbl_Esp32.git
synced 2025-09-01 10:23:19 +02:00
Added MD file for generic factory. Moved Parser::is to cpp file.
This commit is contained in:
39
Grbl_Esp32/src/Configuration/GenericFactory.md
Normal file
39
Grbl_Esp32/src/Configuration/GenericFactory.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# How GenericFactory works
|
||||
|
||||
In short. Motors and spindles are registered through an abstract factory
|
||||
(GenericFactory.h). The 'factory' builds motors and spindle instances
|
||||
by name. The only thing you need to do is put the name in the header
|
||||
file (`const char* name() const override { return "null_motor"; }`)
|
||||
and put the registration in the cpp file
|
||||
`namespace { MotorFactory::InstanceBuilder<Nullmotor> registration("null_motor"); }`.
|
||||
In the yaml parser, the correct motor is then created in the handle
|
||||
method by calling `Motors::MotorFactory::handle(handler, _motor);`.
|
||||
|
||||
This means that there are literally no hard dependencies between motors.
|
||||
Not having dependencies is good, it can greatly help with compile-times
|
||||
and git merging.
|
||||
|
||||
In long (How this works)... In C++, each template class is a separate
|
||||
type. So, that means that if we have a `MotorFactory` (Motors.h) and
|
||||
a `SpindleFactory` (Spindle.h), they don't share static members. Once
|
||||
registered, the builders in the factory returns the classes that can
|
||||
build a certain type; so a SpindleFactory won't have motors and visa
|
||||
versa.
|
||||
|
||||
Registration works using a global variable. Global variables are
|
||||
instantiated before the first method is invoked. In our case this
|
||||
means it will call the constructor of the builder, which registers
|
||||
itself in the factory. There's just one more thing that needs to be
|
||||
solved at that point, and that's the fact that registration here will
|
||||
lead to make conflicts. This is solved by using an anonymous namespace,
|
||||
which ensures that these registration global variables are unique.
|
||||
|
||||
So, what happens... When the application starts up, it automatically
|
||||
runs the globals, which set up the name-to-builder mapping in the
|
||||
factory. Then, while parsing the yaml, the name is looked up, finds
|
||||
a builder, and the instance is created.
|
||||
|
||||
# Further reading
|
||||
|
||||
GenericFactory is a C++ implementation of an
|
||||
[Abstract factory pattern](https://en.wikipedia.org/wiki/Abstract_factory_pattern).
|
@@ -22,6 +22,18 @@ namespace Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Parser::is(const char* expected) const {
|
||||
if (current_.keyStart_ == nullptr) {
|
||||
return false;
|
||||
}
|
||||
auto len = strlen(expected);
|
||||
if (len != (current_.keyEnd_ - current_.keyStart_)) {
|
||||
return false;
|
||||
}
|
||||
return !strncmp(expected, current_.keyStart_, len);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MoveNext: moves to the next entry in the current section. By default we're in the
|
||||
/// root section.
|
||||
|
@@ -38,16 +38,7 @@ namespace Configuration {
|
||||
void enter();
|
||||
void leave();
|
||||
|
||||
bool is(const char* expected) const {
|
||||
if (current_.keyStart_ == nullptr) {
|
||||
return false;
|
||||
}
|
||||
auto len = strlen(expected);
|
||||
if (len != (current_.keyEnd_ - current_.keyStart_)) {
|
||||
return false;
|
||||
}
|
||||
return !strncmp(expected, current_.keyStart_, len);
|
||||
}
|
||||
bool is(const char* expected) const;
|
||||
|
||||
inline StringRange key() const { return StringRange(current_.keyStart_, current_.keyEnd_); }
|
||||
|
||||
|
Reference in New Issue
Block a user