Skip to content

Instantly share code, notes, and snippets.

@randomphrase
Created August 7, 2011 11:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save randomphrase/1130306 to your computer and use it in GitHub Desktop.
Save randomphrase/1130306 to your computer and use it in GitHub Desktop.
99 Bottles Of Beer, using Boost MPL
#include <boost/mpl/assert.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/back_inserter.hpp>
#include <boost/mpl/copy.hpp>
#include <boost/mpl/divides.hpp>
#include <boost/mpl/empty_sequence.hpp>
#include <boost/mpl/equal.hpp>
#include <boost/mpl/equal_to.hpp>
#include <boost/mpl/fold.hpp>
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/joint_view.hpp>
#include <boost/mpl/less.hpp>
#include <boost/mpl/minus.hpp>
#include <boost/mpl/modulus.hpp>
#include <boost/mpl/push_back.hpp>
#include <boost/mpl/range_c.hpp>
#include <boost/mpl/string.hpp>
#include <boost/mpl/transform.hpp>
#include <boost/mpl/vector.hpp>
#include <iostream>
using namespace boost::mpl;
template <typename n>
struct NumberInEnglish
{
// Can't handle >= 100
BOOST_MPL_ASSERT(( less<n, int_<100> > ));
typedef int_<10> ten;
typedef int_<20> twenty;
typedef char_<'-'> dash;
typedef vector<
string<>, // use Ones vector
string<>, // use Teens vector
string<'twen','ty'>,
string<'thir','ty'>,
string<'four','ty'>,
string<'fift','y'>,
string<'sixt','y'>,
string<'seve','nty'>,
string<'eigh','ty'>,
string<'nine','ty'> > Tens;
typedef vector<
string<'no ','more'>,
string<'one'>,
string<'two'>,
string<'thre','e'>,
string<'four'>,
string<'five'>,
string<'six'>,
string<'seve','n'>,
string<'eigh','t'>,
string<'nine'>
> Ones;
typedef vector<
string<'ten'>,
string<'elev','en'>,
string<'twel','ve'>,
string<'thir','teen'>,
string<'four','teen'>,
string<'fift','een'>,
string<'sixt','een'>,
string<'seve','ntee','n'>,
string<'eigh','teen'>,
string<'nine','teen'>
> Teens;
typedef if_<
modulus<n, ten>,
typename copy<
joint_view<
typename push_back<typename at<Tens, divides<n, ten> >::type, dash>::type,
typename at<Ones, modulus<n, ten> >::type>,
back_inserter<string<> >
>::type,
typename at<Tens, divides<n, ten> >::type
> DoubleDigit;
typedef typename if_<
less<n, ten>,
typename at<Ones, n>::type,
typename if_<
less<n, twenty>,
typename at<Teens, minus<n, ten> >::type,
typename DoubleDigit::type
>::type
>::type type;
};
BOOST_MPL_ASSERT(( equal< NumberInEnglish<int_<4> >::type, string<'four'> > ));
BOOST_MPL_ASSERT(( equal< NumberInEnglish<int_<14> >::type, string<'four','teen'> > ));
BOOST_MPL_ASSERT(( equal< NumberInEnglish<int_<20> >::type, string<'twen','ty'> > ));
BOOST_MPL_ASSERT(( equal< NumberInEnglish<int_<44> >::type, string<'four','ty-f','our'> > ));
template <typename n>
struct CountBottles
{
typedef string<'bott','le'> Bottle;
typedef typename copy<
joint_view<
typename push_back<
typename NumberInEnglish<n>::type, char_<' '> >::type,
typename if_<
equal_to<n, int_<1> >,
Bottle,
push_back<Bottle, char_<'s'> >::type
>::type
>,
back_inserter<string<> >
>::type type;
};
BOOST_MPL_ASSERT(( equal< CountBottles<int_<0> >::type, string<'no m','ore ','bott','les'> > ));
BOOST_MPL_ASSERT(( equal< CountBottles<int_<1> >::type, string<'one ','bott','le'> > ));
BOOST_MPL_ASSERT(( equal< CountBottles<int_<14> >::type, string<'four','teen',' bot','tles'> > ));
template <typename n>
struct Verse
{
typedef string<'\n'> NL;
typedef string<',\n'> CommaNL;
typedef string<' of ','beer'> OfBeer;
typedef string<' on ','the ','wall'> OnTheWall;
typedef string<'take',' one',' dow','n, p','ass ','it a','roun','d,\n'> TakeOneDownPassItAround;
typedef typename transform<
vector<
typename CountBottles<n>::type,
OfBeer,
OnTheWall,
CommaNL,
typename CountBottles<n>::type,
OfBeer,
CommaNL,
TakeOneDownPassItAround,
typename CountBottles<typename prior<n>::type>::type,
OfBeer,
NL,
NL
>,
c_str<_1>
>::type strings;
};
struct PrintValue
{
PrintValue(std::ostream& os) : os_(os) {}
std::ostream& os_;
template <typename T>
void operator() (T t)
{
os_ << T::value;
}
};
template <typename n>
std::ostream& operator<< (std::ostream& os, Verse<n> verse)
{
boost::mpl::for_each<typename Verse<n>::strings>(PrintValue(os));
};
struct PrintTo
{
PrintTo(std::ostream& os) : os_(os) {}
std::ostream& os_;
template <typename T>
void operator() (T t)
{
os_ << t;
}
};
int main()
{
boost::mpl::for_each<
range_c<int, 1, 100>,
lambda<
Verse<minus<int_<100>, _1> >
>::type>(
PrintTo(std::cout));
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment