This adds two data structures that wrap a node tree. However, they work on different abstraction levels.
NodeTreeRef is in immutable structure that makes working with a node tree in C++ much more efficient
and convenient. It supports various efficient queries that are not easily possible using just bNodeTree (see comment in code).
DerivedNodeTree builds on top of NodeTreeRef. It contains a flattened view on the node tree,
i.e. with node groups being inlined. However, every inlined node still knows its "call stack".
It supports pretty much the same queries as NodeTreeRef.
Maybe DerivedNodeTree should have a different name. Over the course of the last year, I had various names
for it, including VirtualNodeTree and InlinedNodeTree. The difficulty here is that there are related
names like DSocket, DNode and more. There needs to be some connection between these names and the name
of the node tree class. Also the name should not be unnecessarily long, as this would make them quite annoying
to use in some contexts.
The name also depends a bit on the scope for DerivedNodeTree. Currently, it has the features that I needed
for particle nodes in the functions branch. However, if we want to use that structure for other node tree
types later on, the requirements might be slightly different. If we decide that this structure should just
be used for simulation node trees, we can also call it SimulationNodeTree (with SNode, SSocket, ...).
For both data structures there are dot graph exporters for debugging purposes.
Both also assign ids to nodes and sockets. Those can often be used to as index into an array instead of having
to has a hash table.