#include <cstring>
#include <chrono>
#include <map>
#include <string>
#include <vector>
#include <unordered_map>
#include <iostream>
 
enum class animal
{
    Unknown, 
        Aardvark, 
        Albatross, 
        Alligator, 
        Alpaca, 
        AmericanBison, 
        Ant, 
        Anteater, 
        Antelope, 
        Ape, 
        Armadillo, 
};
 
animal to_animal_naive(const char* s)
{
        if (std::strcmp(s, "Aardvark") == 0)
                return animal::Aardvark;
        if (std::strcmp(s, "Albatross") == 0)
                return animal::Albatross;
        if (std::strcmp(s, "Alligator") == 0)
                return animal::Alligator;
        if (std::strcmp(s, "Alpaca") == 0)
                return animal::Alpaca;
        if (std::strcmp(s, "AmericanBison") == 0)
                return animal::AmericanBison;
        if (std::strcmp(s, "Ant") == 0)
                return animal::Ant;
        if (std::strcmp(s, "Anteater") == 0)
                return animal::Anteater;
        if (std::strcmp(s, "Antelope") == 0)
                return animal::Antelope;
        if (std::strcmp(s, "Ape") == 0)
                return animal::Ape;
        if (std::strcmp(s, "Armadillo") == 0)
                return animal::Armadillo;
        return animal::Unknown;
}
 
animal to_animal_naive_map(const char* s)
{
        struct animal_selector
        {
                std::map<std::string, animal> animal_map_;
 
                animal_selector()
                {
                        animal_map_["Aardvark"] = animal::Aardvark;
                        animal_map_["Albatross"] = animal::Albatross;
                        animal_map_["Alligator"] = animal::Alligator;
                        animal_map_["Alpaca"] = animal::Alpaca;
                        animal_map_["AmericanBison"] = animal::AmericanBison;
                        animal_map_["Ant"] = animal::Ant;
                        animal_map_["Anteater"] = animal::Anteater;
                        animal_map_["Antelope"] = animal::Antelope;
                        animal_map_["Ape"] = animal::Ape;
                        animal_map_["Armadillo"] = animal::Armadillo;
                }
 
                animal operator () (const char* s) const
                {
                        auto found = animal_map_.find(s);
                        if (found != animal_map_.end())
                                return found->second;
                        return animal::Unknown;
                }
        };
 
        static animal_selector selector;
 
        return selector(s);
}
 
animal to_animal_map(const char* s)
{
        struct animal_selector
        {
                struct compare
                {
                        bool operator () (const char* s, const char* t) const
                        {
                                return std::strcmp(s, t) < 0;
                        }
                };
 
                std::map<const char*, animal, compare> animal_map_;
 
                animal_selector()
                {
                        animal_map_["Aardvark"] = animal::Aardvark;
                        animal_map_["Albatross"] = animal::Albatross;
                        animal_map_["Alligator"] = animal::Alligator;
                        animal_map_["Alpaca"] = animal::Alpaca;
                        animal_map_["AmericanBison"] = animal::AmericanBison;
                        animal_map_["Ant"] = animal::Ant;
                        animal_map_["Anteater"] = animal::Anteater;
                        animal_map_["Antelope"] = animal::Antelope;
                        animal_map_["Ape"] = animal::Ape;
                        animal_map_["Armadillo"] = animal::Armadillo;
                }
 
                animal operator () (const char* s) const
                {
                        auto found = animal_map_.find(s);
                        if (found != animal_map_.end())
                                return found->second;
                        return animal::Unknown;
                }
        };
 
        static animal_selector selector;
 
        return selector(s);
}
 
animal to_animal_unordered_map(const char* s)
{
        struct animal_selector
        {
                std::unordered_map<std::string, animal> animal_map_;
 
                animal_selector()
                {
                        animal_map_["Aardvark"] = animal::Aardvark;
                        animal_map_["Albatross"] = animal::Albatross;
                        animal_map_["Alligator"] = animal::Alligator;
                        animal_map_["Alpaca"] = animal::Alpaca;
                        animal_map_["AmericanBison"] = animal::AmericanBison;
                        animal_map_["Ant"] = animal::Ant;
                        animal_map_["Anteater"] = animal::Anteater;
                        animal_map_["Antelope"] = animal::Antelope;
                        animal_map_["Ape"] = animal::Ape;
                        animal_map_["Armadillo"] = animal::Armadillo;
                }
 
                animal operator () (const char* s) const
                {
                        auto found = animal_map_.find(s);
                        if (found != animal_map_.end())
                                return found->second;
                        return animal::Unknown;
                }
        };
 
        static animal_selector selector;
 
        return selector(s);
}
 
