Friday, August 16, 2024

An overview of my DataObj program.

 DataObj really is a beautiful piece of code. I forgot how good it since I last looked at it. The project is located here.

It is based on cooperative multitasking where any one function call tries to return as quickly as possible. You don't wait for file or network ports, you get a callback when there is data ready for your function. I even have callbacks for dns calls to get ip addresses from host names. And these lookups are cached.  When you do it right almost nothing is faster than cooperative multitasking.

This is the space on disk the entire framework and libframework.so files take up.  Less than 140KB.  And the entire program compresses down to just  34KB.  Each widget should just be a few KB as well. So they should load fast. 


This is the main section of the framework.  It is just a small shim on top of the raw parts and pieces of libframework.so to define the behaviors and create an environment.  Eventually I want to be able to load and save environments as compressed xml files in this shim.  But that means that you can build any kind of program you want with libframework.so. 

I don't want to add much more functionality to the program directly.  That is why I am creating the object interface.  I want to add features in the future by creating objects and perform things like loading compressed xml using a file reading object that sends its output to a decompression object and then to an xml parser that generates a node representation of the xml file.  If I do it right I can just run main from the node I loaded off disk. 

If you notice, the task list and the Main node are the only variables used by the lower level code.  That means you could load in a dozen different environments at the same time each performing cooperative tasks concurrently. And you could run each of these environments in different threads to take full advantage of 36 threads, if your CPU supports that many.  This is one of the features I will be working on eventually. 


This is the main.c program that becomes framework and loads libframework.so. 
You can see the main loop at the top of it.  All the message passing between everything happens in this loop.  It delivers data as messages to instances function calls, and those functions process that data and send more messages.  Those messages are added to the end of the list of messages to deliver.  You can also schedule messages to be delivered later, that makes it easy rate limit file and network objects and it is trivial to create a pulse generator in just a few lines of code.

This is the main function. It is so clean and clear that it doesn't even look like C code. 


The last feature I want to discuss is the DataObj variable type.  Any variable is a string, int, hex, and float value and the system converts between these types automagically.  This broke when we went to 64 bit machines, and an AI helped direct me to fix it.  It was beyond my skills for over a decade to make it work again. 

The conversions are automatic and it keeps track of the first value set and converts from that to the other types and caches that value if anything else needs the conversion.  This is an example of the conversions from the unit test for the data library. 


But I didn't stop there. I used this DataObj data structure to build a full node library that can store any kind of data in any way you want. I can store a simple value, it can store an entire xml or tcl or json document.  

And the way I am going to set things up is that you can transfer these entire documents through the system passing by reference.  I want to make it so that you have to do copy on write to the data structures if you want to modify them. This should help make the code much more thread safe as well.  Plus just passing around copies is fast.  if you just store a reference to the data you could have the same data in 1000 inputs and it wouldn't take up much more than the first copy.

I want to add security and meta data about the messages that an instance can query later.  Wouldn't it be amazing if a network object could just route a response to a query to the proper client by seeing that the message originated from a specific connection?  Or if a security packet could be attached that only allows messages from a source to be delivered to some objects and not others. 


I am finally going to finish this code I started such a long time ago.  :D

No comments:

Post a Comment