Big changes to List, templatizing several things and making some alias defintions.
Big changes to List, templatizing several things and making some alias defintions.

--- a/include/boilerplate.hpp
+++ b/include/boilerplate.hpp
@@ -100,6 +100,7 @@
 void die(s32 status, string message, params... args) {
 	if (message.length() > 0)
 	{
+		fprintf(stderr, "FATAL: ");
 		fprintf(stderr, string_format(message, args...).c_str());
 	}
 
@@ -110,6 +111,7 @@
 void die(s32 status, wstring message, params... args) {
 	if (message.length() > 0)
 	{
+		fwprintf(stderr, L"FATAL: ");
 		fwprintf(stderr, string_format(message, args...).c_str());
 	}
 
@@ -154,8 +156,8 @@
 }
 
 // List type valid up to lots and lots of members.
-template <typename T>
-struct List {
+template <typename T, typename INDEX_TYPE, typename SUBDEX_TYPE, SUBDEX_TYPE _DEFAULT_MAX_BUCKETS, SUBDEX_TYPE _DEFAULT_ITEMS_PER_BUCKET>
+struct __Base_List {
 private:
 	static s8 default_comparer(T l, T r) {
 		if (l < r) {
@@ -169,15 +171,15 @@
 		}
 	}
 
-	u32 ITEMS_PER_BUCKET;
-	u32 MAX_BUCKETS;
+	SUBDEX_TYPE ITEMS_PER_BUCKET;
+	SUBDEX_TYPE MAX_BUCKETS;
 
 	T** buckets;
 
-	u32 bucketCount;
-	u64 itemCount;
-
-	T** BucketPtr(u32 idx) {
+	SUBDEX_TYPE bucketCount;
+	INDEX_TYPE itemCount;
+
+	T** BucketPtr(INDEX_TYPE idx) {
 		if (idx >= bucketCount) {
 			die(1, "Tried to access a list bucket with an index '%u' greater than the current count '%u'.", idx, bucketCount);
 		}
@@ -185,7 +187,7 @@
 		return buckets + idx;
 	}
 
-	T* GetBucket(u32 idx) {
+	T* GetBucket(INDEX_TYPE idx) {
 		return *BucketPtr(idx);
 	}
 
@@ -193,7 +195,7 @@
 		*BucketPtr(bucketCount++) = (T*)malloc(sizeof(T) * ITEMS_PER_BUCKET);
 	}
 
-	s64 qs_partition(u64 ltIdx, u64 rtIdx, u64 pvtIdx, s8 (*comp_func)(T, T), bool reversed) {
+	s64 qs_partition(INDEX_TYPE ltIdx, INDEX_TYPE rtIdx, INDEX_TYPE pvtIdx, s8 (*comp_func)(T, T), bool reversed) {
 		// Fetch the value of the pivot point.
 		T pvtVal = GetItem(pvtIdx);
 
@@ -209,7 +211,7 @@
 		// swap values left of the pivot.
 		u64 strIdx = ltIdx;
 
-		for (u64 idx = ltIdx; idx < rtIdx; idx++) {
+		for (INDEX_TYPE idx = ltIdx; idx < rtIdx; idx++) {
 			s8 result = (*comp_func)(GetItem(idx), pvtVal);
 			if ((!reversed && result < 0) || (reversed && result > 0)) {
 				swap1 = GetItem(strIdx);
@@ -231,11 +233,11 @@
 		return strIdx;
 	}
 
-	void qs_region(u64 ltIdx, u64 rtIdx, s8 (*comp_func)(T, T), bool reversed) {
+	void qs_region(INDEX_TYPE ltIdx, INDEX_TYPE rtIdx, s8 (*comp_func)(T, T), bool reversed) {
 		if (ltIdx < rtIdx && rtIdx < Count()) {
 			// Select a random pivot point between ltIdx and rtIdx.  The location is not important,
 			// and picking randomly may provide speedup in some cases.
-			u64 pvtIdx = random_range(ltIdx, rtIdx);
+			INDEX_TYPE pvtIdx = random_range(ltIdx, rtIdx);
 
 			// L"Sift" the array around the pivot value, and record its new location.
 			s64 newIdx = qs_partition(ltIdx, rtIdx, pvtIdx, comp_func, reversed);
@@ -247,24 +249,36 @@
 	}
 
 public:
-	static const u32 DEFAULT_ITEMS_PER_BUCKET = 256;
-	static const u32 DEFAULT_MAX_BUCKETS = 256;
+	static const SUBDEX_TYPE DEFAULT_ITEMS_PER_BUCKET = _DEFAULT_ITEMS_PER_BUCKET;
+	static const SUBDEX_TYPE DEFAULT_MAX_BUCKETS = _DEFAULT_MAX_BUCKETS;
 
 	s8 (*comparer)(T, T);
 
-	u64 CurrentCapacity() {
-		return (u64)ITEMS_PER_BUCKET * (u64)bucketCount;
-	}
-
-	u64 MaxCapacity() {
-		return (u64)ITEMS_PER_BUCKET * (u64)MAX_BUCKETS;
-	}
-
-	u64 Count() {
+	INDEX_TYPE CurrentCapacity() {
+		return (INDEX_TYPE)ITEMS_PER_BUCKET * (u64)bucketCount;
+	}
+
+	INDEX_TYPE MaxCapacity() {
+		return (INDEX_TYPE)ITEMS_PER_BUCKET * (u64)MAX_BUCKETS;
+	}
+
+	SUBDEX_TYPE BucketCount() {
+		return bucketCount;
+	}
+
+	SUBDEX_TYPE MaxBuckets() {
+		return MAX_BUCKETS;
+	}
+
+	SUBDEX_TYPE ItemsPerBucket() {
+		return ITEMS_PER_BUCKET;
+	}
+
+	INDEX_TYPE Count() {
 		return itemCount;
 	}
 
-	T* ItemPtr(u64 idx) {
+	T* ItemPtr(INDEX_TYPE idx) {
 		if (idx >= MaxCapacity()) {
 			die(1, "Tried to access List item with index '%u' >= maximum capacity '%llu'.", idx, MaxCapacity());
 		}
@@ -272,21 +286,30 @@
 			die(1, "Tried to access List item with index '%u' >= current count '%llu'.", idx, Count());
 		}
 
-		u32 arIdx = (u32)(idx / ITEMS_PER_BUCKET);
-		u32 lfIdx = (u32)(idx % ITEMS_PER_BUCKET);
+		SUBDEX_TYPE arIdx;
+		INDEX_TYPE lfIdx;
+
+		if (MAX_BUCKETS > 1) {
+			arIdx = (SUBDEX_TYPE)(idx / ITEMS_PER_BUCKET);
+			lfIdx = (idx % ITEMS_PER_BUCKET);
+		}
+		else {
+			arIdx = 0;
+			lfIdx = idx;
+		}
 
 		return GetBucket(arIdx) + lfIdx;
 	}
 
-	T& Item(u64 idx) {
+	T& Item(INDEX_TYPE idx) {
 		return *ItemPtr(idx);
 	}
 
-	T GetItem(u64 idx) {
+	T GetItem(INDEX_TYPE idx) {
 		return *ItemPtr(idx);
 	}
 
-	T& operator[] (u64 idx) {
+	T& operator[] (INDEX_TYPE idx) {
 		return Item(idx);
 	}
 
@@ -295,10 +318,10 @@
 	}
 
 	void AddItem(T value) {
-		u64 idx = itemCount;
+		INDEX_TYPE idx = itemCount;
 		itemCount++;
 
-		if (itemCount > ITEMS_PER_BUCKET * bucketCount) {
+		if (itemCount > (INDEX_TYPE)ITEMS_PER_BUCKET * (INDEX_TYPE)bucketCount) {
 			AddBucket();
 		}
 
@@ -312,13 +335,13 @@
 		itemCount = MaxCapacity();
 	}
 
-	void RemoveAt(u64 idx) {
+	void RemoveAt(INDEX_TYPE idx) {
 		T* itemPtr = ItemPtr(idx);
 
-		u32 arIdx = (u32)(idx / ITEMS_PER_BUCKET);
-		u32 lfIdx = (u32)(idx % ITEMS_PER_BUCKET);
-
-		u32 rem_in_bucket = ITEMS_PER_BUCKET - lfIdx - 1;
+		SUBDEX_TYPE arIdx = (SUBDEX_TYPE)(idx / ITEMS_PER_BUCKET);
+		INDEX_TYPE lfIdx = idx % ITEMS_PER_BUCKET;
+
+		INDEX_TYPE rem_in_bucket = ITEMS_PER_BUCKET - lfIdx - 1;
 
 		// First we need to condense this bucket.	
 		if (rem_in_bucket > 0) {
@@ -339,8 +362,8 @@
 		itemCount--;
 	}
 
-	u64 IndexOf(T item) {
-		u64 idx = 0;
+	INDEX_TYPE IndexOf(T item) {
+		INDEX_TYPE idx = 0;
 		
 		do
 		{
@@ -352,7 +375,7 @@
 		return idx;
 	}
 
-	bool TryGetIndexOf(T item, u64* idx)
+	bool TryGetIndexOf(T item, INDEX_TYPE* idx)
 	{
 		*idx = IndexOf(item);
 
@@ -361,7 +384,7 @@
 
 	bool IsSorted(s8 (*comp_func)(T, T), bool reversed) {
 		T first = GetItem(0);
-		for (u32 idx = 1; idx < Count(); idx++) {
+		for (INDEX_TYPE idx = 1; idx < Count(); idx++) {
 			s8 result = (*comp_func)(GetItem(idx), first);
 			if (reversed && result > 0) {
 				return false;
@@ -396,19 +419,19 @@
 	}
 
 	void PrintEachBucket() {
-		u64 printed_items = 0;
-		for (u32 idx = 0; idx < bucketCount; idx++) {
-			print_array(GetBucket(idx), std::min((u64)ITEMS_PER_BUCKET, itemCount - printed_items));
+		SUBDEX_TYPE printed_items = 0;
+		for (SUBDEX_TYPE idx = 0; idx < bucketCount; idx++) {
+			print_array(GetBucket(idx), std::min((INDEX_TYPE)ITEMS_PER_BUCKET, itemCount - printed_items));
 			printed_items += ITEMS_PER_BUCKET;
 		}
 	}
 
-	u64 SizeOf() {
-		return sizeof(T) * bucketCount * ITEMS_PER_BUCKET;
+	INDEX_TYPE SizeOf() {
+		return sizeof(T) * bucketCount * ITEMS_PER_BUCKET + sizeof(T*) * MAX_BUCKETS;
 	}
 
 	void Clear() {
-		for (u32 bIdx = 0; bIdx < bucketCount; bIdx++) {
+		for (SUBDEX_TYPE bIdx = 0; bIdx < bucketCount; bIdx++) {
 			T* bucket = GetBucket(bIdx);
 			if (bucket) {
 				free(bucket);
@@ -422,9 +445,9 @@
 	// Using a const pointer here to highlight that the pointer MUST already be valid
 	// for use with this overload.
 	void CopyTo(T* const ptr) {
-		u64 items_copied = 0;
-		for (u32 bkIdx = 0; bkIdx < bucketCount; bkIdx++) {
-			u64 items_to_copy = std::min((u64)ITEMS_PER_BUCKET, itemCount - items_copied);
+		INDEX_TYPE items_copied = 0;
+		for (SUBDEX_TYPE bkIdx = 0; bkIdx < bucketCount; bkIdx++) {
+			INDEX_TYPE items_to_copy = std::min((INDEX_TYPE)ITEMS_PER_BUCKET, itemCount - items_copied);
 			memmove(&(ptr[items_copied]), GetBucket(bkIdx), sizeof(T) * items_to_copy);
 			items_copied += items_to_copy;
 		}
@@ -447,90 +470,40 @@
 		CopyTo(array);
 	}
 
-	List(u32 max_buckets, u32 items_per_bucket) :
+	__Base_List(SUBDEX_TYPE max_buckets, SUBDEX_TYPE items_per_bucket, s8 (*comp_func)(T, T), bool preallocate) :
 		ITEMS_PER_BUCKET(items_per_bucket),
 		MAX_BUCKETS(max_buckets),
 		bucketCount(0),
 		itemCount(0),
-		comparer(&default_comparer)
+		comparer(comp_func)
 	{
 		buckets = (T**)malloc(sizeof(T*) * MAX_BUCKETS);
-	}
-
-	List() : List(DEFAULT_MAX_BUCKETS, DEFAULT_ITEMS_PER_BUCKET) {}
-
-	List(u64 capacity, bool contiguous_small_list) : bucketCount(0), itemCount(0), comparer(&default_comparer) {
-		if (capacity > 0xfffffffe00000001)
+		if (preallocate)
 		{
-			capacity = 0xfffffffe00000001;
-		}
-
-		double bit_width = std::log2(capacity);
-
-		u32 items_per_bucket, max_buckets;
-
-		if (bit_width > 62)
-		{
-			max_buckets = 0xffffffff;
-		}
-		else
-		{
-			if (contiguous_small_list && bit_width < 32)
-			{
-				max_buckets = 1;
-			}
-			else if (bit_width < 8)
-			{
-				max_buckets = 1;
-			}
-			else if (bit_width < 12)
-			{
-				max_buckets = 1 << 4;
-			}
-			else if (bit_width < 40)
-			{
-				max_buckets = 1ull << 8;
-			}
-			else if (bit_width < 46)
-			{
-				max_buckets = 1ull << 14;
-			}
-			else if (bit_width < 56)
-			{
-				max_buckets = 1ull << 24;
-			}
-			else
-			{
-				max_buckets = 1ull << ((u64)ceil(bit_width) / 2ull);
-			}
-		}
-
-		items_per_bucket = (u32)(capacity / (u64)max_buckets);
-
-		u64 real_capacity = (u64)max_buckets * (u64)items_per_bucket;
-
-		if (real_capacity < capacity && items_per_bucket < 0xffffffff) {
-			items_per_bucket++;
-			real_capacity = (u64)max_buckets * (u64)items_per_bucket;
-		}
-
-		MAX_BUCKETS = max_buckets;
-		ITEMS_PER_BUCKET = items_per_bucket;
-
-		buckets = (T**)malloc(sizeof(T*) * MAX_BUCKETS);
-
-		if (contiguous_small_list && capacity < (1ull << 32))
-		{
-			AddBucket();
-			itemCount = items_per_bucket;
-		}
-	}
-
-	~List() {
+			AllocateToMaxCapacity();
+		}
+	}
+
+	__Base_List(SUBDEX_TYPE max_buckets, SUBDEX_TYPE items_per_bucket) : __Base_List(max_buckets, items_per_bucket, &default_comparer, false) {}
+
+	__Base_List() : __Base_List(DEFAULT_MAX_BUCKETS, DEFAULT_ITEMS_PER_BUCKET, &default_comparer, false) {}
+
+	__Base_List(s8 (*comp_func)(T, T)) : __Base_List(DEFAULT_MAX_BUCKETS, DEFAULT_ITEMS_PER_BUCKET, comp_func, false) {}
+
+	~__Base_List() {
 		Clear();
 		free(buckets);
 	}
 };
+
+template<typename T>
+using List = __Base_List<T, u32, u16, 256ul, 1024ul>;
+
+template<typename T, u16 b, u16 i>
+using List2 = __Base_List<T, u32, u16, b, i>;
+
+template <typename T>
+using BigList = __Base_List<T, u64, u32, 1ull << 15, 1ull << 17>;
 
 typedef std::function<void()> Callback;
 typedef Callback* CallbackPtr;
@@ -607,3 +580,4 @@
 	}
 };
 
+