splitting tasks to categories - c++

I have a class (lets call it checker) and diffrent kind of classes that execute tasks (lets call them tasks). each tasks belongs to several categories
each task runs and at some point asks checker if they are allowed to do something. checker answers according to system state and according to their category. a task can be in multiple categories
how would you implement that? (cpp but I don't really think its language specific).
I was thinking adding a list of categories in each task and have a function that gets a category and answers if the task belongs to it.
class checker {
bool is_allowed(Task * task);
}
class Task
{
bool is_belongging_to_category(Category cat);
void some_task_to_do()
{
...
if (checker::is_allowed(this)) { ....}
else {....}
}
}
Is there a better way to solve this? Maybe some known design pattern...

This looks like questionable design. You're making tasks the objects.
Let's say your tasks are: Eat, Drink, and Be_Merry
If you make each of those tasks objects, they'll have to maintain a reference to the actual individual that they operate on, then when the condition is met they'll need to modify state on the given individual.
This is a violation of Object Oriented Design which defines an object as:
A tight coupling or association of data structures with the methods or functions that act on the data
Notice that you have split the "methods or functions that act on the data" from the object. Instead you should have modeled the objects Jack and Jill which had methods: Eat, Drink, and BeMerry
As far as checker, whether it's parceled out will depend upon whether you're using a push or a pull coding. If you're doing push coding, then checker is simply a holding area for the behavioral properties of Jack and Jill, in such a case the properties should be pushed to Jack and Jill rather than held in checker. If they are properties for all Jack or Jill objects, use a static property. If however you are using pull coding then the information is unavailable until you attempt to execute the task. In this case the checker should probably be a singleton that Jack and Jill access in the process of performing their tasks.
EDIT:
Your comment reveals further tragedy in the design. It seems as though you've kicked off a bunch of threads which are doing busy waiting on checker. This indicates that you need to be using a pull coding. You're Jack and Jill objects need to maintain booleans for which tasks they are actively involved in, for example m_is_going_to_school, then when checker gets the condition that would stop your busy waiting in your design, instead kick off the goToSchool method.

You could make a vector to store all the possible allowed options. You can make a bool function (like you have) called IsAllowed with argument string and that will check if the option its going to do is allowed. If not, return false. That's just my idea though. Of course there's a zillion different ways to implement this. If you want multiple choices. Then you can make a 2d vector, and see if the corresponding row has any of the options. Good luck!

If you know the maximum number of categories in advance, I'd recommend using Bit Flags to do this.
enum Category {
CATEGORY_A = 1,
CATEGORY_B = 1 << 1,
CATEGORY_C = 1 << 2,
CATEGORY_D = 1 << 3,
};
class Task {
int32_t categories_;
public:
Task() : categories_(0) {}
void add_category(Category cat) {
categories_ |= cat;
}
void run() {
checker::can_run(categories_);
}
}
This allows to test for multiple categories all at once:
namespace checker {
bool can_run(int32_t categories) {
int32_t cannot_run_right_now = CATEGORY_A | CATEGORY_C;
if(categories & cannot_run_right_now != 0) {
return false;
}
...
}
}

Well, it depends. If you are 100% sure that you know how many categories there are to be and that is not some gigantic number then you might store this information as an integer. If n-th bit is 1 then task belongs to n-th category. Then depends on the state of system you might create some another integer that would serve as a mask. In the end you would just do some bit-AND ( mask & categories != 0 ) operation to determine if task and mask share common bit.
On the other hand if there will be unknown number of categories you might just make a list of categories it belongs to. Make a dictionary of [SYSTEM_STATE] => [CATEGORIES_AVAILABLE] and check
bool is_allowed(Task * task){
foreach (Category sysC in stateCategories[sys.GetState()])
{
foreach (Category taskC in task.GetCategories())
{
if(sysC == taskC) return true;
}
}
return false;
}
That would of course be slow for a big number of categories.
You could improve this method by making this list of categories some another data structure, in which searching is not O(n) such that the code would look like this :
bool is_allowed(Task * task){
foreach (Category sysC in stateCategories[sys.GetState()])
{
if task.GetCategories().Contains(sysC) {
return true;
}
}
It depends

Related

OOP for global system/task monitoring class

I'm trying to create a performance monitor of sorts to run on a Particle board (STM32 based). I'm used to programming in c so the OOP approach is a bit new but I think it would fit well here.
For the purpose of this question let's assume I have two types of monitors:
Frequency. The application can call a "tick" method of the monitor to calculate the time since it last ran and store it.
Period- call a "start" and "stop" method of the monitor to calculate how long a process takes to run and store it.
What I would like to do is to create instances of these monitors throughout my application and be able to report on the stats of all monitors of all types from the main module.
I've read about the singleton design pattern which seems like it might be what I need but I'm not sure and I'm also concerned about thread safety with that.
I'm thinking I will create a "StatMonitor" class and a derived class "FrequencyMonitor" and "PeriodMonitor". Monitor would be a singleton and everywhere I wanted to create a new monitor I would request an instance of "Monitor" and use that like so:
freqMonitor * task1FreqMonitor = StatMonitor::GetInstance()->Add_Freq_Monitor("Task1");
The StatMonitor would track all monitors I've added and when I wanted to print the stats I could just call the printAll method which would iterate it's array of monitors and request their results like so:
StatMonitor::GetInstance()->PrintAllStats();
Am I going down the right path?
Your path sounds good, except that FrequencyMonitor and PeriodMonitor should not derive from the class that "manages" all these monitors (let's call it MonitorPrinter).
MonitorPrinter should be a singleton and could look like this:
class MonitorPrinter
{
public:
static MonitorPrinter& getInstance()
{
static MonitorPrinter monitorPrinter;
return monitorPrinter;
}
void printAllStats()
{
for (const auto& [_, frequencyMonitor] : _frequencyMonitors)
frequencyMonitor.print();
for (const auto& [_, periodMonitor] : _periodMonitors)
periodMonitor.print();
}
FrequencyMonitor& getFrequencyMonitor(std::string name)
{ return _frequencyMonitors[name]; }
PeriodMonitor& getPeriodMonitor(std::string name)
{ return _periodMonitors[name]; }
private:
MonitorPrinter() = default;
std::map<std::string, FrequencyMonitor> _frequencyMonitors;
std::map<std::string, PeriodMonitor> _periodMonitors;
};
Demo
(The const auto& [_, frequencyMonitor] is a structured binding).
FrequencyMonitor and PeriodMonitor should not have anything to do with singletons, and from your description, they need not be part of a class hierarchy either (as they have different interfaces). If you want, you can prevent users (other than the MonitorPrinter) from instantiating these classes using other techniques, but I won't elaborate on that here.
In short, there is no need to use OOP here. Use a singleton to provide (and keep track of) the monitors, and implement the monitors to your liking. Be wary of thread safety if this is relevant (the above is not thread-safe!).

State Machine design handling data input

Im working on a real time machine control system, which performs a series of tasks, and should react to a large number of inputs. I've decided to implement this system using a state machine.
Ive used simple switch/case based state machines in the past and would like to transition to a more maintainable solution. At the moment I'm a little confused as to how to handle input and transitions.
For example I have an AnalogInput class which provides me with measurement values which i should monitor. Say I have a state WaitForThreshold, which should read a AnalogInput and then transition if the threshold is reached.
Do I
a) a pass a reference of the AnalogInput class to the WaitForThreshold class and allow it to monitor the input itself, signaling to the StateMachine class that it wishes to transition.
b) create dedicated events, LaserMeasurementAtThreshold and a state transition map: StateMachine.addTransition(State A, Event e, State B)
c)create more generic events AnalogInputChanged and implement event handlers for each of the events, which again signal to the StateMachine that a transition is desired
option a is essentially the larger version of a simple switch/case state machine, which could get messy with time, but offers great flexibility and b/c seems more structured and clean but seems like i may have to jump through alot of hoops to implement relatively simple tasks because the number of events can be very large.
Can someone offer some insight on the design of state machines where a large number of inputs sources and types must be monitored, and events are largely state-specific(Most event pertain only to a single state)?
Are there possibly other alternatives to state machine design to control a system where a sequence of steps must be implemented (non linear, looping and branchig must be possible)
Language: C++
Thanks
I believe this would be clearer to implement as a table of transitions:
typedef (void)((*Pointer_To_Transition_Function)());
struct Table_Entry
{
Input_Type input_value;
Pointer_To_Transisiton_Function p_trans_function;
};
static const Table_Entry Transition_Table[] =
{
{4, Read_Sensor},
};
static const size_t transition_quantity =
sizeof(Transition_Table) / sizeof(Transition_Table[0]);
//...
for (size_t index = 0; index < transition_quantity; ++index)
{
if (input_value = Transition_Table[index].input_value)
{
Pointer_To_Transition_Function p_function = Transition_Table[index].p_trans_function;
// Call the function:
p_function();
break;
}
}
You could use std::map, but the std::map has to be initialized during run-time. The table (array) is static and constant, thus it can be placed into a read-only memory segment (convenient for embedded systems); and doesn't use dynamic memory allocation.
Edit 1: ASCII drawing of the table
+-------------+--------------------------------+
| Input value | Pointer to transition function |
+-------------+--------------------------------+
| 4 | Read sensor |
+-------------+--------------------------------+
| 2 | Start motor |
+-------------+--------------------------------+

