#include "crany.hpp"

#include <cmath>
#include <iostream>
#include <vector>


auto constexpr pi = std::acos(-1.0F);


struct Circle
{
    float radius;
    void  scale(float scale)       { radius *= scale;         }
    float area()             const { return pi*radius*radius; }
    float circumference()    const { return 2.0F*pi*radius;   }
};

struct Rectangle
{
    float side1;
    float side2;
    void  scale(float scale)       { side1 *= scale; side2 *= scale; }
    float area()             const { return side1*side2;             }
};


template<typename Self>
struct ShapeConcept : Self
{
    using Self::self;
    virtual void  scale(float value)       { return self().scale(value); }
    virtual float area()             const { return self().area();       }
};

using Shape = Crany<ShapeConcept>;
using Shapes = std::vector<Shape>;


int main()
{
    static_assert(std::is_standard_layout   <Circle>{}, "Circle not is standard layout");
    static_assert(std::is_trivially_copyable<Circle>{}, "Circle not is trivially copyable");

    auto shapes = Shapes{
        Circle{1.0F},
        Rectangle{2.0F, 3.0F},
    };
    shapes.push_back(shapes.front());
    shapes.back().scale(2.0F);

    std::cout << std::boolalpha;
    for (auto const & shape : shapes)
        std::cout
            << shape.area()
            << " "
            << bool(crany_cast<Circle>(&shape))
            << "\n";
}
