summaryrefslogtreecommitdiff
path: root/boost/spirit/home/support/modify.hpp
blob: 80d2f71b71e7853456eeb8fce157833544344801 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/*=============================================================================
  Copyright (c) 2001-2011 Joel de Guzman
  http://spirit.sourceforge.net/

  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 BOOST_SPIRIT_MODIFY_OCTOBER_25_2008_0142PM
#define BOOST_SPIRIT_MODIFY_OCTOBER_25_2008_0142PM

#if defined(_MSC_VER)
#pragma once
#endif

#include <boost/spirit/include/phoenix_limits.hpp>      // needs to be included before proto
#include <boost/proto/proto.hpp>
#include <boost/mpl/if.hpp>
#include <boost/type_traits/is_base_of.hpp>
#include <boost/spirit/home/support/unused.hpp>

namespace boost { namespace spirit
{
    template <typename Domain, typename T, typename Enable = void>
    struct is_modifier_directive;

    // Testing if a modifier set includes a modifier T involves
    // checking for inheritance (i.e. Modifiers is derived from T)
    template <typename Modifiers, typename T>
    struct has_modifier
        : is_base_of<T, Modifiers> {};

    // Adding modifiers is done using multi-inheritance
    template <typename Current, typename New, typename Enable = void>
    struct compound_modifier : Current, New
    {
        compound_modifier()
          : Current(), New() {}

        compound_modifier(Current const& current, New const& new_)
          : Current(current), New(new_) {}
    };

    // Don't add if New is already in Current
    template <typename Current, typename New>
    struct compound_modifier<
        Current, New, typename enable_if<has_modifier<Current, New> >::type>
      : Current
    {
        compound_modifier()
          : Current() {}

        compound_modifier(Current const& current, New const&)
          : Current(current) {}
    };

    // Special case if Current is unused_type
    template <typename New, typename Enable>
    struct compound_modifier<unused_type, New, Enable> : New
    {
        compound_modifier()
          : New() {}

        compound_modifier(unused_type, New const& new_)
          : New(new_) {}
    };

    // Domains may specialize this modify metafunction to allow
    // directives to add information to the Modifier template
    // parameter that is passed to the make_component metafunction.
    // By default, we return the modifiers untouched
    template <typename Domain, typename Enable = void>
    struct modify
    {
        template <typename Sig>
        struct result;

        template <typename This, typename Tag, typename Modifiers>
        struct result<This(Tag, Modifiers)>
        {
            typedef typename remove_const<
                typename remove_reference<Tag>::type>::type
            tag_type;
            typedef typename remove_const<
                typename remove_reference<Modifiers>::type>::type
            modifiers_type;

            typedef typename mpl::if_<
                is_modifier_directive<Domain, tag_type>
              , compound_modifier<modifiers_type, tag_type>
              , Modifiers>::type
            type;
        };

        template <typename Tag, typename Modifiers>
        typename result<modify(Tag, Modifiers)>::type
        operator()(Tag tag, Modifiers modifiers) const
        {
            return op(tag, modifiers, is_modifier_directive<Domain, Tag>());
        }

        template <typename Tag, typename Modifiers>
        Modifiers
        op(Tag /*tag*/, Modifiers modifiers, mpl::false_) const
        {
            return modifiers;
        }

        template <typename Tag, typename Modifiers>
        compound_modifier<Modifiers, Tag>
        op(Tag tag, Modifiers modifiers, mpl::true_) const
        {
            return compound_modifier<Modifiers, Tag>(modifiers, tag);
        }
    };
}}

namespace boost { namespace proto
{
    template <typename Domain, typename Enable>
    struct is_callable<spirit::modify<Domain, Enable> >
      : mpl::true_ {};
}}

#endif