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