1 // Copyright Daniel Wallin 2007. Use, modification and distribution is
2 // subject to the Boost Software License, Version 1.0. (See accompanying
3 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
4 
5 #ifndef LUABIND_ITERATOR_POLICY_071111_HPP
6 # define LUABIND_ITERATOR_POLICY_071111_HPP
7 
8 # include <luabind/config.hpp>           // for LUABIND_ANONYMOUS_FIX
9 # include <luabind/detail/convert_to_lua.hpp>  // for convert_to_lua
10 # include <luabind/detail/policy.hpp>    // for index_map, etc
11 
12 # include <new>                          // for operator new
13 
14 namespace luabind { namespace detail {
15 
16 struct null_type;
17 
18 template <class Iterator>
19 struct iterator
20 {
nextluabind::detail::iterator21     static int next(lua_State* L)
22     {
23         iterator* self = static_cast<iterator*>(
24             lua_touserdata(L, lua_upvalueindex(1)));
25 
26         if (self->first != self->last)
27         {
28             convert_to_lua(L, *self->first);
29             ++self->first;
30         }
31         else
32         {
33             lua_pushnil(L);
34         }
35 
36         return 1;
37     }
38 
destroyluabind::detail::iterator39     static int destroy(lua_State* L)
40     {
41         iterator* self = static_cast<iterator*>(lua_touserdata(L, 1));
42         self->~iterator();
43         (void)self; // MSVC warns about self not being referenced.
44         return 0;
45     }
46 
iteratorluabind::detail::iterator47     iterator(Iterator first_, Iterator last_)
48       : first(first_)
49       , last(last_)
50     {}
51 
52     Iterator first;
53     Iterator last;
54 };
55 
56 template <class Iterator>
make_range(lua_State * L,Iterator first,Iterator last)57 int make_range(lua_State* L, Iterator first, Iterator last)
58 {
59     void* storage = lua_newuserdata(L, sizeof(iterator<Iterator>));
60     lua_createtable(L, 0, 1);
61     lua_pushcclosure(L, iterator<Iterator>::destroy, 0);
62     lua_setfield(L, -2, "__gc");
63     lua_setmetatable(L, -2);
64     lua_pushcclosure(L, iterator<Iterator>::next, 1);
65     new (storage) iterator<Iterator>(first, last);
66     return 1;
67 }
68 
69 template <class Container>
make_range(lua_State * L,Container & container)70 int make_range(lua_State* L, Container& container)
71 {
72     return make_range(L, container.begin(), container.end());
73 }
74 
75 struct iterator_converter
76 {
77     typedef iterator_converter type;
78 
79     template <class Container>
applyluabind::detail::iterator_converter80     void apply(lua_State* L, Container& container)
81     {
82         make_range(L, container);
83     }
84 
85     template <class Container>
applyluabind::detail::iterator_converter86     void apply(lua_State* L, Container const& container)
87     {
88         make_range(L, container);
89     }
90 };
91 
92 struct iterator_policy : conversion_policy<0>
93 {
precallluabind::detail::iterator_policy94     static void precall(lua_State*, index_map const&)
95     {}
96 
postcallluabind::detail::iterator_policy97     static void postcall(lua_State*, index_map const&)
98     {}
99 
100     template <class T, class Direction>
101     struct apply
102     {
103         typedef iterator_converter type;
104     };
105 };
106 
107 }} // namespace luabind::detail
108 
109 namespace luabind {
110 
111     detail::policy_cons<detail::iterator_policy, detail::null_type> const
112         return_stl_iterator = {};
113 
114     namespace detail
115     {
ignore_unused_return_stl_iterator()116         inline void ignore_unused_return_stl_iterator()
117         {
118             (void)return_stl_iterator;
119         }
120     }
121 
122 } // namespace luabind
123 
124 #endif // LUABIND_ITERATOR_POLICY__071111_HPP
125