#include <cassert>
#include <sstream>
#include <cctype>
#include <cmath>
#include <algorithm>
#include <iostream>
//Extends std::basic_string and adds more functionality
class MyString : public std::basic_string<char>
{
public:
	typedef std::basic_string<char> string_type;
public:
	MyString() : string_type() {}
	MyString(const char * str) : string_type(str){}
	MyString(const char * str, size_t n) : string_type(str, n) {}
	MyString(size_t n, char c) : string_type(n, c) {}
public:
	//added functionalities
	MyString  MytoUpper()const      { return _apply(std::toupper); }
	MyString  MytoLower()const      { return _apply(std::tolower); }

	bool    MyisDigits()const       { return _isAllDigits(); }
	bool    MyisLower()const      { return _checkIf(std::islower); }
	bool    MyisUpper()const      { return _checkIf(std::isupper); }
	bool    MyisAlpha()const      { return _checkIf(std::isalpha); }
	int       MytoInt()const           { return _convertTo<int>(*this); }
	long    MytoLong()const       { return _convertTo<long>(*this); }
	float     MytoFloat()const      { return _convertTo<float>(*this); }
	double  MytoDouble()const     { return _convertTo<double>(*this); }
	size_t   MytoSizeT()const      { return _convertTo<size_t>(*this); }
	void     Myreset()             { *this = MyString(); }

	//conversion function
	operator const char*(){
		return c_str();
	}
private:
	//helpers
	typedef int(*ApplyFunc)(int);
	//converts a string to a valid data type
	template<typename ReturnType>
	ReturnType _convertTo(const MyString& str)const{
		_assertValidSize();
		std::stringstream convert;
		convert << str;
		ReturnType data;
		assert(!(convert >> data).fail()); //make sure conversion was succesful
		return data;
	}
	//takes in a function and returns a string with that function applied to the whole string
	MyString _apply(const ApplyFunc& Applier)const{
		_assertValidSize();
		MyString str;
		std::transform(begin(), end(), //from start to end
			std::back_insert_iterator<string_type>(str), //adjust str size
			Applier); //while applying a function to it
		return str;
	}
	//takes in a function and checks if it passes the function checking
	bool _checkIf(const ApplyFunc& Applier)const{
		for (size_t indx = 0; indx != size(); ++indx){
			if (!Applier((*this)[indx]))return false;
		}
		return true;
	}
	//A valid digit is 0-9, with the expection of '.' for floating point, and '-' for negative digits
	//A valid here cannot end with any post-fix, ex : 3.14f or 124L is invalid!
	bool _isAllDigits()const{
		size_t start = 0;
		if ((*this)[0] == '-')
			start = 1;
		for (; start < size(); ++start){
			char value = (*this)[start];
			if (!isdigit(value) && value != '.')
				return false;
		}
		return true;
	}
	void _assertValidSize()const{
		assert(size());
	}
};
int main()
{
	using namespace std;
	MyString str("StRinG");

	cout << str.MytoUpper() << endl;
	cout << str.MytoLower() << endl;
	str = "34.56";
	float f1, f2;
	f1 = str.MytoFloat();
	str = "100.1";
	f2 = str.MytoFloat();
	cout << "f1=" << f1 << ", f2=" << f2 << ", sum=" << f1+f2 << ", flr=" << floor(f1+f2) << endl;
}

