Friday, May 6, 2022

The State Design pattern in C++ using timer and notification






As a #guru, let me pay my respects today to my #guru in the tech world, who has influenced my technical skills and mindset.

Although I have never seen them, nor do they know I exist.

But I am grateful to them - and because of them, I have at last become an engineer in the true sense.

First guru: The authors of The Gang of Four Design Pattern Book

Second Guru: Linus Torvalds for offering Linux and rather helping me come out of the vicious cycle of windows

Third Guru: The Android creator and Google for showing me the different nitty-gritty of a complicated framework that i learnt through delving into the Android framework code

Fourth Guru: A professor of a USA University by the name Doug, from whom I got insights of how to study the Android OS difficult parts of the code like the AsyncTask Framework, and he showed  me the right approach of taking the OS study from an engineer’s perspective - delving into the difficult concurrent framework of the Android OS

And my all-time Guru: My family for giving me a sweet, caring, loving #home and my only son, #ridit, for becoming my best student from his early childhood. He is still driving me to burn the midnight oil in front of the laptop to explore the deep ocean of Computer science.

And I am sure, the way the whole professional world of technology is moving, very soon somebody will have to dismiss the book called

#theworldisflat  - The World Is Flat

and write a new one 

#theflatistheworld - The Flat Is The World


Now let's come back to the subject. Let's discuss the technical side of the State Design Pattern.

The state design pattern is a powerful tool in software design, allowing you to encapsulate an object's behavior based on its internal state.

The main participants in this design pattern are:

Context: This object represents the entire entity experiencing state changes. It holds a reference to the current state object and exposes an interface for external interaction.

State: These are concrete classes representing each possible state the object can be in. Each state class defines its own behavior for responding to events and transitions.

Transitions: These define how the object can move from one state to another. They can be triggered by events, user actions, or internal conditions.

In my example, I have cited the process of cooking chicken - how the chicken states alter from an uncleaned state to a cleaned state to a marinated state to a cooked state and finally served to the guests.

Here is the class diagram of the design pattern...


Runtime Behaviour

The runtime interaction follows these steps:

  1. The application creates the Context.
  2. The Context delegates execution to the current State.
  3. The State starts a Timer.
  4. The Timer expires.
  5. The Timer invokes the notification callback.
  6. The callback requests the Context to change its current State.
  7. The Context delegates subsequent operations to the new State.

The source code...

Callback.h

#ifndef CALLBACK_H_

#define CALLBACK_H_


class Callback {

public:

virtual void goToNextStateFromCallback() = 0;

virtual ~Callback() = default;

};


#endif



ChickenState.h

#ifndef CHICKENSTATE_H_

#define CHICKENSTATE_H_


#include <string>


class ChickenState {

public:

virtual ~ChickenState() = default;

virtual void wash(int period, int totalTime) {}

virtual void marinate(int period, int totalTime) {}

virtual void cook(int period, int totalTime) {}

virtual void serve(int period, int totalTime) {}

virtual void goToNextState() = 0;

virtual std::string getTag() const = 0;

};


#endif



UncleanedState.h

#ifndef UNCLEANEDSTATE_H_

#define UNCLEANEDSTATE_H_


#include "ChickenState.h"

#include "Mamma.h"

#include "CleanedState.h"

#include <iostream>


class UncleanedState : public ChickenState {

private:

Mamma* mamma;

std::string tag = "Uncleaned";


public:

UncleanedState(Mamma* ctx) : mamma(ctx) {}


void wash(int period, int totalTime) override {

std::cout << "[Uncleaned] Chicken is getting washed... please wait...\n";

mamma->t.setTimeout([this]() {

mamma->goToNextStateFromCallback();

}, totalTime);

}


void goToNextState() override {

mamma->isUncleanedStateDone = true;

mamma->changeChickenState(std::make_unique<CleanedState>(mamma));

}


std::string getTag() const override { return tag; }

};


#endif


CleanedState.h

#ifndef CLEANEDSTATE_H_

#define CLEANEDSTATE_H_


#include "ChickenState.h"

#include "Mamma.h"

#include "MarinatedState.h"

#include <iostream>


class CleanedState : public ChickenState {

private:

Mamma* mamma;

std::string tag = "Cleaned";


public:

CleanedState(Mamma* ctx) : mamma(ctx) {}


void marinate(int period, int totalTime) override {

std::cout << "[Cleaned] Chicken is getting marinated... please wait...\n";

mamma->t.setTimeout([this]() {

mamma->goToNextStateFromCallback();

}, totalTime);

}


void goToNextState() override {

mamma->isCleanedStateDone = true;

mamma->changeChickenState(std::make_unique<MarinatedState>(mamma));

}


std::string getTag() const override { return tag; }

};


#endif


