blob: f48b343376b032753b0bbdf0028e211e325874d7 [file] [log] [blame]
// Copyright (c) 2001-2011 Hartmut Kaiser
//
// 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)
#if !defined(BOOST_SPIRIT_KARMA_STREAM_MAY_01_2007_0310PM)
#define BOOST_SPIRIT_KARMA_STREAM_MAY_01_2007_0310PM
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/spirit/home/support/common_terminals.hpp>
#include <boost/spirit/home/support/info.hpp>
#include <boost/spirit/home/support/container.hpp>
#include <boost/spirit/home/support/detail/hold_any.hpp>
#include <boost/spirit/home/support/detail/get_encoding.hpp>
#include <boost/spirit/home/karma/domain.hpp>
#include <boost/spirit/home/karma/meta_compiler.hpp>
#include <boost/spirit/home/karma/delimit_out.hpp>
#include <boost/spirit/home/karma/auxiliary/lazy.hpp>
#include <boost/spirit/home/karma/stream/detail/format_manip.hpp>
#include <boost/spirit/home/karma/stream/detail/iterator_sink.hpp>
#include <boost/spirit/home/karma/detail/get_casetag.hpp>
#include <boost/spirit/home/karma/detail/extract_from.hpp>
#include <boost/fusion/include/at.hpp>
#include <boost/fusion/include/vector.hpp>
#include <boost/fusion/include/cons.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_same.hpp>
#include <iosfwd>
///////////////////////////////////////////////////////////////////////////////
namespace boost { namespace spirit
{
namespace tag
{
template <typename Char = char>
struct stream_tag {};
}
namespace karma
{
///////////////////////////////////////////////////////////////////////
// This one is the class that the user can instantiate directly in
// order to create a customized int generator
template <typename Char = char>
struct stream_generator
: spirit::terminal<tag::stream_tag<Char> >
{};
}
///////////////////////////////////////////////////////////////////////////
// Enablers
///////////////////////////////////////////////////////////////////////////
template <>
struct use_terminal<karma::domain, tag::stream> // enables stream
: mpl::true_ {};
template <>
struct use_terminal<karma::domain, tag::wstream> // enables wstream
: mpl::true_ {};
template <typename A0>
struct use_terminal<karma::domain // enables stream(...)
, terminal_ex<tag::stream, fusion::vector1<A0> >
> : mpl::true_ {};
template <typename A0>
struct use_terminal<karma::domain // enables wstream(...)
, terminal_ex<tag::wstream, fusion::vector1<A0> >
> : mpl::true_ {};
template <> // enables stream(f)
struct use_lazy_terminal<
karma::domain, tag::stream, 1 /*arity*/
> : mpl::true_ {};
template <> // enables wstream(f)
struct use_lazy_terminal<
karma::domain, tag::wstream, 1 /*arity*/
> : mpl::true_ {};
// enables stream_generator<char_type>
template <typename Char>
struct use_terminal<karma::domain, tag::stream_tag<Char> >
: mpl::true_ {};
template <typename Char, typename A0>
struct use_terminal<karma::domain
, terminal_ex<tag::stream_tag<Char>, fusion::vector1<A0> >
> : mpl::true_ {};
template <typename Char>
struct use_lazy_terminal<
karma::domain, tag::stream_tag<Char>, 1 /*arity*/
> : mpl::true_ {};
}}
///////////////////////////////////////////////////////////////////////////////
namespace boost { namespace spirit { namespace karma
{
using spirit::stream;
using spirit::wstream;
///////////////////////////////////////////////////////////////////////////
template <typename Char, typename CharEncoding, typename Tag>
struct any_stream_generator
: primitive_generator<any_stream_generator<Char, CharEncoding, Tag> >
{
template <typename Context, typename Unused = unused_type>
struct attribute
{
typedef spirit::hold_any type;
};
// any_stream_generator has an attached attribute
template <
typename OutputIterator, typename Context, typename Delimiter
, typename Attribute
>
static bool generate(OutputIterator& sink, Context& context
, Delimiter const& d, Attribute const& attr)
{
typedef karma::detail::iterator_sink<
OutputIterator, Char, CharEncoding, Tag
> sink_device;
if (!traits::has_optional_value(attr))
return false;
// use existing operator<<()
typedef typename attribute<Context>::type attribute_type;
boost::iostreams::stream<sink_device> ostr(sink);
ostr << traits::extract_from<attribute_type>(attr, context) << std::flush;
if (ostr.good())
return karma::delimit_out(sink, d); // always do post-delimiting
return false;
}
// this is a special overload to detect if the output iterator has been
// generated by a format_manip object.
template <
typename T, typename Traits, typename Properties, typename Context
, typename Delimiter, typename Attribute
>
static bool generate(
karma::detail::output_iterator<
karma::ostream_iterator<T, Char, Traits>, Properties
>& sink, Context& context, Delimiter const& d
, Attribute const& attr)
{
typedef karma::detail::output_iterator<
karma::ostream_iterator<T, Char, Traits>, Properties
> output_iterator;
typedef karma::detail::iterator_sink<
output_iterator, Char, CharEncoding, Tag
> sink_device;
if (!traits::has_optional_value(attr))
return false;
// use existing operator<<()
typedef typename attribute<Context>::type attribute_type;
boost::iostreams::stream<sink_device> ostr(sink);
ostr.imbue(sink.get_ostream().getloc());
ostr << traits::extract_from<attribute_type>(attr, context)
<< std::flush;
if (ostr.good())
return karma::delimit_out(sink, d); // always do post-delimiting
return false;
}
// this any_stream has no parameter attached, it needs to have been
// initialized from a value/variable
template <typename OutputIterator, typename Context
, typename Delimiter>
static bool
generate(OutputIterator&, Context&, Delimiter const&, unused_type)
{
// It is not possible (doesn't make sense) to use stream generators
// without providing any attribute, as the generator doesn't 'know'
// what to output. The following assertion fires if this situation
// is detected in your code.
BOOST_SPIRIT_ASSERT_MSG(false, stream_not_usable_without_attribute, ());
return false;
}
template <typename Context>
info what(Context& /*context*/) const
{
return info("stream");
}
};
template <typename T, typename Char, typename CharEncoding, typename Tag>
struct lit_stream_generator
: primitive_generator<lit_stream_generator<T, Char, CharEncoding, Tag> >
{
template <typename Context, typename Unused>
struct attribute
{
typedef unused_type type;
};
lit_stream_generator(typename add_reference<T>::type t)
: t_(t)
{}
// lit_stream_generator has an attached parameter
// this overload will be used in the normal case (not called from
// format_manip).
template <
typename OutputIterator, typename Context, typename Delimiter
, typename Attribute>
bool generate(OutputIterator& sink, Context&, Delimiter const& d
, Attribute const&)
{
typedef karma::detail::iterator_sink<
OutputIterator, Char, CharEncoding, Tag
> sink_device;
boost::iostreams::stream<sink_device> ostr(sink);
ostr << t_ << std::flush; // use existing operator<<()
if (ostr.good())
return karma::delimit_out(sink, d); // always do post-delimiting
return false;
}
// this is a special overload to detect if the output iterator has been
// generated by a format_manip object.
template <
typename T1, typename Traits, typename Properties
, typename Context, typename Delimiter, typename Attribute>
bool generate(
karma::detail::output_iterator<
karma::ostream_iterator<T1, Char, Traits>, Properties
>& sink, Context&, Delimiter const& d, Attribute const&)
{
typedef karma::detail::output_iterator<
karma::ostream_iterator<T1, Char, Traits>, Properties
> output_iterator;
typedef karma::detail::iterator_sink<
output_iterator, Char, CharEncoding, Tag
> sink_device;
boost::iostreams::stream<sink_device> ostr(sink);
ostr.imbue(sink.get_ostream().getloc());
ostr << t_ << std::flush; // use existing operator<<()
if (ostr.good())
return karma::delimit_out(sink, d); // always do post-delimiting
return false;
}
template <typename Context>
info what(Context& /*context*/) const
{
return info("any-stream");
}
T t_;
private:
// silence MSVC warning C4512: assignment operator could not be generated
lit_stream_generator& operator= (lit_stream_generator const&);
};
///////////////////////////////////////////////////////////////////////////
// Generator generators: make_xxx function (objects)
///////////////////////////////////////////////////////////////////////////
template <typename Char, typename Modifiers>
struct make_stream
{
static bool const lower =
has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
static bool const upper =
has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
typedef any_stream_generator<
Char
, typename spirit::detail::get_encoding_with_case<
Modifiers, unused_type, lower || upper>::type
, typename detail::get_casetag<Modifiers, lower || upper>::type
> result_type;
result_type operator()(unused_type, unused_type) const
{
return result_type();
}
};
// stream
template <typename Modifiers>
struct make_primitive<tag::stream, Modifiers>
: make_stream<char, Modifiers> {};
// wstream
template <typename Modifiers>
struct make_primitive<tag::wstream, Modifiers>
: make_stream<wchar_t, Modifiers> {};
// any_stream_generator<char_type>
template <typename Char, typename Modifiers>
struct make_primitive<tag::stream_tag<Char>, Modifiers>
: make_stream<Char, Modifiers> {};
///////////////////////////////////////////////////////////////////////////
template <typename Char, typename A0, typename Modifiers>
struct make_any_stream
{
static bool const lower =
has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
static bool const upper =
has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
typedef typename add_const<A0>::type const_attribute;
typedef lit_stream_generator<
const_attribute, Char
, typename spirit::detail::get_encoding_with_case<
Modifiers, unused_type, lower || upper>::type
, typename detail::get_casetag<Modifiers, lower || upper>::type
> result_type;
template <typename Terminal>
result_type operator()(Terminal const& term, unused_type) const
{
return result_type(fusion::at_c<0>(term.args));
}
};
// stream(...)
template <typename Modifiers, typename A0>
struct make_primitive<
terminal_ex<tag::stream, fusion::vector1<A0> >, Modifiers>
: make_any_stream<char, A0, Modifiers> {};
// wstream(...)
template <typename Modifiers, typename A0>
struct make_primitive<
terminal_ex<tag::wstream, fusion::vector1<A0> >, Modifiers>
: make_any_stream<wchar_t, A0, Modifiers> {};
// any_stream_generator<char_type>(...)
template <typename Char, typename Modifiers, typename A0>
struct make_primitive<
terminal_ex<tag::stream_tag<Char>, fusion::vector1<A0> >
, Modifiers>
: make_any_stream<Char, A0, Modifiers> {};
}}}
#endif