]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/metaparse/tools/string_headers.py
update sources to v12.2.3
[ceph.git] / ceph / src / boost / libs / metaparse / tools / string_headers.py
CommitLineData
7c673cae
FG
1#!/usr/bin/python
2"""Utility to generate the header files for BOOST_METAPARSE_STRING"""
3
4# Copyright Abel Sinkovics (abel@sinkovics.hu) 2016.
5# Distributed under the Boost Software License, Version 1.0.
6# (See accompanying file LICENSE_1_0.txt or copy at
7# http://www.boost.org/LICENSE_1_0.txt)
8
9import argparse
10import math
11import os
12import sys
13
14
15VERSION = 1
16
17
18class Namespace(object):
19 """Generate namespace definition"""
20
21 def __init__(self, out_f, names):
22 self.out_f = out_f
23 self.names = names
24
25 def begin(self):
26 """Generate the beginning part"""
27 self.out_f.write('\n')
28 for depth, name in enumerate(self.names):
29 self.out_f.write(
30 '{0}namespace {1}\n{0}{{\n'.format(self.prefix(depth), name)
31 )
32
33 def end(self):
34 """Generate the closing part"""
35 for depth in xrange(len(self.names) - 1, -1, -1):
36 self.out_f.write('{0}}}\n'.format(self.prefix(depth)))
37
38 def prefix(self, depth=None):
39 """Returns the prefix of a given depth. Returns the prefix code inside
40 the namespace should use when depth is None."""
41 if depth is None:
42 depth = len(self.names)
43 return ' ' * depth
44
45 def __enter__(self):
46 self.begin()
47 return self
48
49 def __exit__(self, typ, value, traceback):
50 self.end()
51
52
53def write_autogen_info(out_f):
54 """Write the comment about the file being autogenerated"""
55 out_f.write(
56 '\n'
57 '// This is an automatically generated header file.\n'
58 '// Generated with the tools/string_headers.py utility of\n'
59 '// Boost.Metaparse\n'
60 )
61
62
63class IncludeGuard(object):
64 """Generate include guards"""
65
b32b8144 66 def __init__(self, out_f):
7c673cae 67 self.out_f = out_f
7c673cae
FG
68
69 def begin(self):
70 """Generate the beginning part"""
b32b8144 71 name = 'BOOST_METAPARSE_V1_CPP11_IMPL_STRING_HPP'
7c673cae
FG
72 self.out_f.write('#ifndef {0}\n#define {0}\n'.format(name))
73 write_autogen_info(self.out_f)
74
75 def end(self):
76 """Generate the closing part"""
77 self.out_f.write('\n#endif\n')
78
79 def __enter__(self):
80 self.begin()
81 return self
82
83 def __exit__(self, typ, value, traceback):
84 self.end()
85
86
87def macro_name(name):
88 """Generate the full macro name"""
89 return 'BOOST_METAPARSE_V{0}_{1}'.format(VERSION, name)
90
91
92def define_macro(out_f, (name, args, body), undefine=False, check=True):
93 """Generate a macro definition or undefinition"""
94 if undefine:
95 out_f.write(
96 '#undef {0}\n'
97 .format(macro_name(name))
98 )
99 else:
b32b8144 100 if args:
7c673cae
FG
101 arg_list = '({0})'.format(', '.join(args))
102 else:
103 arg_list = ''
104
105 if check:
106 out_f.write(
107 '#ifdef {0}\n'
108 '# error {0} already defined.\n'
109 '#endif\n'
110 .format(macro_name(name))
111 )
112
113 out_f.write(
114 '#define {0}{1} {2}\n'.format(macro_name(name), arg_list, body)
115 )
116
117
118def filename(out_dir, name, undefine=False):
119 """Generate the filename"""
120 if undefine:
121 prefix = 'undef_'
122 else:
123 prefix = ''
124 return os.path.join(out_dir, '{0}{1}.hpp'.format(prefix, name.lower()))
125
126
127def length_limits(max_length_limit, length_limit_step):
128 """Generates the length limits"""
129 string_len = len(str(max_length_limit))
130 return [
131 str(i).zfill(string_len) for i in
132 xrange(
133 length_limit_step,
134 max_length_limit + length_limit_step - 1,
135 length_limit_step
136 )
137 ]
138
139
140def unique_names(count):
141 """Generate count unique variable name"""
142 return ('C{0}'.format(i) for i in xrange(0, count))
143
144
145def generate_take(out_f, steps, line_prefix):
146 """Generate the take function"""
147 out_f.write(
148 '{0}constexpr inline int take(int n_)\n'
149 '{0}{{\n'
150 '{0} return {1} 0 {2};\n'
151 '{0}}}\n'
152 '\n'.format(
153 line_prefix,
154 ''.join('n_ >= {0} ? {0} : ('.format(s) for s in steps),
155 ')' * len(steps)
156 )
157 )
158
159
160def generate_make_string(out_f, max_step):
161 """Generate the make_string template"""
162 steps = [2 ** n for n in xrange(int(math.log(max_step, 2)), -1, -1)]
163
164 with Namespace(
165 out_f,
166 ['boost', 'metaparse', 'v{0}'.format(VERSION), 'impl']
167 ) as nsp:
168 generate_take(out_f, steps, nsp.prefix())
169
170 out_f.write(
171 '{0}template <int LenNow, int LenRemaining, char... Cs>\n'
172 '{0}struct make_string;\n'
173 '\n'
174 '{0}template <char... Cs>'
175 ' struct make_string<0, 0, Cs...> : string<> {{}};\n'
176 .format(nsp.prefix())
177 )
178
179 disable_sun = False
180 for i in reversed(steps):
181 if i > 64 and not disable_sun:
182 out_f.write('#ifndef __SUNPRO_CC\n')
183 disable_sun = True
184 out_f.write(
185 '{0}template <int LenRemaining,{1}char... Cs>'
186 ' struct make_string<{2},LenRemaining,{3}Cs...> :'
187 ' concat<string<{4}>,'
188 ' typename make_string<take(LenRemaining),'
189 'LenRemaining-take(LenRemaining),Cs...>::type> {{}};\n'
190 .format(
191 nsp.prefix(),
192 ''.join('char {0},'.format(n) for n in unique_names(i)),
193 i,
194 ''.join('{0},'.format(n) for n in unique_names(i)),
195 ','.join(unique_names(i))
196 )
197 )
198 if disable_sun:
199 out_f.write('#endif\n')
200
201
202def generate_string(out_dir, limits):
203 """Generate string.hpp"""
204 max_limit = max((int(v) for v in limits))
205
206 with open(filename(out_dir, 'string'), 'wb') as out_f:
b32b8144 207 with IncludeGuard(out_f):
7c673cae
FG
208 out_f.write(
209 '\n'
b32b8144 210 '#include <boost/metaparse/v{0}/cpp11/impl/concat.hpp>\n'
7c673cae
FG
211 '#include <boost/preprocessor/cat.hpp>\n'
212 .format(VERSION)
213 )
214
215 generate_make_string(out_f, 512)
216
217 out_f.write(
218 '\n'
219 '#ifndef BOOST_METAPARSE_LIMIT_STRING_SIZE\n'
220 '# error BOOST_METAPARSE_LIMIT_STRING_SIZE not defined\n'
221 '#endif\n'
222 '\n'
223 '#if BOOST_METAPARSE_LIMIT_STRING_SIZE > {0}\n'
224 '# error BOOST_METAPARSE_LIMIT_STRING_SIZE is greater than'
225 ' {0}. To increase the limit run tools/string_headers.py of'
226 ' Boost.Metaparse against your Boost headers.\n'
227 '#endif\n'
228 '\n'
229 .format(max_limit)
230 )
231
232 define_macro(out_f, (
233 'STRING',
234 ['s'],
235 '{0}::make_string< '
236 '{0}::take(sizeof(s)-1), sizeof(s)-1-{0}::take(sizeof(s)-1),'
237 'BOOST_PP_CAT({1}, BOOST_METAPARSE_LIMIT_STRING_SIZE)(s)'
238 '>::type'
239 .format(
240 '::boost::metaparse::v{0}::impl'.format(VERSION),
241 macro_name('I')
242 )
243 ))
244
245 out_f.write('\n')
246 for limit in xrange(0, max_limit + 1):
247 out_f.write(
248 '#define {0} {1}\n'
249 .format(
250 macro_name('I{0}'.format(limit)),
251 macro_name('INDEX_STR{0}'.format(
252 min(int(l) for l in limits if int(l) >= limit)
253 ))
254 )
255 )
256 out_f.write('\n')
257
258 prev_macro = None
259 prev_limit = 0
260 for length_limit in (int(l) for l in limits):
261 this_macro = macro_name('INDEX_STR{0}'.format(length_limit))
262 out_f.write(
263 '#define {0}(s) {1}{2}\n'
264 .format(
265 this_macro,
266 '{0}(s),'.format(prev_macro) if prev_macro else '',
267 ','.join(
268 '{0}((s), {1})'
269 .format(macro_name('STRING_AT'), i)
270 for i in xrange(prev_limit, length_limit)
271 )
272 )
273 )
274 prev_macro = this_macro
275 prev_limit = length_limit
276
277
278def positive_integer(value):
279 """Throws when the argument is not a positive integer"""
280 val = int(value)
281 if val > 0:
282 return val
283 else:
284 raise argparse.ArgumentTypeError("A positive number is expected")
285
286
287def existing_path(value):
288 """Throws when the path does not exist"""
289 if os.path.exists(value):
290 return value
291 else:
292 raise argparse.ArgumentTypeError("Path {0} not found".format(value))
293
294
295def main():
296 """The main function of the script"""
297 parser = argparse.ArgumentParser(description=__doc__)
298 parser.add_argument(
299 '--boost_dir',
300 required=False,
301 type=existing_path,
302 help='The path to the include/boost directory of Metaparse'
303 )
304 parser.add_argument(
305 '--max_length_limit',
306 required=False,
307 default=2048,
308 type=positive_integer,
309 help='The maximum supported length limit'
310 )
311 parser.add_argument(
312 '--length_limit_step',
313 required=False,
314 default=128,
315 type=positive_integer,
316 help='The longest step at which headers are generated'
317 )
318 args = parser.parse_args()
319
320 if args.boost_dir is None:
321 tools_path = os.path.dirname(os.path.abspath(__file__))
322 boost_dir = os.path.join(
323 os.path.dirname(tools_path),
324 'include',
325 'boost'
326 )
327 else:
328 boost_dir = args.boost_dir
329
330 if args.max_length_limit < 1:
331 sys.stderr.write('Invalid maximum length limit')
332 sys.exit(-1)
333
334 generate_string(
b32b8144
FG
335 os.path.join(
336 boost_dir,
337 'metaparse',
338 'v{0}'.format(VERSION),
339 'cpp11',
340 'impl'
341 ),
7c673cae
FG
342 length_limits(args.max_length_limit, args.length_limit_step)
343 )
344
345
346if __name__ == '__main__':
347 main()