#include <iostream>
#include <utility>
#include <string>

class Var
{
private:
    struct controlBlockBase
    {
        unsigned short uses;
    
        controlBlockBase() : uses(1) { }
        virtual ~controlBlockBase() { }
    };

    template <class K>
    struct controlBlockImpl : controlBlockBase
    {
        K value;
        controlBlockImpl(const K &val) : controlBlockBase(), value(val) {}
    };
    
    controlBlockBase *cb;
  
public:
    Var() : cb(nullptr) {
    	std::cout << "Var default constructed" << std::endl;
    }
    
    template<typename K>
    Var(const K &value) : cb(new controlBlockImpl<K>(value)) { 
    	std::cout << "Var value constructed" << std::endl;
    }
    
    Var(const Var &obj) : cb(obj.cb) {
        if (cb) {
            ++(cb->uses);
        }
        std::cout << "Var copy constructed" << std::endl;
    }
    
    Var(Var &&obj) : cb(nullptr) {
        obj.swap(*this);
        std::cout << "Var move constructed" << std::endl;
    }
    
    ~Var() {
        if ((cb) && ((cb->uses -= 1) <= 0)) {
            delete cb;
            cb = nullptr;
        }
        std::cout << "Var destructed" << std::endl;
    }
    
    Var& operator=(const Var& obj) {
        if (this != &obj) {
            Var(obj).swap(*this);
        }
        std::cout << "Var copy assigned" << std::endl;
        return *this;
    }
    
    Var& operator=(Var &&obj) {
        obj.swap(*this);
        std::cout << "Var move assigned" << std::endl;
        return *this;
    }
    
    void swap(Var &other) {
    	std::swap(cb, other.cb);
    }
    
    unsigned short getUses() const {
    	return (cb) ? cb->uses : 0;
    }
};

namespace std {
	void swap(Var &v1, Var &v2) {
		v1.swap(v2);
	}
}

class C
{
public:
    Var var;

    C() {
    	std::cout << "C default constructed" << std::endl;
    }
    
    C(const C &c) : var(c.var) {
    	std::cout << "C copy constructed" << std::endl;
    }
    
    C(C &&c) : var(std::move(c.var)) {
    	std::cout << "C move constructed" << std::endl;
    }
    
    C(Var var) : var(var) {
    	std::cout << "C value constructed" << std::endl;
    }

    ~C() {
    	std::cout << "C destructed" << std::endl;
    }

    C& operator=(const C &c) {
    	if (this != &c) {
    		 C tmp(c);
    		 std::swap(var, tmp.var);
    	}
    	std::cout << "C copy assigned" << std::endl;
    	return *this;
    }

    C& operator=(C &&c) {
        std::swap(var, c.var);
    	std::cout << "C move assigned" << std::endl;
    	return *this;
    }
};

class MyString
{
public:
    std::string str;

    MyString() {
    	std::cout << "MyString default constructed" << std::endl;
    }

    MyString(const char *s) : str(s) {
    	std::cout << "MyString value constructed" << std::endl;
    }

    MyString(const std::string &s) : str(s) {
    	std::cout << "MyString value constructed" << std::endl;
    }
    
    MyString(const MyString &s) : str(s.str) {
    	std::cout << "MyString copy constructed" << std::endl;
    }

    MyString(MyString &&s) : str(std::move(s.str)) {
    	std::cout << "MyString move constructed" << std::endl;
    }

    ~MyString() {
    	std::cout << "MyString destructed" << std::endl;
    }

    MyString& operator=(const MyString &s) {
    	if (this != &s) {
    		 str = s.str;
    	}
    	std::cout << "MyString copy assigned" << std::endl;
    	return *this;
    }

    MyString& operator=(MyString &&s) {
        str = std::move(s.str);
    	std::cout << "MyString move assigned" << std::endl;
    	return *this;
    }
};

void test()
{
    MyString string = "Hello";
    Var var1 = Var(string);
    std::cout << "var1 uses=" << var1.getUses() << std::endl;
    C c = C(var1);
    std::cout << "var1 uses=" << var1.getUses() << std::endl;
    Var var2 = Var(c);
    std::cout << "var1 uses=" << var1.getUses() << std::endl;
    std::cout << "var2 uses=" << var2.getUses() << std::endl;
}

int main() {
    test();
    return 0;
}