/*
 * Lazy generation of Pythagorean Triples
 * Inspired by http://b...content-available-to-author-only...i.com/2014/04/21/getting-lazy-with-c/
 * John Zwinck, 2014-04-22
 * 
 * This demonstrates a different, perhaps more C++ish solution to lazily
 * generate a sequence.  This approach does no dynamic memory allocation.
 * The main idea is to implement a custom forward iterator (STL compatible).
 *
 * Separation of concerns are handled thusly:
 * 1. Generating Pythagorean Triples is done by our triple_iterator.
 * 2. Printing is handled by std::ostream_iterator<>.
 * 3. Limiting the number of triples generated is via std::copy_n().
 *
 * As in the original version, the algorithm is naive.
 */

#include <algorithm>
#include <iostream>
#include <iterator>
#include <cassert>
#include <climits>

using namespace std;

struct triple
{
    int x = 0;
    int y = 0;
    int z = 0;
};

ostream& operator<<(ostream& out, const triple& value)
{
	//another sanity check
	assert((value.x * value.x) + (value.y * value.y) == (value.z * value.z));
    return out << value.x << ", " << value.y << ", " << value.z;
}

// unbounded forward iterator producing Pythagorean Triples on demand
class triple_iterator : public iterator<forward_iterator_tag, triple>, triple
{
public:
    triple_iterator() { ++*this; } // initialize to the first valid triple
    const triple& operator*() { return *this; }

    // set ourselves to the next Pythagorean Triple
    triple_iterator& operator++()
    {
    	//checking sanity since x,y,and z are public members of this iterator
    	assert(z < INT_MAX);
    	assert(y <= z);
    	assert(x <= z);

    	++y;
    	
        for (;z < INT_MAX; ++z) {
            for (; x < z; ++x) {
                for (; y < z; ++y) {
                    if (x*x + y*y == z*z) {
                        return *this;
                    }
                }
                y = x + 1;
            }
            x = 1;
        }
        
        cerr << "Could not calculate the next Pythagorean triple..." << endl;
        exit(EXIT_FAILURE);
    }
};

int main()
{
    // write the first few Pythagorean Triples to stdout
    copy_n(triple_iterator(), 100, ostream_iterator<triple>(cout, "\n"));
}
