C++, how to change class of object in runtime.

August 12, 2010

Filed under: How-to, Source code — Andrew @ 4:06 pm

There is a nice feature in TIScript that allows to change class of already instantiated object.
Let’s say we have two classes:

class MyWidget : Behavior { ... }
class MyWidgetReadonly : Behavior { ... }

that handle user interaction with some widget on the screen. This widget can operate in two distinct modes: normal and read-only.
These modes share the same widget state but have substantially different behavioral characteristic. So it makes sense to split these two sets of methods into two classes to avoid pollution of our code by the crowd of if(readonly) ... else ....
When needed we can switch class of the object like this:

var widget = new MyWidget();
....
if( needReadOnlyMode )
  widget.prototype = MyWidgetReadonly; // changing class of the object.
...

Pretty much all dynamic languages allow to do such things. E.g. in Python you can modify obj.__bases__.

Surprisingly you can do the same in C++ too and without any “hack”. We can use so called placement new operator to do the trick. Here is how.

Let’s define our class hierarchy as this:

class MyWidget
{
public:
  int data;  // state variables here
  virtual void on_mouse() { printf("normal on_mouse, data=%d\n",data); }
  virtual void on_key() { printf("normal on_key\n"); }
};
class MyWidgetReadOnly: public MyWidget
{
  // no data at all here, sic!
  virtual void on_mouse() { printf("read-only on_mouse, data=%d\n",data); }
  virtual void on_key() { printf("read-only on_key\n"); }
};

And we will switch class of our object using this helper template function:

// turn_to(A* obj) changes class of the object
// that means it just replaces VTBL of the object by VTBL of another class.
// NOTE: these two classes has to be ABI compatible!
template <typename TO_T, typename FROM_T>
  inline void turn_to(FROM_T* p)
  {
    assert( sizeof(FROM_T) == sizeof(TO_T));
    ::new(p) TO_T(); // use of placement new
  }

Note: This will work if our class has default constructor that does not initialize any member variables.

Let’s try this small sample ( test.cpp ):

#include <new>
#include <assert.h>
// turn_to(A* obj) changes class of the object
// that means it just replaces VTBL of the object by VTBL of another class.
// NOTE: these two classes has to be ABI compatible!
template <typename TO_T, typename FROM_T>
  inline void turn_to(FROM_T* p)
  {
    assert( sizeof(FROM_T) == sizeof(TO_T));
    ::new(p) TO_T(); // use of placement new
  }

class MyWidget
{
public:
  int data;  // state variables here
  virtual void on_mouse() { printf("normal on_mouse, data=%d\n",data); }
  virtual void on_key() { printf("normal on_key\n"); }
};
class MyWidgetReadOnly: public MyWidget
{
  // no data at all here, sic!
  virtual void on_mouse() { printf("read-only on_mouse, data=%d\n",data); }
  virtual void on_key() { printf("read-only on_key\n"); }
};

int main(int argc, char* argv[])
{
  MyWidget *w = new MyWidget();
  w->data = 123;
  w->on_mouse();
  turn_to<MyWidgetReadOnly>(w); // turning the instance to MyWidgetReadOnly class.
  w->on_mouse();
	return 0;
}

After compiling and running it we should see in console output like this:

normal on_mouse, data=123
read-only on_mouse, data=123

So it works – we are able to transform existing instance of some class to the instance of other class.

DISCLAIMER:

Be warned that this is a Jedi Sword feature. Use it responsibly, only if you know why you need it. And what are the consequences. Even mentioning of this approach in some software development companies (that usually are on the Dark Side) may damage your reputation.

Generators in C++ revisited.

June 25, 2008

Filed under: Philosophy, Source code — Andrew @ 6:09 pm

Previous version of generators had design problem – it required some special stop value. That is the same kind of problem as with iterators in C++. In some cases it is not possible to choose such a value.

So is this new version:


