static void zend_generator_add_child(zend_generator *generator, zend_generator *child)
{
	zend_generator *leaf = child->node.children ? child->node.ptr.leaf : child;
	zend_generator_node *multi_children_node;
	zend_bool was_leaf = generator->node.children == 0;

	if (was_leaf) {
		zend_generator *next = generator->node.parent;
		leaf->node.ptr.root = generator->node.ptr.root;
		++GC_REFCOUNT(&generator->std); /* we need to increment the generator refcount here as it became integrated into the tree (no leaf), but we must not increment the refcount of the *whole* path in tree */
		generator->node.ptr.leaf = leaf;

		while (next) {
			if (next->node.children > 1) {
				if (next->node.children > 4) {
					zend_generator *child = zend_hash_index_find_ptr(&next->node.child.ht, (zend_ulong) generator);
					zend_hash_index_del(&next->node.child.ht, (zend_ulong) generator);
					zend_hash_index_add_ptr(&next->node.child.ht, (zend_ulong) leaf, child);
				} else {
					switch (next->node.children) {
#define ZEND_GEN_UPDATE_CHILD(x) \
							if (next->node.child.array[x].leaf == generator) { \
								next->node.child.array[x].leaf = leaf; \
								break; \
							}
						case 4:
							ZEND_GEN_UPDATE_CHILD(3)
						case 3:
							ZEND_GEN_UPDATE_CHILD(2)
						case 2:
							ZEND_GEN_UPDATE_CHILD(1)
							ZEND_GEN_UPDATE_CHILD(0)
							ZEND_ASSERT(0); // we never should have no matching child
					}
				}
			}

			next->node.ptr.leaf = leaf;
			next = next->node.parent;
		}

		zend_generator_add_single_child(&generator->node, child, leaf);
	} else if (generator->node.children == 1) {
		multi_children_node = zend_generator_search_multi_children_node(&generator->node);
		if (multi_children_node) {
			generator->node.children = 0;
			zend_generator_merge_child_nodes(&generator->node, multi_children_node, generator->node.child.array[0].child);
		}
	}

	if (!was_leaf) {
		multi_children_node = zend_generator_search_multi_children_node(&child->node);
	} else {
		multi_children_node = (zend_generator_node *) 0x1;
	}

	{
		zend_generator *parent = generator->node.parent, *cur = generator;

		if (multi_children_node > (zend_generator_node *) 0x1) {
			zend_generator_merge_child_nodes(&generator->node, multi_children_node, child);
		} else {
			zend_generator_add_single_child(&generator->node, child, leaf);
		}
		while (parent) {
			if (parent->node.children > 1) {
				if (multi_children_node == (zend_generator_node *) 0x1) {
					multi_children_node = zend_generator_search_multi_children_node(&child->node);
				}
				if (multi_children_node) {
					zend_generator_merge_child_nodes(&parent->node, multi_children_node, cur);
				} else {
					zend_generator_add_single_child(&parent->node, cur, leaf);
				}
			}
			cur = parent;
			parent = parent->node.parent;
		}
	}
}
static void zend_generator_add_child(zend_generator *generator, zend_generator *child)
{
	zend_generator *leaf = child->node.children ? child->node.ptr.leaf : child;
	zend_generator_node *multi_children_node;
	zend_bool was_leaf = generator->node.children == 0;

	if (was_leaf) {
		zend_generator *next = generator->node.parent;
		leaf->node.ptr.root = generator->node.ptr.root;
		++GC_REFCOUNT(&generator->std);  
		generator->node.ptr.leaf = leaf;

		while (next) {
			if (next->node.children > 1) {
				if (next->node.children > 4) {
					zend_generator *child = zend_hash_index_find_ptr(&next->node.child.ht, (zend_ulong) generator);
					zend_hash_index_del(&next->node.child.ht, (zend_ulong) generator);
					zend_hash_index_add_ptr(&next->node.child.ht, (zend_ulong) leaf, child);
				} else {
					switch (next->node.children) {
#define ZEND_GEN_UPDATE_CHILD(x) \
							if (next->node.child.array[x].leaf == generator) { \
								next->node.child.array[x].leaf = leaf; \
								break; \
							}
						case 4:
							ZEND_GEN_UPDATE_CHILD(3)
						case 3:
							ZEND_GEN_UPDATE_CHILD(2)
						case 2:
							ZEND_GEN_UPDATE_CHILD(1)
							ZEND_GEN_UPDATE_CHILD(0)
							ZEND_ASSERT(0);  
					}
				}
			}

			next->node.ptr.leaf = leaf;
			next = next->node.parent;
		}

		zend_generator_add_single_child(&generator->node, child, leaf);
	} else if (generator->node.children == 1) {
		multi_children_node = zend_generator_search_multi_children_node(&generator->node);
		if (multi_children_node) {
			generator->node.children = 0;
			zend_generator_merge_child_nodes(&generator->node, multi_children_node, generator->node.child.array[0].child);
		}
	}

	if (!was_leaf) {
		multi_children_node = zend_generator_search_multi_children_node(&child->node);
	} else {
		multi_children_node = (zend_generator_node *) 0x1;
	}

	{
		zend_generator *parent = generator->node.parent, *cur = generator;

		if (multi_children_node > (zend_generator_node *) 0x1) {
			zend_generator_merge_child_nodes(&generator->node, multi_children_node, child);
		} else {
			zend_generator_add_single_child(&generator->node, child, leaf);
		}
		while (parent) {
			if (parent->node.children > 1) {
				if (multi_children_node == (zend_generator_node *) 0x1) {
					multi_children_node = zend_generator_search_multi_children_node(&child->node);
				}
				if (multi_children_node) {
					zend_generator_merge_child_nodes(&parent->node, multi_children_node, cur);
				} else {
					zend_generator_add_single_child(&parent->node, cur, leaf);
				}
			}
			cur = parent;
			parent = parent->node.parent;
		}
	}
}