Task: Same fringe

C: #include <stdio.h>
#include <stdlib.h>
#include <ucontext.h>

typedef struct {
	ucontext_t caller, callee;
	char stack[8192];
	void *in, *out;
} co_t;

co_t * co_new(void(*f)(), void *data)
{
	co_t * c = malloc(sizeof(*c));
	getcontext(&c->callee);
	c->in = data;

	c->callee.uc_stack.ss_sp = c->stack;
	c->callee.uc_stack.ss_size = sizeof(c->stack);
	c->callee.uc_link = &c->caller;
	makecontext(&c->callee, f, 1, (int)c);

	return c;
}

void co_del(co_t *c)
{
	free(c);
}

inline void
co_yield(co_t *c, void *data)
{
	c->out = data;
	swapcontext(&c->callee, &c->caller);
}

inline void *
co_collect(co_t *c)
{
	c->out = 0;
	swapcontext(&c->caller, &c->callee);
	return c->out;
}



typedef struct node node;
struct node {
	int v;
	node *left, *right;
};

node *newnode(int v)
{
	node *n = malloc(sizeof(node));
	n->left = n->right = 0;
	n->v = v;
	return n;
}

void tree_insert(node **root, node *n)
{
	while (*root) root = ((*root)->v > n->v)
				? &(*root)->left
				: &(*root)->right;
	*root = n;
}

void tree_trav(int x)
{
	co_t *c = (co_t *) x;

	void trav(node *root) {
		if (!root) return;
		trav(root->left);
		co_yield(c, root);
		trav(root->right);
	}

	trav(c->in);
}

int tree_eq(node *t1, node *t2)
{
	co_t *c1 = co_new(tree_trav, t1);
	co_t *c2 = co_new(tree_trav, t2);

	node *p = 0, *q = 0;
	do {
		p = co_collect(c1);
		q = co_collect(c2);
	} while (p && q && (p->v == q->v));

	co_del(c1);
	co_del(c2);
	return !p && !q;
}

int main()
{
	int x[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1 };
	int y[] = { 2, 5, 7, 1, 9, 0, 6, 4, 8, 3, -1 };
	int z[] = { 0, 1, 2, 3, 4, 5, 6, 8, 9, -1 };

	node *t1 = 0, *t2 = 0, *t3 = 0;

	void mktree(int *buf, node **root) {
		int i;
		for (i = 0; buf[i] >= 0; i++)
			tree_insert(root, newnode(buf[i]));
	}

	mktree(x, &t1); 
	mktree(y, &t2); 
	mktree(z, &t3);

	printf("t1 == t2: %s\n", tree_eq(t1, t2) ? "yes" : "no");
	printf("t1 == t3: %s\n", tree_eq(t1, t3) ? "yes" : "no");

	return 0;
}


C++: #include <algorithm>
#include <coroutine>
#include <iostream>
#include <memory>
#include <tuple>
#include <variant>

using namespace std;

class BinaryTree
{
  
  
  
  
  using Node = tuple<BinaryTree, int, BinaryTree>;
  unique_ptr<Node> m_tree;

public:
  
  BinaryTree() = default; 
  BinaryTree(BinaryTree&& leftChild, int value, BinaryTree&& rightChild)
  : m_tree {make_unique<Node>(move(leftChild), value, move(rightChild))} {}
  BinaryTree(int value) : BinaryTree(BinaryTree{}, value, BinaryTree{}){}
  BinaryTree(BinaryTree&& leftChild, int value)
  : BinaryTree(move(leftChild), value, BinaryTree{}){}
  BinaryTree(int value, BinaryTree&& rightChild)
  : BinaryTree(BinaryTree{}, value, move(rightChild)){}

  
  explicit operator bool() const
  {
    return (bool)m_tree;
  }

  
  int Value() const
  {
    return get<1>(*m_tree);
  }

  
  const BinaryTree& LeftChild() const
  {
    return get<0>(*m_tree);
  }

  
  const BinaryTree& RightChild() const
  {
    return get<2>(*m_tree);
  }
};


struct TreeWalker {
  struct promise_type {
    int val;

    suspend_never initial_suspend() noexcept {return {};}
    suspend_never return_void() noexcept {return {};}
    suspend_always final_suspend() noexcept {return {};}
    void unhandled_exception() noexcept { }

    TreeWalker get_return_object() 
    {
      return TreeWalker{coroutine_handle<promise_type>::from_promise(*this)};
    }

    suspend_always yield_value(int x) noexcept 
    {
      val=x;
      return {};
    }
  };

  coroutine_handle<promise_type> coro;

  TreeWalker(coroutine_handle<promise_type> h): coro(h) {}

  ~TreeWalker()
  {
    if(coro) coro.destroy();
  }

  
  class Iterator
  {
    const coroutine_handle<promise_type>* m_h = nullptr;

  public:
    Iterator() = default;
    constexpr Iterator(const coroutine_handle<promise_type>* h) : m_h(h){}

    Iterator& operator++()
    {
      m_h->resume();
      return *this;
    }

    Iterator operator++(int)
    {
      auto old(*this);
      m_h->resume();
      return old;
    }

    int operator*() const
    {
      return m_h->promise().val;
    }

    bool operator!=(monostate) const noexcept
    {
      return !m_h->done();
      return m_h && !m_h->done();
    }

    bool operator==(monostate) const noexcept
    {
      return !operator!=(monostate{});
    }
  };

  constexpr Iterator begin() const noexcept
  {
    return Iterator(&coro);
  }

  constexpr monostate end() const noexcept
  {
    return monostate{};
  }
};


namespace std {
    template<>
    class iterator_traits<TreeWalker::Iterator>
    {
    public:
        using difference_type = std::ptrdiff_t;
        using size_type = std::size_t;
        using value_type = int;
        using pointer = int*;
        using reference = int&;
        using iterator_category = std::input_iterator_tag;
    };
}


TreeWalker WalkFringe(const BinaryTree& tree)
{
  if(tree)
  {
    auto& left = tree.LeftChild();
    auto& right = tree.RightChild();
    if(!left && !right)
    {
      
      co_yield tree.Value();
    }

    for(auto v : WalkFringe(left))
    {
      co_yield v;
    }

    for(auto v : WalkFringe(right))
    {
      co_yield v;
    }
  }
  co_return;
}


void PrintTree(const BinaryTree& tree)
{
  if(tree)
  {
    cout << "(";
    PrintTree(tree.LeftChild());
    cout << tree.Value();
    PrintTree(tree.RightChild());
    cout <<")";
  }
}


void Compare(const BinaryTree& tree1, const BinaryTree& tree2)
{
  
  auto walker1 = WalkFringe(tree1);
  auto walker2 = WalkFringe(tree2);
  
  
  bool sameFringe = ranges::equal(walker1.begin(), walker1.end(),
               walker2.begin(), walker2.end());
  
  
  PrintTree(tree1);
  cout << (sameFringe ? " has same fringe as " : " has different fringe than ");
  PrintTree(tree2);
  cout << "\n";
}

int main()
{
  
  BinaryTree tree1(BinaryTree{6}, 77, BinaryTree{BinaryTree{3}, 77,
    BinaryTree{77, BinaryTree{9}}});
  BinaryTree tree2(BinaryTree{BinaryTree{BinaryTree{6}, 77}, 77, BinaryTree{
    BinaryTree{3}, 77, BinaryTree{9}}});
  
  BinaryTree tree3(BinaryTree{BinaryTree{BinaryTree{6}, 77}, 77, BinaryTree{77, BinaryTree{9}}});

  
  Compare(tree1, tree2);
  Compare(tree1, tree3);
}