Entity component architecture : want to split big entity -> hard to refactor

In the first step of development, I design Car and AI as 1 entity.
It works nice (pseudo code):-
for(every entity that is "racing car"){
//^ know type by using flag
// or iterate special component (e.g. "RacingCarComponent")
Entity entity=...
AI* ai=get<AI>(entity);
ai->setInformation(...)
}
for(every entity that is "bicycle"){
Entity entity=...
AI* ai=get<AI>(entity);
ai->setInformation(...) //the info is very different from "racing car"
}
Later, I want a new feature : switch in-out Driver (which effect AI).
I split the entity as shown in the following diagram :-
The above code will be updated to be :-
for(every entity that is "racing car"){
Entity entity=...
AttachAI* aiAttach=get<AttachAI>(entity); //<-- edit
aiAttach->ai->setInformation(...) //<-- edit
}
for(every entity that is "bicycle"){
Entity entity=...
AttachAI* aiAttach=get<AttachAI>(entity); //<-- edit
aiAttach->ai->setInformation(...) //<-- edit
}
Problem
It works nice both before and after the change, but it is hard to maintain.
If there are N types of vehicle in version1 e.g. truck, motercycle, plane, boat, rocket,
I will have to edit N*2 lines of which potentially have already scattered around many .cpp.
Main issue : If I forget to refactor any code, it will still compile fine.
Problem will appear in only run-time.
In real life, I face such issue whenever new design wish to divide an entity into many simpler entities.
The refactoring is always just adding another one indirection.
Question
Suppose that in version1, I don't expect that I will want to switch in/out Driver.
Is it possible to prevent the problem? How?
I may be mistaken, but it seems as though you may be looping through all of the entities multiple times, checking a condition. I am not exactly sure about c++ syntax, so please bear with me:
for (entities as entity) {
info = null;
//Check type to get specific info
if (type is a "racing car"){
info = "fast car";
}
elseif (type is a "bicycle") {
info = "rad spokes";
}
//If we found info, we know we had a valid type
if (info isnt null) {
aiAttach = get(entity);
aiAttach->ai->setInformation(info);
}
}
I'm not sure if the get function requires anything specific for each type. In my pseudocode example, I assume we are only sending the entity and not something type specific. If it does, an additional variable could be used.