// generator/continuation for C++
// author: Andrew Fedoniouk @ terrainformatica.com
// idea borrowed from: "coroutines in C" Simon Tatham,
//                     http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html

  //++ coroutine, generator, continuation for C++

  struct _generator
  {
    int _line;
    _generator():_line(-1) {}
  };

  #define $generator(NAME) struct NAME : public _generator

  #define $emit(T) bool operator()(T& _rv) { \
                      if(_line < 0) { _line=0;}\
                      switch(_line) { case 0:;

  #define $stop  } _line = 0; return false; }

  #define $yield(V)     \
          do {\
              _line=__LINE__;\
              _rv = (V); return true; case __LINE__:;\
          } while (0)

  //-- coroutine, generator, continuation for C++

Implementation of typical iterator practically is the same an in previous version except of $stop is being used without any parameter now:

#include "generator.h"

$generator(descent)
{
   int i;
   $emit(int) // will emit int values. Start of body of the generator.
      for (i = 10; i > 0; i–)
         $yield(i); // a.k.a. yield in Python,
                      // returns next number in [1..10], reversed.
   $stop; // stop, end of sequence. End of body of the generator.
};

But its usage is a bit different and is close to JavaScript for(var in sequence) statement:

int main(int argc, char* argv[])
{
  descent gen;
  for(int n; gen(n);) // "get next" generator invocation
    printf("next number is %d\n", n);
  return 0;
}

And here is version of the generator that supports restart (recursive call) - needed for walking through tree alike (recursive) data structures. It uses allocations on the heap that I think is overkill for such constructions.

Generators in C++

May 26, 2008

Filed under: Source code — Andrew @ 6:19 pm

As we know iterators in C++ is a good but not perfect abstraction. Concept of foreach() (D, Python, Ruby, etc.) appears as more generic solution. At least foreach() does not require artificial iterator::end() to be defined for the collection.

Abstraction foreach() can be imagined as some function/object that is returning next value of collection/sequence each time it is getting invoked. Such functions are known as generators.

Here is my version of generator() for the C++. It is based on the bright idea of Simon Tatham – “coroutines in C“.

First of all sample, here is a declaration of our generator function in C++:

#include "generator.h"

generator(descent)
{
   int i;
   emit(int) // will emit int values. Start of body of the generator.
      for (i = 10; i > 0; i--)
         yield(i); // a.k.a. yield in Python - return next number in [1..10], reversed.
   stop(0); // stop, end of sequence. End of body of the generator.
};

Having declared such generator we can use it as:

int main(int argc, char* argv[])
{
  descent gen;
  do
    printf("next number is %d\n", gen());
  while (gen);
  return 0;
}

That is pretty simple and should be intuitively clear, no?

Here is full source of the generator.h file:

// generator/continuation for C++
// author: Andrew Fedoniouk @ terrainformatica.com
// idea borrowed from: "coroutines in C" Simon Tatham,
//                     http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html

#ifndef __generator_h_
#define __generator_h_

struct _generator
{
  int _line;
  _generator():_line(-1) {}
  operator bool() const { return _line != 0; }
};

#define generator(NAME) struct NAME : public _generator

#define emit(T)     T operator()() { \
                     if(_line < 0) { _line=0;}\
                     switch(_line) { case 0:;

#define stop(V)     } _line = 0; return (V); }

#define yield(V)     \
        do {\
            _line=__LINE__;\
            return (V); case __LINE__:;\
        } while (0)

#endif // __generator_h_

Enjoy!

JavaScript. Private members (instance variables).

March 13, 2008

Filed under: Sciter, Script, Source code, Web Application Techologies — Andrew @ 1:28 pm

As you know JavaScript has no concept of private members in objects. Objects there are “racks of properties” that anyone can change.

Here is a simple way of making “objects” in JS that have private instance variables. Such variables can be changed only by [public] methods you provide.

Consider following code:

  function CreateMyObject()
  {
    var m_first = 0;
    var m_second = 0;

    var envelope = // our public interface
    {
        getFirst: function() { return m_first; },
        setFirst: function(v) { m_first = v; },
        getSecond: function() { return m_second; },
        setSecond: function(v) { m_second = v; }
    };
    return envelope;
  }  

  var f = CreateMyObject();

  var n = f.getFirst(); // calling our methods

Here we have CreateMyObject() that behaves as a constructor of our object. It returns envelope object that has four methods. Only these methods can update or retrieve state of m_first and m_second variables. There are literally no other ways to access them from anywhere else other than set of methods provided.

Under the hood: In this example each interface method that we’ve created is a closure in fact: such methods have access to environment of outer function (CreateMyObject in this case) so they can access variables in this environment. Making a closure can be a memory expensive operation so avoid their use when you expect many instances of such objects.

Sciter. Working with persistent data (database)

March 2, 2008

Filed under: Sciter, Script, Source code, Web Application Techologies — Andrew @ 9:08 pm

Here is an example of minimalistic application working with DB (persistent data) in Sciter.

Screenshot of DB form.

This sample is using three files:

  1. simple-db-form.htm – main file of our application;
  2. db.tis – open or create database;
  3. form.tis – behavior that handles showing/saving data from list of input elements on the form.

db.tis – open or create database

This file contains single procedure that will open or create new storage if does not exist:

function openDatabase(pathname = "records.db")
{
  var ndb = Storage.open(pathname);
  if(!ndb.root)
  {
    // new db, initialize structure
    ndb.root =
      { // root of our db is an object having single field 'records'
        records: ndb.createIndex(#integer) // main index, int -> item
      };
  }
  return ndb;
}

Structure of our storage is simple – its root node contains single field records of type Index. In our example this index maps integer – number of the record to the record itself – object that may have arbitrary structure.

form.tis – showing/saving data from input elements on a form

// Form handler class
type Form: Behavior
{
  function show(rec)
  {
    if(this.shown) this.save(); // save previously shown record.
    this.shown = rec;
    function load_value(el)
    {
      var name = el.attributes#name;
      el.value = rec[symbol(name)];
    }
    this.select(load_value, "[name]");
    // call load_value for each element having "name" defined.
    // De facto this means that form content defines structure of the record.
  }
  function save()
  {
    var shown = this.shown;
    function store_value(el)
    {
      var name = el.attributes#name;
      shown[symbol(name)] = el.value;
    }
    this.select(store_value, "[name]");
    // call store_value for each element having "name" defined.
  }
}

This behavior class has two methods:

  • show(rec) – show fields of object rec in fields of the form and
  • save() – stores content of input elements of the form in fields of last shown rec object

simple-db-form.htm – main file of our application

And last part is our main file that defines UI layout and assembles all parts together:

<html>
<head>
  <style>
    form#record
    {
      prototype:Form;
    }
    ...
  </style>
  <script type="text/tiscript">
    include "form.tis";
    include "db.tis";

    var form = self.select("form#record");
    var rec_no = self.select("#rec-no");

    var db = openDatabase();
    var no = 0;

    function gotoRecNo( n )
    {
      no = n;
      if( no < 0 ) no = 0;
      else if( no >= db.root.records.length ) no = db.root.records.length - 1;
      form.show( db.root.records[no] );
      rec_no.text = String.printf("%d of %d", no, db.root.records.length); rec_no.update();
    }

    function gotoNewRecord()
    {
      // create new record
      var newidx = db.root.records.length;
      db.root.records[ newidx ] = { first:0, second:"", third:"<html><\/html>" };
      gotoRecNo(newidx);
    }

    // handlers of navigatonal buttons
    function self #first .onClick() { gotoRecNo(0); }
    function self #prev  .onClick() { gotoRecNo(no - 1); }
    function self #next  .onClick() { gotoRecNo(no + 1); }
    function self #last  .onClick() { gotoRecNo(db.root.records.length - 1); }
    function self #new   .onClick() { gotoNewRecord(); }

    function view.onLoad()   { if(db.root.records.length) gotoRecNo(0);
                                        else gotoNewRecord(); }
    function view.onUnload() { form.save(); db.close(); }

  </script>
<head>
<body>
  <h1>Simple DB form</h1>
  <form #record>
    <table>
      <tr><td>First (number)</td><td><input name="first" type="number"/></td></tr>
      <tr><td>Second (text)</td><td><input name="second" type="text"/></td></tr>
      <tr><td>Third (richtext(html))</td><td><richtext name="third" /></td></tr>
    </table>
  </form>
  <div #nav>
    <button #first title="to first record">|<</button>
    <button #prev title="to prev record"><</button>
    <button #next title="to next record">></button>
    <button #last title="to last record">>|</button>
    <button #new title="create new record">new</button>
    record: <span #rec-no>?</span>
  </div>
</body>
</html>

Done. We have simple form that allows us to create records with text, numeric and richtext (html) fields.


Code above is not the best one from architectural point of view – its goal is to show basic principles, not more.
You can find this sample in [Sciter SDK]/samples/ideas/db/ folder.

XML/HTML tokenizer (or pull parser?)

October 7, 2007

Filed under: Source code — Andrew @ 11:19 pm

Here is source code of my XML/HTML tokenizer: xh_scanner_demo.zip

See my article on CodeProject: HTML/XML scanner/tokenizer

Does not allocate any memory while parsing, extremely fast and compact.