blob: 87b7a28f7658a418397c24e3fa4bee4fcbb26886 [file] [log] [blame]
/*//////////////////////////////////////////////////////////////////////////////
Copyright (c) 2014-2017 Jamboree
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//////////////////////////////////////////////////////////////////////////////*/
#ifndef BUSTACHE_MODEL_HPP_INCLUDED
#define BUSTACHE_MODEL_HPP_INCLUDED
#include <bustache/format.hpp>
#include <bustache/detail/variant.hpp>
#include <bustache/detail/any_context.hpp>
#include <vector>
#include <functional>
#include <boost/unordered_map.hpp>
namespace bustache
{
class value;
using array = std::vector<value>;
// We use boost::unordered_map because it allows incomplete type.
using object = boost::unordered_map<std::string, value>;
using lambda0v = std::function<value()>;
using lambda0f = std::function<format()>;
using lambda1v = std::function<value(ast::content_list const&)>;
using lambda1f = std::function<format(ast::content_list const&)>;
namespace detail
{
struct bool_
{
bool_(bool);
};
}
#define BUSTACHE_VALUE(X, D) \
X(0, std::nullptr_t, D) \
X(1, bool, D) \
X(2, int, D) \
X(3, double, D) \
X(4, std::string, D) \
X(5, array, D) \
X(6, lambda0v, D) \
X(7, lambda0f, D) \
X(8, lambda1v, D) \
X(9, lambda1f, D) \
X(10, object, D) \
/***/
class value : public variant_base<value>
{
static std::nullptr_t match_type(std::nullptr_t);
static int match_type(int);
// Use a fake bool_ to prevent unintended bool conversion.
static bool match_type(detail::bool_);
static double match_type(double);
static std::string match_type(std::string);
static array match_type(array);
static lambda0v match_type(lambda0v);
static lambda0f match_type(lambda0f);
static lambda1v match_type(lambda1v);
static lambda1f match_type(lambda1f);
static object match_type(object);
// Need to override for `char const*`, otherwise `bool` will be chosen
static std::string match_type(char const*);
public:
struct view;
using pointer = variant_ptr<view>;
Zz_BUSTACHE_VARIANT_DECL(value, BUSTACHE_VALUE, false)
value() noexcept : _which(0), _0() {}
pointer get_pointer() const
{
return {_which, _storage};
}
};
struct value::view : variant_base<view>
{
using switcher = value::switcher;
#define BUSTACHE_VALUE_VIEW_CTOR(N, U, D) \
view(U const& data) noexcept : _which(N), _data(&data) {}
BUSTACHE_VALUE(BUSTACHE_VALUE_VIEW_CTOR,)
#undef BUSTACHE_VALUE_VIEW_CTOR
view(value const& data) noexcept
: _which(data._which), _data(data._storage)
{}
view(unsigned which, void const* data) noexcept
: _which(which), _data(data)
{}
unsigned which() const
{
return _which;
}
void const* data() const
{
return _data;
}
pointer get_pointer() const
{
return {_which, _data};
}
private:
unsigned _which;
void const* _data;
};
#undef BUSTACHE_VALUE
}
namespace bustache
{
// Forward decl only.
template<class CharT, class Traits, class Context>
void generate_ostream
(
std::basic_ostream<CharT, Traits>& out, format const& fmt,
value::view const& data, Context const& context, option_type flag
);
// Forward decl only.
template<class String, class Context>
void generate_string
(
String& out, format const& fmt,
value::view const& data, Context const& context, option_type flag
);
template<class CharT, class Traits, class T, class Context,
typename std::enable_if<std::is_constructible<value::view, T>::value, bool>::type = true>
inline std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& out, manipulator<T, Context> const& manip)
{
generate_ostream(out, manip.fmt, manip.data, detail::any_context(manip.context), manip.flag);
return out;
}
template<class T, class Context,
typename std::enable_if<std::is_constructible<value::view, T>::value, bool>::type = true>
inline std::string to_string(manipulator<T, Context> const& manip)
{
std::string ret;
generate_string(ret, manip.fmt, manip.data, detail::any_context(manip.context), manip.flag);
return ret;
}
}
#endif