Suggested flow-control structure for order-dependant operations

I've run into the following issue which is not difficult to solve by any stretch of the imagination but I would like to know what the best / most elegant solution is.
I have the following method that the prototype of looks like this:
bool Team::isEveryoneDead(int teamOnTurn);
There are two teams available and depending on what instance of the team is currently on turn, I would like to check whether every Character in the team is dead in this very particular order:
Loop trough all the Characters in the team that's not on turn first. Should there be any character that's alive, stop looping (and goto step 2.). Should there be noone alive, terminate the function and return.
Now that I know that the team that's not on turn contains at least one character that's alive, loop trough the team that's currently on turn and check for the same thing. Should I find someone alive, stop looping and terminate / return.
The argument int teamOnTurn allows me to resolve the instance of Team that's currently on turn. The order in which i evaluate the "alive condition" is of great importance here.
Now, there are several approaches that can be taken, say hardcoding the order (since there are only 2 possible orders) and resolving the order by checking who's on turn and then executing the branch that already has the specific order like this:
bool Team::isEveryoneDead(int teamOnTurn) {
if (Team::Blue == teamOnTurn) {
checkThis();
checkThat();
} else {
checkThat();
checkThis();
}
}
This solution however wouldn't quite work for say 5! permutations for specific call-ordering for more items. What technique should one deploy to solve this with the utmost elegance :) ?
Thanks in advance, Scarlet.
Try creating another internal method that actually does the checking, and let the isEveryoneDead() method orchestrate the order in which the teams are checked, maybe something like this:
bool Team::isEveryoneDead(int teamOnTurn) {
bool isFound = isEveryoneDeadInternal( /* params for team not on turn */ );
if(isFound) {
isFound = isEveryoneDeadInternal( /* params for team on turn */ );
}
return isFound;
}
// This method know nothing about on turn or off turn
bool Team:isEveryoneDeadInternal() {
// Loop through all characters in the team, checking if any are alive
// When the first live character is found, return true
// else return false
}
This is a concept called DRY : Dont Repeat Yourself

Best tree/heap data structure for fixed set of nodes with changing values + need top 20 values?

