C++ making your well written legacy type a bit more usable

So little C++ so much good!

Simple things are simply the most useful things. But one has to be careful not to make them simpler than that.

Not patient? Not a problem. Github repo is here. For the code regarding this post please look into dbj_nifty_store.h

You are a seasoned C++ developer. Your C++ types can be very useful and well written. But they very likely are legacy by now.  that is natural and normal.

For example, your good legacy type (aka class) can not be thread-aware, due to original requirements. That can be a challenge. And this thread-safe requirement can come years down the line. As they usually do.

That class happens to be used elsewhere as it is. Faced with the obvious impossibility to change your type (aka class)  you write wrappers. Like for example, the unfortunate std::any is.  Which you quickly discard, as you are the master of simple, resilient C++. And, on top of that, as many other projects are, you and your team are also not very keen on STL. Even less keen on boost.

Or simply your code has to run in tight environments. IoT for example. Or medical equipment.

In this very likely scenario, I have something for you. The simplest possible type (aka class) that can store a single piece of data.

What is that good for? Why would you need this?

In there is a very simple and very resilient C++. You need to start from somewhere to develop a more complex wrapper for your particular new set of requirements.  Let me rephrase what do we have here:

A single all static type holding a single piece of data, uniquely identifiable and thread resilient.

Catch my drift? This is the core of the modern re-tooling of your legacy class. Usage is deceptively simple.

Single data storage. Simple, small resilient, and fast. Ideal to extend it and add for example “atomicity” or knowledge of persistent storage without changing your original and working legacy type.

Same type many stores

What are those guid_a and guid_b template arguments? They are identity providers. Simple functions returning dbj::GUID.

Remember one store stores only one single piece of data. And that store template definition is a class with only statics inside.  There is no point of creating instances of that. Internally they all will be the same single instance.

To keep the store simple and to differentiate between stores we add the second template argument as the unique identifier.Consider this.

Now using the above I want to have two storages of bool data. How do i do that?

The only way is to add some kind of identification without abandoning the static data concept.

That exactly is the role of second argument in the dbj::data<> template. And since up to C++20 concrete type as an template argument can not be a class we are using function pointers. Hint: see the code.

Thus store_a and store_b above are two distinct types. But providing the same functionality. And the storage wrapper.

The dbj::data<> template when defined is a class that has only one static data member and no methods, ctors or dtors. Thus its moveability and copy ability depends entirely on the moveability and copy the ability of that static value type. Meaning: if your type is well written you will be able to carry around this data wrapper too.

Instance less programing

Did you get carried away? Not checking on me? The template definition is a type. And there is no point in making instances of this type. Everything is static inside.

Thus there is no need for passing instances as e.g. function arguments. It is enough to pass the type only

Above is all zero overhead. As far as the store is concerned.

In the code ( file dbj_nifty_store.h) there is one simple usage example. I have also shown store_silly_user(). It is redundant. Just use the type created by dbj::data<> template definition.

The resilient identification

The dbj::GUID suite will be detailed in the next post.  The testing function is on the bottom of the same header.  I will just mention the unique identification available.

That is not a mockup. That is real UIID aka GUID. The value of that solution will be much more obvious with complex types handled in your complex scenarios. Hint: for example transaction processing.


Caveat Emptor

It is important you have understood this is half advice, half design and half modern C++ code. Oops, three halves?

You will easily add more functionality by adding functions around it, without touching the core template itself.

Github repo is here. It contains also the code from the next post on this GUID used here.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.