template <animal A>
struct this_or_unknown
{
        animal operator () (const char* s, const char* t) const
        {
                return std::strcmp(s, t) == 0 ? A : animal::Unknown;
        }
};
 
animal to_animal_switch_only(const char* s)
{
        switch (*s++)
        {
        default:
                return animal::Unknown;
        case 'A':
                switch (*s++)
                {
                default:
                        return animal::Unknown;
                case 'a':
                        return this_or_unknown<animal::Aardvark>()(s, "rdvark");
                case 'l':
                        switch (*s++)
                        {
                        default:
                                return animal::Unknown;
                        case 'b':
                                return this_or_unknown<animal::Albatross>()(s, "atross");
                        case 'l':
                                return this_or_unknown<animal::Alligator>()(s, "igator");
                        case 'p':
                                return this_or_unknown<animal::Alpaca>()(s, "aca");
                        }
                case 'm':
                        return this_or_unknown<animal::AmericanBison>()(s, "ericanBison");
                case 'n':
                        switch (*s++)
                        {
                        default:
                                return animal::Unknown;
                        case 't':
                                switch (*s++)
                                {
                                default:
                                        return animal::Unknown;
                                case '\0':
                                        return animal::Ant;
                                case 'e':
                                        switch (*s++)
                                        {
                                        default:
                                                return animal::Unknown;
                                        case 'a':
                                                return this_or_unknown<animal::Anteater>()(s, "ter");
                                        case 'l':
                                                return this_or_unknown<animal::Antelope>()(s, "ope");
                                        }
                                }
                        }
                case 'p':
                        return *s == 'e' ? animal::Ape : animal::Unknown;
                case 'r':
                        return this_or_unknown<animal::Armadillo>()(s, "madillo");
                }
        }
}
 
animal to_animal_if_only(const char* s)
{
        if (*s++ == 'A')
        {
                if (*s == 'a')
                {
                        return this_or_unknown<animal::Aardvark>()(++s, "rdvark");
                }
                else if (*s == 'l')
                {
                        ++s;
                        if (*s == 'b')
                                return this_or_unknown<animal::Albatross>()(++s, "atross");
                        else if (*s == 'l')
                                return this_or_unknown<animal::Alligator>()(++s, "igator");
                        else if (*s == 'p')
                                return this_or_unknown<animal::Alpaca>()(++s, "aca");
                }
                else if (*s == 'm')
                {
                        return this_or_unknown<animal::AmericanBison>()(++s, "ericanBison");
                }
                else if (*s == 'n')
                {
                        ++s;
                        if (*s++ == 't')
                        {
                                if (*s == '\0')
                                {
                                        return animal::Ant;
                                }
                                else if (*s++ == 'e')
                                {
                                        if (*s == 'a')
                                                return this_or_unknown<animal::Anteater>()(++s, "ter");
                                        else if (*s == 'l')
                                                return this_or_unknown<animal::Antelope>()(++s, "ope");
                                }
                        }
                }
                else if (*s == 'p' && *++s == 'e')
                {
                        return animal::Ape;
                }
                else if (*s == 'r')
                {
                        return this_or_unknown<animal::Armadillo>()(s, "madillo");
                }
        }
        return animal::Unknown;
}
 
animal to_animal_nice_mix(const char* s)
{
        if (*s++ == 'A')
        {
                switch (*s++)
                {
                default:
                        break;
                case 'a':
                        return this_or_unknown<animal::Aardvark>()(s, "rdvark");
                case 'l':
                        if (*s == 'b')
                                return this_or_unknown<animal::Albatross>()(++s, "atross");
                        else if (*s == 'l')
                                return this_or_unknown<animal::Alligator>()(++s, "igator");
                        else if (*s == 'p')
                                return this_or_unknown<animal::Alpaca>()(++s, "aca");
                        break;
                case 'm':
                        return this_or_unknown<animal::AmericanBison>()(s, "ericanBison");
                case 'n':
                        if (*s++ == 't')
                        {
                                if (*s == '\0')
                                {
                                        return animal::Ant;
                                }
                                else if (*s++ == 'e')
                                {
                                        if (*s == 'a')
                                                return this_or_unknown<animal::Anteater>()(++s, "ter");
                                        else if (*s == 'l')
                                                return this_or_unknown<animal::Antelope>()(++s, "ope");
                                }
                        }
                        break;
                case 'p':
                        return *s == 'e' ? animal::Ape : animal::Unknown;
                case 'r':
                        return this_or_unknown<animal::Armadillo>()(s, "madillo");
                }
        }
        return animal::Unknown;
}
 