MarinatedState.h

#ifndef MARINATEDSTATE_H_

#define MARINATEDSTATE_H_


#include "ChickenState.h"

#include "Mamma.h"

#include "CookedState.h"

#include <iostream>


class MarinatedState : public ChickenState {

private:

Mamma* mamma;

std::string tag = "Marinated";


public:

MarinatedState(Mamma* ctx) : mamma(ctx) {}


void cook(int period, int totalTime) override {

std::cout << "[Marinated] Chicken is getting cooked... please wait...\n";

mamma->t.setTimeout([this]() {

mamma->goToNextStateFromCallback();

}, totalTime);

}


void goToNextState() override {

mamma->isMarinatedStateDone = true;

mamma->changeChickenState(std::make_unique<CookedState>(mamma));

}


std::string getTag() const override { return tag; }

};


#endif


CookedState.h

#ifndef COOKEDSTATE_H_

#define COOKEDSTATE_H_


#include "ChickenState.h"

#include "Mamma.h"

#include <iostream>


class CookedState : public ChickenState {

private:

Mamma* mamma;

std::string tag = "Cooked";


public:

CookedState(Mamma* ctx) : mamma(ctx) {}


void serve(int period, int totalTime) override {

std::cout << "[Cooked] Chicken is ready! Enjoy the delicious Ajwaini Chicken!\n";

mamma->isCookedStateDone = true;

mamma->timerRunning = false; // Break the execution loop

}


void goToNextState() override {}

std::string getTag() const override { return tag; }

};


#endif





Mamma.h

#ifndef MAMMA_H_

#define MAMMA_H_


#include <memory>

#include <atomic>

#include "Callback.h"

#include "ChickenState.h"

#include "timer.h"


class Mamma : public Callback {

private:

std::unique_ptr<ChickenState> currentState;


public:

Timer t;

std::atomic<bool> timerRunning{true};


// Flags tracking state milestones safely

std::atomic<bool> isUncleanedStateDone{false};

std::atomic<bool> isCleanedStateDone{false};

std::atomic<bool> isMarinatedStateDone{false};

std::atomic<bool> isCookedStateDone{false};


Mamma();

~Mamma() override = default;


void changeChickenState(std::unique_ptr<ChickenState> nextState);

void startPreparation();

void goToNextStateFromCallback() override;


ChickenState* getCurrentState() { return currentState.get(); }

};


#endif


Mamma.cpp

#include "Mamma.h"

#include "UncleanedState.h"

#include "CleanedState.h"

#include "MarinatedState.h"

#include "CookedState.h"

#include <iostream>


Mamma::Mamma() {

t.setCallback(this);

// Initialize with the starting state

currentState = std::make_unique<UncleanedState>(this);

}


void Mamma::changeChickenState(std::unique_ptr<ChickenState> nextState) {

currentState = std::move(nextState);

}


void Mamma::startPreparation() {

while (timerRunning) {

if (!isUncleanedStateDone) {

currentState->wash(1000, 1500);

} else if (!isCleanedStateDone) {

currentState->marinate(1000, 1500);

} else if (!isMarinatedStateDone) {

currentState->cook(200, 2000);

} else if (!isCookedStateDone) {

currentState->serve(200, 1000);

}

}

std::cout << "Mamma - the cook is leaving the kitchen.\n";

}


void Mamma::goToNextStateFromCallback() {

t.justStop();

currentState->goToNextState();

}





Timer.h

#ifndef TIMER_H_

#define TIMER_H_


#include <thread>

#include <chrono>

#include <atomic>

#include "Callback.h"


class Timer {

private:

Callback* cb = nullptr;

std::atomic<bool> active{true};


public:

Timer() = default;


void setCallback(Callback* callback) {

cb = callback;

}


void setTimeout(auto function, int delay) {

active = true;

std::thread t([this, function, delay]() {

if (!active.load()) return;

std::this_thread::sleep_for(std::chrono::milliseconds(delay));

if (!active.load()) return;

function();

});

t.join(); // Blocks parent execution sequentially per step

}


void stop() {

if (cb) cb->goToNextStateFromCallback();

}


void justStop() {

active = false;

}

};


#endif


Main.cpp


//============================================================================

// Name : Main.cpp

// Author : Som

// Version :

// Copyright : som-itsolutions

// Description : Hello World in C++, Ansi-style

//============================================================================


#include "Mamma.h"


int main() {

auto mamma = std::make_unique<Mamma>();

mamma->startPreparation();

return 0;

}


To compile the above code, we need to activate the -pthread option for the compiler and linker.


Enjoy...


Wednesday, March 30, 2022

Logic vs Imagination...

 



