#include "Tutorial.h"

void ContainerClientTypes()
{
	/// .Client types in U++ containers

	/// So far we were using int as type of elements. In order to store client defined types
	/// into the `Vector` (and the Vector ^topic://Core/src/Overview$en-us:flavor^) the type
	/// must satisfy ^topic://Core/src/Moveable$en-us:moveable^ requirement - in short, it must
	/// not contain back-pointers nor virtual methods. Type must be marked as %moveable% in
	/// order to define interface contract using `Moveable`
	/// ^https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern:CRTP idiom^:

	struct Distribution : Moveable<Distribution> {
		String      text;
		Vector<int> data;
		
		String ToString() const { return text + ": " + AsString(data); }
	};


	/// Now to add `Distribution` elements you cannot use `Vector::Add(const T&)`, because it requires
	/// elements to have default deep-copy constructor - and `Distribution does not have one, as
	/// `Vector<int>` has default pick-constructor, so Distribution itself has pick-constructor.
	/// It would no be a good idea either, because deep-copy would involve expensive copying of
	/// inner Vector.
	
	/// Instead, Add without parameters has to be used - it default constructs (that is cheap)
	/// element in Vector and returns reference to it:

	Vector<Distribution> dist;
	for(int n = 5; n <= 10; n++) {
		Distribution& d = dist.Add();
		d.text << "Test " << n;
		for(int i = 0; i < 10000; i++)
			d.data.At(Random(n), 0)++;
	}
	
	DUMPC(dist);

	/// Another possibility is to use `Vector::Add(T&&)` method, which uses pick-constructor
	/// instead of deep-copy constructor. E.g. `Distribution` elements might be generated by
	/// some function:

#if 0
	Distribution CreateDist(int n);

	/// and code for adding such elements to Vector then looks like:

	for(n = 5; n <= 10; n++)
		dist.Add(CreateDist(n));

	/// alternatively, you can use default-constructed variant too

		dist.Add() = CreateDist();
#endif

	///
}