template <typename Clock = std::chrono::high_resolution_clock>
class stopwatch
{
    typename Clock::time_point last_;
 
public:
    stopwatch()
        : last_(Clock::now())
    {}
 
    void reset()
    {
        *this = stopwatch();
    }
 
    typename Clock::duration elapsed() const
    {
        return Clock::now() - last_;
    }
 
    typename Clock::duration tick()
    {
        auto now = Clock::now();
        auto elapsed = now - last_;
        last_ = now;
        return elapsed;
    }
};
 
template <typename T, typename Rep, typename Period>
T duration_cast(const std::chrono::duration<Rep, Period>& duration)
{
    return duration.count() * static_cast<T>(Period::num) / static_cast<T>(Period::den);
}
 
int main()
{
        //while (true)
        //{
                std::size_t max_iterations;
                std::cout << "Max iterations: ";
                std::cin >> max_iterations;
 
                std::vector<std::string> animals;
                std::cout << "Enter animals:\n";
                for (std::string s;;)
                {
                        std::cin >> s;
 
                        if (s == "start")
                                break;
 
                        animals.push_back(s);
                }
 
    stopwatch<> sw;
                double t;
    
                sw.reset();
                for (auto i = max_iterations; i--; )
                {
                        animal a = to_animal_naive(animals[i % animals.size()].c_str());
                        if (i % 13373 == 0 && a == animal::Albatross)
                                std::cout << '.';
                }
                std::cout << '\n';
                t = duration_cast<double>(sw.elapsed());
    std::cout << "to_animal_naive: " << t << '\n';
 
                sw.reset();
                for (auto i = max_iterations; i--; )
                {
                        animal a = to_animal_naive_map(animals[i % animals.size()].c_str());
                        if (i % 13373 == 0 && a == animal::Albatross)
                                std::cout << '.';
                }
                std::cout << '\n';
                t = duration_cast<double>(sw.elapsed());
    std::cout << "to_animal_naive_map: " << t << '\n';
 
                sw.reset();
                for (auto i = max_iterations; i--; )
                {
                        animal a = to_animal_map(animals[i % animals.size()].c_str());
                        if (i % 13373 == 0 && a == animal::Albatross)
                                std::cout << '.';
                }
                std::cout << '\n';
                t = duration_cast<double>(sw.elapsed());
    std::cout << "to_animal_map: " << t << '\n';
 
                sw.reset();
                for (auto i = max_iterations; i--; )
                {
                        animal a = to_animal_unordered_map(animals[i % animals.size()].c_str());
                        if (i % 13373 == 0 && a == animal::Albatross)
                                std::cout << '.';
                }
                std::cout << '\n';
                t = duration_cast<double>(sw.elapsed());
    std::cout << "to_animal_unordered_map: " << t << '\n';
 
                sw.reset();
                for (auto i = max_iterations; i--; )
                {
                        animal a = to_animal_switch_only(animals[i % animals.size()].c_str());
                        if (i % 13373 == 0 && a == animal::Albatross)
                                std::cout << '.';
                }
                std::cout << '\n';
                t = duration_cast<double>(sw.elapsed());
    std::cout << "to_animal_switch_only: " << t << '\n';
 
                sw.reset();
                for (auto i = max_iterations; i--; )
                {
                        animal a = to_animal_if_only(animals[i % animals.size()].c_str());
                        if (i % 13373 == 0 && a == animal::Albatross)
                                std::cout << '.';
                }
                std::cout << '\n';
                t = duration_cast<double>(sw.elapsed());
    std::cout << "to_animal_if_only: " << t << '\n';
 
                sw.reset();
                for (auto i = max_iterations; i--; )
                {
                        animal a = to_animal_nice_mix(animals[i % animals.size()].c_str());
                        if (i % 13373 == 0 && a == animal::Albatross)
                                std::cout << '.';
                }
                std::cout << '\n';
                t = duration_cast<double>(sw.elapsed());
    std::cout << "to_animal_nice_mix: " << t << '\n';
        //}
}