To start this topic, I can quote Einstein and many such great people to raise the standard. However, as I see myself just as a pure worker, the #karmyogi, for whom working with sweat and blood, having scars are real marks of a leader, i will tell you about how the fake world of fashionable leadership camouflage and stop the real imagination power of the real engineers to run their agenda and create a flock of sheep instead of a pride of lions in the tech world.


We should strive for 


#passion…


not…


#fashion…


Please closely observe a few so-called highly paid, dashing personalities in various professions, like medicine, software consultancy, and see how they earn money by stopping others from imagining and asking them just to be satisfied with foolish logic.


I will give you an example.


When you attend a very important tech meeting in a big MNC, meeting, you will find some of the smartest people use their charisma to first dig out problems in the system.


There is a flaw in the design….


and then he will start drawing some esoteric diagrams describing the flaw.


and then the discussion continues for hours after hours, months after months.


new recruitment. new joiners. and then training them specifically on that flaw.


the hourly bill of the consultant will be rising


In #bharat, we say it like aapka meter charne laga


A new #gillbates is born.


On the contrary, Linus Torvalds sir will continue writing high-class code in his bath-rope.


there are few #fools like me who will adore Linus Torvalds sir maybe sometimes because of his such attire and sometimes maybe by remembering his own hostel days and training his son to use Linux


In the corporate world, the new Windows11 will be launched with a little bit of flavor of Linux in it


but don't try to add any extra xxx after the Linux used there


because #kids must be protected


too much xxx may damage their real #manhood


The first sign of a boy attaining manhood with nightfall happens through imagination, not logic..


So cut the crap from your kid's life


let him imagine and enjoy…


There is life beyond algorithms and logic...

Monday, February 28, 2022

Let's remove the prawnheads from top technical positions of Bharat...

Please have a look at my Android app which is a kind of training for a Call Setup process from a GSM to a PSTN.

https://play.google.com/store/apps/details?id=appinventor.ai_som_mukhopadhyay.GSMCallSetupMSToPSTN&hl=en-GB

I have thought about my life, my changed personality from a curious self-driven student, a carefree guy who was really capable of thinking on his own to an asshole, after I was admitted to the engineering college and left my small town at one of the most backward districts called #purulia and hence I am sure it was not exactly the plan of #lordshiva who, I am sure would not have done such a cruel thing to a nice fellow, but maybe some #prawnhead, and #dickhead people of #bharat who were considered to be the smartest people because they were being "pushed" to hold responsible position without #accountability. And then whatever happened to my life after the engineering in the guise of experience was nothing but some sort of #timepass for me and the reason was not exactly to #uplift, to #elevate a #poor fellow like me with big dreams in his eyes to serve his #nation as projected by those big #corporate house, but for serving their own purpose because of #lust for #money and nothing else.

Hence I have decided to discard everything that has happened to me after 10+2 from my #linkedinprofile and made it barebone as I was in my 10+2 version considering these were just #junkjewellary to drag an intelligent boy behind.

Here I am challenging all those #dickhead people who worked behind this ghastly plan, to come out of their hiding and masks and face me with whatever skills they have achieved so far and prove that they are worthy to be called anything other than just #prawnhead of #bharat - the real people dragging the process of development of this great nation. 

Here is my middle finger to all those #prawnheads of #bharat

You cannot defeat a person whose #lordshiva is now guiding him.

accept the challenge and showcase your skills.

#performorperish

aa dekhe jara, kisme kitna hain dum…

And towards the end of this discussion, let me add that after I showed my real, nasty, raw, beastly power in the big meeting room of a #Fortune25 company when I blasted the General Manager saying …” We cannot offer any bullshit to the customers…. If you really want to prepare your engineers as future technical leaders, train them well with real technologies and don’t treat your job as a mere #timepass” and then came out of that company, and joined the software industry with no knowledge and suffered a lot, struggled a lot owing to several real-life problems of the software industry, went down with deep depression and all sorts of mental trauma, but I own up to that decision. And today I am proudly announcing that in spite of many issues, i have become a knowledgeable software engineer, left the world of Microsoft forever, embraced Linux and Open source software, even left Github after it was taken over by Microsoft and instead embraced Gitlab and pushed myself towards the open-source world to learn real software. And when my dream of learning real technologies behind the great #telecommunication world through whatever ways possible was shattered because of your #timepass management, I was still able to learn it - although not i exactly the kind of Telecommunication Switching Software or anything as such, but through my ways in the future #avatar in which the telecom world was transformed from more of a telecom centric world to the mobile app-centric world.

And I became capable of using my software knowledge to create real values to even the telecommunication world by explaining the knowledge I was expecting to gain from that fortune25 company, absolutely on my own.

Please have a look at this app which I created quite sometimes back to showcase that a person, when guided by his #lordshiva can really take up any challenges of professional life gracefully and maybe still enjoys the journey…