0

I have a generic tree implementation written in C++ that can store any type (int, float, string, etc.)

template<class T> class Tree {
public:
// Class interface
private:
T node;
std::list<Tree<T>*>* children;
};

and I have a program (written in C++) that take as input a source tree and give in output another tree based on a set of rules (stored in a file).

Any instance of class A become an instance of class X
Any instance of class B become an instance of class Y
Any instance of class C become an instance of class Z

For example, suppose I have this input tree A(B(C)) (the node A has B as child and B has C as child). Based on the file of rule my program give me this tree X(Y(Z)). My question is: How can I save in a file the set of rules? How can I store the tree type in this file? I'm thinking to use XML for store the rules, like this

<translationUnit>
  <from>
    <A>
      <B>
        <C></C>
      </B>
    </A>
  </from>
  <to>
    <X>
      <Y>
        <Z></Z>
      </Y>
    </X>
  <to>
</translationUnit>

but how can I store the class type?

Peter G.
  • 14,786
  • 7
  • 57
  • 75
WileTheCoyot
  • 513
  • 1
  • 5
  • 20
  • You should be using some serialization library such as Apache thrift or Google Protobuf. But tree as a data type may not be supported and hence you need to work around that. BUT making them work for a template class will be a real problem :( – Nipun Talukdar Feb 23 '14 at 16:42
  • _'I'm thinking to use xml for store the rules but how could i store the class type?'_ As for XML, you'll need to have some kind of discriminator, be it the element name or an enum attibute. BTW, you should consider to use smart pointers instead of `Tree*` et.al. – πάντα ῥεῖ Feb 23 '14 at 16:48
  • Forget storing the rules in a file for a moment. What would you *do* with the rules once you load them from a file? Supposedly you will have some C++ object named "MySetOfRules" or somesuch. How would you use it? Do you have an interface in mind? – n. m. could be an AI Feb 23 '14 at 17:03
  • You could define a serialization protocol (as traits) that types which want to be serialized must implement. – StoryTeller - Unslander Monica Feb 23 '14 at 17:03
  • @πάνταῥεῖ what is a smart pointer? – WileTheCoyot Feb 23 '14 at 17:34
  • @WileTheCoyot Look here: [Dynamic memory management](http://en.cppreference.com/w/cpp/memory) – πάντα ῥεῖ Feb 23 '14 at 17:39

2 Answers2

0

I guess you use pointers for relation between nodes. something like:

class node{
 int value;
 node* first_child;
 node* next_sibling;
};

you can create serialize node with indexes instead of pointers. something like:

class node2{
     int value;
     int id_first_child;
     int id_next_sibling;
};

Now you can flat the tree. means turn it into array.

add all nodes pointers to a vector<node*>, and to a map<node*,int> the map used to translate pointer to the index in the vector.

now write the nodes to the file with indexes instead of pointers.

when you read from the file you need to do it opposite, and translate the indexes to pointers.

SHR
  • 7,940
  • 9
  • 38
  • 57
  • using your solution, how do you convert from pointers to int? do you need to store the map too? Also note that i don't need to store pointers, i can rebuilt the tree when i load the file – WileTheCoyot Feb 23 '14 at 17:08
  • No, trees are not normally stored this way. That would be quite a waste of programmer's effort. Instead, trees are usually stored recursively, for example, as `(root,[child1,child2,...childN])`, where `root` is the value of the root node and `left` and `right` are its children. An empty tree is `()`. This is only an example and the actual format can be almost anything, provided you can distinguish delimiters (parentheses, brackets and commas in this case) from node values. – n. m. could be an AI Feb 23 '14 at 17:13
  • for now i use xml for sav tree since a lot of parser exists but your idea is very good – WileTheCoyot Feb 23 '14 at 17:32
0

For each value in your tree you should associate a type. So each elements in the tree is a pair of the type of the value and the value and a list of children. In your file you have to store this information for each node.

You can consider json to do store the serialized version of your tree, it's easy to read and a lot of good c++ library exist. For instance, the input tree will be :

{ 
     type: "A",
     value: "value of the first node,
     children: [
         {
             type: "B"
             value: "a value ...",
             children: [
                  {
                      type: "C",
                      value: "a value ...",
                  }
             ]
         }
     ]
}

your result will become:

{ 
     type: "X",
     value: "value of the first node,
     children: [
         {
             type: "Y"
             value: "a value ...",
             children: [
                  {
                      type: "Z",
                      value: "a value ...",
                  }
             ]
         }
     ]
}

and in your configuration file you can store each type transformation:

[
     { from: "A", to: "X" },  
     { from: "B", to: "Y" },
     { from: "C", to: "Z" }
]

If you want to store a children of type B inside a Tree of type A, with you interface, A and B should share a base type and you should use pointers to store your node member. If you don't want to manage it manually use a unique_ptr :

unique_ptr<T> node;

After that, you have a pointer to a list of pointer to trees, it's a lot of pointer to manage, if you want to avoid a pointer to a list, you can use boost::container::list which allow containers of incomplete type. After that, you don't need to have a pointer to a tree stored in the list, a Tree value will do the job.

boost::container::list<Tree<T> > children;
pan-
  • 143
  • 9
  • your idea is great, but could you explain me why using unique_ptr and boost list should be better? do your answer work with xml istead of json? – WileTheCoyot Feb 23 '14 at 17:28
  • When I was reading your code, I though that T should be a base type for all your values in your tree otherwise, you tree will only be a tree of T, which mean that a tree of a will not be able to have has children a tree of B. You need a polymorphic type here, if you have a polymorphic type, you should use a pointer, if you have a pointer, unique pointer are great to apply RAII. The boost::container::list is here to avoid a raw pointer to a list. Of course you can use xml instead of json, it's just the serialization format – pan- Feb 23 '14 at 17:30
  • i've accepted your answer not only because is complete but also because you had give me the tips on unique_ptr and boost list – WileTheCoyot Feb 24 '14 at 08:12