I'm writing something like a game in C++ where I have a database table containing the current score for each user. I want to read that table into memory at the start of the game, quickly change each user's score while the game is being played in response to what each user does, and then when the game ends write the current scores back to the database. I also want to be able to find the 20 or so users with the highest scores. No users will be added or deleted during the short period when the game is being played. I haven't tried it yet, but updating the database might take too much time during the period when the game is being played.
Fixed set of users (might be 10,000 to 50,000 users)
Will map user IDs to their score and other user-specific information.
User IDs will be auto_increment values.
If the structure has a high memory overhead that's probably not an issue.
If the program crashes during gameplay it can just be re-started.
Greatly prefer something already available, such as open source/public domain code.
Quickly get a user's current score.
Quickly add to a user's current score (and return their current score)
Quickly get 20 users with highest score.
No deletes.
No inserts except when the structure is first created, and how long that takes isn't critical.
Getting the top 20 users will only happen every five or ten seconds, but getting/adding will happen much more frequently.
If not for the last, I could just create a memory block equal to sizeof(user) * max(user id) and put each user at user id * sizeof(user) for fast access. Should I do that plus some other structure for the Top 20 feature, or is there one structure that will handle all of this together?
Use a std::map. In the incredibly unlikely event that it ever shows up in your profiling, you could maybe think about changing to something more exotic. Memory overhead for 50k users will be around a megabyte or two.
I doubt that iterating over a map with 50k entries every 5-10 seconds, to find the top scores, will introduce significant overhead. If it does, though, either use a Boost multi-index container, or maintain a separate structure for the hi-scores (a heap, or just an array of pointers to the current top 20, in order). Just with an array / vector of 20, the code to increment a score might look something like this (assuming scores only go up, not down):
player.score += points;
if (player.score > hiscores[19]->score) {
hiscore_dirty = true;
}
And the code to get the hi-scores:
if (hiscore_dirty) {
recalculate_hiscores();
hiscore_dirty = false;
}
std::for_each(hiscores.begin(), hiscores.end(), do_something);
If your "auto-increment" and "no delete" policies are fixed forever (i.e. you will never delete users from the DB), and therefore user ids truly are a contiguous range from 0 to the limit, then you should just use a std::vector instead of a std::map.
You might be interested in Fibonacci Heap. This has O(1) (amortized) increaseKey and findMax.
For more info on Heap in general refer: Heap Data Structure, especially the table which compares different heaps.
An implementation of Fibonacci Heap can be found here which you can perhaps use/get inspired from: http://resnet.uoregon.edu/~gurney_j/jmpc/fib.html
First of all, given that you have a Key/Value scenario, you should probably use an Associative Container.
If you are using plain old C++ and do not have Boost available, follow Steve Jessops's suggestion and simply use a std::map, if you have either C++0x or Boost, you'd better use a hash_map or unordered_map: it just matches your requirements better (you don't need to order the players by id after all, you just want to find them quickly) and will probably be faster given the number of players.
For managing the top20 you have 2 choices:
You could use the Boost.MultiIndex library to create one unique container that both offers fast lookup on ID (using a hash map) and an ordered index on the score... however it's a bit of a waste to order all players when you only need 20 of them
You can simply manages a separate structure, like a vector of pointers to users, and each time you modify the score of a user check it should replace a user in the vector
The last solution, though simple, assumes that a player cannot lose points... it's much more difficult if that may happen.
class UsersCollection;
class User
{
public:
void incrementScore(size_t term);
private:
size_t mId;
size_t mScore;
UsersCollection& mCollection;
};
class UsersCollection
{
public:
static const size_t MNumberHiScores = 20;
static const size_t MNotAChampion = -1;
UsersCollection(DBConnection const&);
// returns either the position of the user in
// the hi scores vector or MNotAChampion
size_t insertUserInHiScores(User const& user);
private:
std::unordered_map<size_t, User> mUsers;
std::vector<User const*> mHiScores; // [1]
};
void User::incrementScore(size_t term)
{
mScore += term;
mCollection.insertUserInHiScores(*this);
}
struct UserSort: std::binary_function<User const*, User const*, bool>
{
bool operator()(User const* lhs, User const* rhs) const
{
return lhs->score() > rhs->score();
}
};
size_t UsersCollection::insertUserInHiScores(User const& user)
{
std::vector<User const*>::const_iterator it =
std::find(mHiScores.begin(), mHiScores.end(), &user);
if (it == mHiScores.end()) // not among the hiscores
{
mHiScores.push_back(&user);
}
std::sort(mHiScores.begin(), mHiScores.end(), UserSort());
if (mHiScores.size() > MNumberHiScores) // purge if too many users
{
User const* last = mHiScores.back();
mHiScores.pop_back();
if (&user == last) return MNotAChampion;
}
// return position in the vector in the [0, MNumberHiScores) range
return std::find(mHiScores.begin(), mHiScores.end(), &user)
- mHiScores.begin();
}
Note (1): using a set may seem a good idea however a set presumes that the elements do not change and it is not the case. It could work if we were very careful:
remove the user from the set before changing the score
putting the user back in once it has changed
optionally popping the last elements if there are too many of them