From 19fcec84d8d7d21e796c7624e521b60d28ee21ed Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 20:45:59 +0200 Subject: Adding upstream version 16.2.11+ds. Signed-off-by: Daniel Baumann --- src/boost/libs/metaparse/tools/benchmark/README.md | 14 + .../libs/metaparse/tools/benchmark/benchmark.py | 354 +++++++++++++++++++++ .../libs/metaparse/tools/benchmark/char_stat.py | 59 ++++ src/boost/libs/metaparse/tools/benchmark/chars.py | 1 + .../libs/metaparse/tools/benchmark/generate.py | 299 +++++++++++++++++ .../tools/benchmark/include/benchmark_util.hpp | 281 ++++++++++++++++ .../metaparse/tools/benchmark/src/length128.cpp | 18 ++ .../metaparse/tools/benchmark/src/max_length.cpp | 21 ++ .../libs/metaparse/tools/benchmark/src/number.cpp | 18 ++ .../libs/metaparse/tools/build_environment.py | 134 ++++++++ src/boost/libs/metaparse/tools/deps.json | 60 ++++ src/boost/libs/metaparse/tools/generate_all.py | 295 +++++++++++++++++ src/boost/libs/metaparse/tools/string_headers.py | 347 ++++++++++++++++++++ 13 files changed, 1901 insertions(+) create mode 100644 src/boost/libs/metaparse/tools/benchmark/README.md create mode 100755 src/boost/libs/metaparse/tools/benchmark/benchmark.py create mode 100755 src/boost/libs/metaparse/tools/benchmark/char_stat.py create mode 100644 src/boost/libs/metaparse/tools/benchmark/chars.py create mode 100755 src/boost/libs/metaparse/tools/benchmark/generate.py create mode 100644 src/boost/libs/metaparse/tools/benchmark/include/benchmark_util.hpp create mode 100644 src/boost/libs/metaparse/tools/benchmark/src/length128.cpp create mode 100644 src/boost/libs/metaparse/tools/benchmark/src/max_length.cpp create mode 100644 src/boost/libs/metaparse/tools/benchmark/src/number.cpp create mode 100755 src/boost/libs/metaparse/tools/build_environment.py create mode 100644 src/boost/libs/metaparse/tools/deps.json create mode 100755 src/boost/libs/metaparse/tools/generate_all.py create mode 100755 src/boost/libs/metaparse/tools/string_headers.py (limited to 'src/boost/libs/metaparse/tools') diff --git a/src/boost/libs/metaparse/tools/benchmark/README.md b/src/boost/libs/metaparse/tools/benchmark/README.md new file mode 100644 index 000000000..b2fbf2446 --- /dev/null +++ b/src/boost/libs/metaparse/tools/benchmark/README.md @@ -0,0 +1,14 @@ +This directory contains benchmarks for the library. + +The characters to use in the benchmarks and their distribution is coming from +`chars.py`. This is an automatically generated file and can be regenerated using +`char_stat.py`. It represents the distribution of characters of the Boost 1.61.0 +header files. + +To regenerate the benchmarks: + +* Generate the source files by running `generate.py`. Unless specified + otherwise, it will generate the source files found in `src` to `generated`. +* Run the benchmarks by running `benchmark.py`. Unless specified otherwise, it + will benchmark the compilation of the source files in `generated` and generate + the diagrams into the library's documentation. diff --git a/src/boost/libs/metaparse/tools/benchmark/benchmark.py b/src/boost/libs/metaparse/tools/benchmark/benchmark.py new file mode 100755 index 000000000..46d3ef9fa --- /dev/null +++ b/src/boost/libs/metaparse/tools/benchmark/benchmark.py @@ -0,0 +1,354 @@ +#!/usr/bin/python +"""Utility to benchmark the generated source files""" + +# Copyright Abel Sinkovics (abel@sinkovics.hu) 2016. +# 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) + +import argparse +import os +import subprocess +import json +import math +import platform +import matplotlib +import random +import re +import time +import psutil +import PIL + +matplotlib.use('Agg') +import matplotlib.pyplot # pylint:disable=I0011,C0411,C0412,C0413 + + +def benchmark_command(cmd, progress): + """Benchmark one command execution""" + full_cmd = '/usr/bin/time --format="%U %M" {0}'.format(cmd) + print '{0:6.2f}% Running {1}'.format(100.0 * progress, full_cmd) + (_, err) = subprocess.Popen( + ['/bin/sh', '-c', full_cmd], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE + ).communicate('') + + values = err.strip().split(' ') + if len(values) == 2: + try: + return (float(values[0]), float(values[1])) + except: # pylint:disable=I0011,W0702 + pass # Handled by the code after the "if" + + print err + raise Exception('Error during benchmarking') + + +def benchmark_file( + filename, compiler, include_dirs, (progress_from, progress_to), + iter_count, extra_flags = ''): + """Benchmark one file""" + time_sum = 0 + mem_sum = 0 + for nth_run in xrange(0, iter_count): + (time_spent, mem_used) = benchmark_command( + '{0} -std=c++11 {1} -c {2} {3}'.format( + compiler, + ' '.join('-I{0}'.format(i) for i in include_dirs), + filename, + extra_flags + ), + ( + progress_to * nth_run + progress_from * (iter_count - nth_run) + ) / iter_count + ) + os.remove(os.path.splitext(os.path.basename(filename))[0] + '.o') + time_sum = time_sum + time_spent + mem_sum = mem_sum + mem_used + + return { + "time": time_sum / iter_count, + "memory": mem_sum / (iter_count * 1024) + } + + +def compiler_info(compiler): + """Determine the name + version of the compiler""" + (out, err) = subprocess.Popen( + ['/bin/sh', '-c', '{0} -v'.format(compiler)], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE + ).communicate('') + + gcc_clang = re.compile('(gcc|clang) version ([0-9]+(\\.[0-9]+)*)') + + for line in (out + err).split('\n'): + mtch = gcc_clang.search(line) + if mtch: + return mtch.group(1) + ' ' + mtch.group(2) + + return compiler + + +def string_char(char): + """Turn the character into one that can be part of a filename""" + return '_' if char in [' ', '~', '(', ')', '/', '\\'] else char + + +def make_filename(string): + """Turn the string into a filename""" + return ''.join(string_char(c) for c in string) + + +def files_in_dir(path, extension): + """Enumartes the files in path with the given extension""" + ends = '.{0}'.format(extension) + return (f for f in os.listdir(path) if f.endswith(ends)) + + +def format_time(seconds): + """Format a duration""" + minute = 60 + hour = minute * 60 + day = hour * 24 + week = day * 7 + + result = [] + for name, dur in [ + ('week', week), ('day', day), ('hour', hour), + ('minute', minute), ('second', 1) + ]: + if seconds > dur: + value = seconds // dur + result.append( + '{0} {1}{2}'.format(int(value), name, 's' if value > 1 else '') + ) + seconds = seconds % dur + return ' '.join(result) + + +def benchmark(src_dir, compiler, include_dirs, iter_count): + """Do the benchmarking""" + + files = list(files_in_dir(src_dir, 'cpp')) + random.shuffle(files) + has_string_templates = True + string_template_file_cnt = sum(1 for file in files if 'bmp' in file) + file_count = len(files) + string_template_file_cnt + + started_at = time.time() + result = {} + for filename in files: + progress = len(result) + result[filename] = benchmark_file( + os.path.join(src_dir, filename), + compiler, + include_dirs, + (float(progress) / file_count, float(progress + 1) / file_count), + iter_count + ) + if 'bmp' in filename and has_string_templates: + try: + temp_result = benchmark_file( + os.path.join(src_dir, filename), + compiler, + include_dirs, + (float(progress + 1) / file_count, float(progress + 2) / file_count), + iter_count, + '-Xclang -fstring-literal-templates' + ) + result[filename.replace('bmp', 'slt')] = temp_result + except: + has_string_templates = False + file_count -= string_template_file_cnt + print 'Stopping the benchmarking of string literal templates' + + elapsed = time.time() - started_at + total = float(file_count * elapsed) / len(result) + print 'Elapsed time: {0}, Remaining time: {1}'.format( + format_time(elapsed), + format_time(total - elapsed) + ) + return result + + +def plot(values, mode_names, title, (xlabel, ylabel), out_file): + """Plot a diagram""" + matplotlib.pyplot.clf() + for mode, mode_name in mode_names.iteritems(): + vals = values[mode] + matplotlib.pyplot.plot( + [x for x, _ in vals], + [y for _, y in vals], + label=mode_name + ) + matplotlib.pyplot.title(title) + matplotlib.pyplot.xlabel(xlabel) + matplotlib.pyplot.ylabel(ylabel) + if len(mode_names) > 1: + matplotlib.pyplot.legend() + matplotlib.pyplot.savefig(out_file) + + +def mkdir_p(path): + """mkdir -p path""" + try: + os.makedirs(path) + except OSError: + pass + + +def configs_in(src_dir): + """Enumerate all configs in src_dir""" + for filename in files_in_dir(src_dir, 'json'): + with open(os.path.join(src_dir, filename), 'rb') as in_f: + yield json.load(in_f) + + +def byte_to_gb(byte): + """Convert bytes to GB""" + return byte / (1024.0 * 1024 * 1024) + + +def join_images(img_files, out_file): + """Join the list of images into the out file""" + images = [PIL.Image.open(f) for f in img_files] + joined = PIL.Image.new( + 'RGB', + (sum(i.size[0] for i in images), max(i.size[1] for i in images)) + ) + left = 0 + for img in images: + joined.paste(im=img, box=(left, 0)) + left = left + img.size[0] + joined.save(out_file) + + +def plot_temp_diagrams(config, results, temp_dir): + """Plot temporary diagrams""" + display_name = { + 'time': 'Compilation time (s)', + 'memory': 'Compiler memory usage (MB)', + } + + files = config['files'] + img_files = [] + + if any('slt' in result for result in results) and 'bmp' in files.values()[0]: + config['modes']['slt'] = 'Using BOOST_METAPARSE_STRING with string literal templates' + for f in files.values(): + f['slt'] = f['bmp'].replace('bmp', 'slt') + + for measured in ['time', 'memory']: + mpts = sorted(int(k) for k in files.keys()) + img_files.append(os.path.join(temp_dir, '_{0}.png'.format(measured))) + plot( + { + m: [(x, results[files[str(x)][m]][measured]) for x in mpts] + for m in config['modes'].keys() + }, + config['modes'], + display_name[measured], + (config['x_axis_label'], display_name[measured]), + img_files[-1] + ) + return img_files + + +def plot_diagram(config, results, images_dir, out_filename): + """Plot one diagram""" + img_files = plot_temp_diagrams(config, results, images_dir) + join_images(img_files, out_filename) + for img_file in img_files: + os.remove(img_file) + + +def plot_diagrams(results, configs, compiler, out_dir): + """Plot all diagrams specified by the configs""" + compiler_fn = make_filename(compiler) + total = psutil.virtual_memory().total # pylint:disable=I0011,E1101 + memory = int(math.ceil(byte_to_gb(total))) + + images_dir = os.path.join(out_dir, 'images') + + for config in configs: + out_prefix = '{0}_{1}'.format(config['name'], compiler_fn) + + plot_diagram( + config, + results, + images_dir, + os.path.join(images_dir, '{0}.png'.format(out_prefix)) + ) + + with open( + os.path.join(out_dir, '{0}.qbk'.format(out_prefix)), + 'wb' + ) as out_f: + qbk_content = """{0} +Measured on a {2} host with {3} GB memory. Compiler used: {4}. + +[$images/metaparse/{1}.png [width 100%]] +""".format(config['desc'], out_prefix, platform.platform(), memory, compiler) + out_f.write(qbk_content) + + +def main(): + """The main function of the script""" + desc = 'Benchmark the files generated by generate.py' + parser = argparse.ArgumentParser(description=desc) + parser.add_argument( + '--src', + dest='src_dir', + default='generated', + help='The directory containing the sources to benchmark' + ) + parser.add_argument( + '--out', + dest='out_dir', + default='../../doc', + help='The output directory' + ) + parser.add_argument( + '--include', + dest='include', + default='include', + help='The directory containing the headeres for the benchmark' + ) + parser.add_argument( + '--boost_headers', + dest='boost_headers', + default='../../../..', + help='The directory containing the Boost headers (the boost directory)' + ) + parser.add_argument( + '--compiler', + dest='compiler', + default='g++', + help='The compiler to do the benchmark with' + ) + parser.add_argument( + '--repeat_count', + dest='repeat_count', + type=int, + default=5, + help='How many times a measurement should be repeated.' + ) + + args = parser.parse_args() + + compiler = compiler_info(args.compiler) + results = benchmark( + args.src_dir, + args.compiler, + [args.include, args.boost_headers], + args.repeat_count + ) + + plot_diagrams(results, configs_in(args.src_dir), compiler, args.out_dir) + + +if __name__ == '__main__': + main() diff --git a/src/boost/libs/metaparse/tools/benchmark/char_stat.py b/src/boost/libs/metaparse/tools/benchmark/char_stat.py new file mode 100755 index 000000000..be5935dd6 --- /dev/null +++ b/src/boost/libs/metaparse/tools/benchmark/char_stat.py @@ -0,0 +1,59 @@ +#!/usr/bin/python +"""Utility to generate character statistics about a number of source files""" + +# Copyright Abel Sinkovics (abel@sinkovics.hu) 2016. +# 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) + +import argparse +import os + + +def count_characters(root, out): + """Count the occurrances of the different characters in the files""" + if os.path.isfile(root): + with open(root, 'rb') as in_f: + for line in in_f: + for char in line: + if char not in out: + out[char] = 0 + out[char] = out[char] + 1 + elif os.path.isdir(root): + for filename in os.listdir(root): + count_characters(os.path.join(root, filename), out) + + +def generate_statistics(root): + """Generate the statistics from all files in root (recursively)""" + out = dict() + count_characters(root, out) + return out + + +def main(): + """The main function of the script""" + desc = 'Generate character statistics from a source tree' + parser = argparse.ArgumentParser(description=desc) + parser.add_argument( + '--src', + dest='src', + required=True, + help='The root of the source tree' + ) + parser.add_argument( + '--out', + dest='out', + default='chars.py', + help='The output filename' + ) + + args = parser.parse_args() + + stats = generate_statistics(args.src) + with open(args.out, 'wb') as out_f: + out_f.write('CHARS={0}\n'.format(stats)) + + +if __name__ == '__main__': + main() diff --git a/src/boost/libs/metaparse/tools/benchmark/chars.py b/src/boost/libs/metaparse/tools/benchmark/chars.py new file mode 100644 index 000000000..95357f1eb --- /dev/null +++ b/src/boost/libs/metaparse/tools/benchmark/chars.py @@ -0,0 +1 @@ +CHARS={' ': 22284371, '\xa3': 2, '$': 4917, '\xa7': 3, '(': 898226, '\xab': 2, ',': 2398845, '\xaf': 2, '0': 624709, '\xb3': 5, '4': 402093, '\xb7': 2, '8': 274327, '\xbb': 2, '<': 906955, '\xbf': 2, '@': 16983, '\xc3': 13, 'D': 291316, '\xc7': 2, 'H': 146671, '\xcb': 2, 'L': 404004, '\xcf': 2, 'P': 717827, '\xd3': 2, 'T': 1426865, '\xd7': 2, 'X': 80953, '\xdb': 2, '\\': 80171, '\xdf': 5, '`': 12213, '\xe3': 2, 'd': 1713185, '\xe7': 2, 'h': 787023, '\xeb': 2, 'l': 2141123, '\xef': 2, 'p': 3018561, '\xf3': 2, 't': 5917113, '\xf7': 2, 'x': 383286, '\xfb': 2, '|': 18625, '\xff': 2, '\x80': 20, '\x9c': 10, '#': 242175, '\xa4': 2, "'": 24359, '\xa8': 2, '+': 62328, '\xac': 2, '/': 1496052, '\xb0': 2, '3': 522407, '\xb4': 2, '7': 281951, '\xb8': 2, ';': 938670, '\xbc': 2, '?': 6554, '\xc0': 2, 'C': 430333, '\xc4': 2, 'G': 143243, '\xc8': 2, 'K': 90732, '\xcc': 2, 'O': 875785, '\xd0': 2, 'S': 702347, '\xd4': 2, 'W': 52216, '\xd8': 2, '[': 66305, '\xdc': 2, '_': 2992229, '\xe0': 2, 'c': 2083806, '\xe4': 2, 'g': 684087, '\xe8': 2, 'k': 165087, '\xec': 2, 'o': 3158786, '\xf0': 2, 's': 2967238, '\xf4': 2, 'w': 247018, '\xf8': 3, '{': 243686, '\xfc': 2, '\n': 2276992, '\x9d': 10, '\xa1': 2, '"': 50327, '\xa5': 2, '&': 418128, '\xa9': 4, '*': 332039, '\xad': 5, '.': 391026, '\xb1': 5, '2': 823421, '\xb5': 2, '6': 322046, '\xb9': 2, ':': 2683679, '\xbd': 2, '>': 915244, '\xc1': 2, 'B': 412447, '\xc5': 2, 'F': 174215, '\xc9': 2, 'J': 11028, '\xcd': 2, 'N': 431761, '\xd1': 2, 'R': 370532, '\xd5': 2, 'V': 120889, '\xd9': 2, 'Z': 14849, '\xdd': 2, '^': 1667, '\xe1': 2, 'b': 645436, '\xe5': 2, 'f': 1305489, '\xe9': 30, 'j': 31303, '\xed': 3, 'n': 3384988, '\xf1': 2, 'r': 2870950, '\xf5': 2, 'v': 519257, '\xf9': 2, 'z': 96213, '\xfd': 2, '~': 13463, '\t': 2920, '\r': 2276968, '!': 72758, '\xa2': 2, '%': 7081, '\xa6': 2, ')': 899122, '\xaa': 2, '-': 325139, '\xae': 2, '1': 1292007, '\xb2': 2, '5': 326024, '\xb6': 2, '9': 258472, '\xba': 4, '=': 626629, '\xbe': 2, 'A': 1040447, '\xc2': 2, 'E': 657368, '\xc6': 2, 'I': 569518, '\xca': 2, 'M': 211683, '\xce': 2, 'Q': 21541, '\xd2': 2, 'U': 218558, '\xd6': 2, 'Y': 64741, '\xda': 2, ']': 65379, '\xde': 2, 'a': 4007230, '\xe2': 22, 'e': 7280723, '\xe6': 2, 'i': 2971166, '\xea': 2, 'm': 1989243, '\xee': 2, 'q': 63623, '\xf2': 2, 'u': 1297465, '\xf6': 30, 'y': 1819692, '\xfa': 2, '}': 242894, '\xfe': 2} diff --git a/src/boost/libs/metaparse/tools/benchmark/generate.py b/src/boost/libs/metaparse/tools/benchmark/generate.py new file mode 100755 index 000000000..52526c827 --- /dev/null +++ b/src/boost/libs/metaparse/tools/benchmark/generate.py @@ -0,0 +1,299 @@ +#!/usr/bin/python +"""Utility to generate files to benchmark""" + +# Copyright Abel Sinkovics (abel@sinkovics.hu) 2016. +# 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) + +import argparse +import os +import string +import random +import re +import json + +import Cheetah.Template +import chars + + +def regex_to_error_msg(regex): + """Format a human-readable error message from a regex""" + return re.sub('([^\\\\])[()]', '\\1', regex) \ + .replace('[ \t]*$', '') \ + .replace('^', '') \ + .replace('$', '') \ + .replace('[ \t]*', ' ') \ + .replace('[ \t]+', ' ') \ + .replace('[0-9]+', 'X') \ + \ + .replace('\\[', '[') \ + .replace('\\]', ']') \ + .replace('\\(', '(') \ + .replace('\\)', ')') \ + .replace('\\.', '.') + + +def mkdir_p(path): + """mkdir -p path""" + try: + os.makedirs(path) + except OSError: + pass + + +def in_comment(regex): + """Builds a regex matching "regex" in a comment""" + return '^[ \t]*//[ \t]*' + regex + '[ \t]*$' + + +def random_chars(number): + """Generate random characters""" + char_map = { + k: v for k, v in chars.CHARS.iteritems() + if not format_character(k).startswith('\\x') + } + + char_num = sum(char_map.values()) + return ( + format_character(nth_char(char_map, random.randint(0, char_num - 1))) + for _ in xrange(0, number) + ) + + +def random_string(length): + """Generate a random string or character list depending on the mode""" + return \ + 'BOOST_METAPARSE_STRING("{0}")'.format(''.join(random_chars(length))) + + +class Mode(object): + """Represents a generation mode""" + + def __init__(self, name): + self.name = name + if name == 'BOOST_METAPARSE_STRING': + self.identifier = 'bmp' + elif name == 'manual': + self.identifier = 'man' + else: + raise Exception('Invalid mode: {0}'.format(name)) + + def description(self): + """The description of the mode""" + if self.identifier == 'bmp': + return 'Using BOOST_METAPARSE_STRING' + elif self.identifier == 'man': + return 'Generating strings manually' + + def convert_from(self, base): + """Convert a BOOST_METAPARSE_STRING mode document into one with + this mode""" + if self.identifier == 'bmp': + return base + elif self.identifier == 'man': + result = [] + prefix = 'BOOST_METAPARSE_STRING("' + while True: + bmp_at = base.find(prefix) + if bmp_at == -1: + return ''.join(result) + base + else: + result.append( + base[0:bmp_at] + '::boost::metaparse::string<' + ) + new_base = '' + was_backslash = False + comma = '' + for i in xrange(bmp_at + len(prefix), len(base)): + if was_backslash: + result.append( + '{0}\'\\{1}\''.format(comma, base[i]) + ) + was_backslash = False + comma = ',' + elif base[i] == '"': + new_base = base[i+2:] + break + elif base[i] == '\\': + was_backslash = True + else: + result.append('{0}\'{1}\''.format(comma, base[i])) + comma = ',' + base = new_base + result.append('>') + + +class Template(object): + """Represents a loaded template""" + + def __init__(self, name, content): + self.name = name + self.content = content + + def instantiate(self, value_of_n): + """Instantiates the template""" + template = Cheetah.Template.Template( + self.content, + searchList={'n': value_of_n} + ) + template.random_string = random_string + return str(template) + + def range(self): + """Returns the range for N""" + match = self._match(in_comment( + 'n[ \t]+in[ \t]*\\[([0-9]+)\\.\\.([0-9]+)\\),[ \t]+' + 'step[ \t]+([0-9]+)' + )) + return range( + int(match.group(1)), + int(match.group(2)), + int(match.group(3)) + ) + + def property(self, name): + """Parses and returns a property""" + return self._get_line(in_comment(name + ':[ \t]*(.*)')) + + def modes(self): + """Returns the list of generation modes""" + return [Mode(s.strip()) for s in self.property('modes').split(',')] + + def _match(self, regex): + """Find the first line matching regex and return the match object""" + cregex = re.compile(regex) + for line in self.content.splitlines(): + match = cregex.match(line) + if match: + return match + raise Exception('No "{0}" line in {1}.cpp'.format( + regex_to_error_msg(regex), + self.name + )) + + def _get_line(self, regex): + """Get a line based on a regex""" + return self._match(regex).group(1) + + +def load_file(path): + """Returns the content of the file""" + with open(path, 'rb') as in_file: + return in_file.read() + + +def templates_in(path): + """Enumerate the templates found in path""" + ext = '.cpp' + return ( + Template(f[0:-len(ext)], load_file(os.path.join(path, f))) + for f in os.listdir(path) if f.endswith(ext) + ) + + +def nth_char(char_map, index): + """Returns the nth character of a character->occurrence map""" + for char in char_map: + if index < char_map[char]: + return char + index = index - char_map[char] + return None + + +def format_character(char): + """Returns the C-formatting of the character""" + if \ + char in string.ascii_letters \ + or char in string.digits \ + or char in [ + '_', '.', ':', ';', ' ', '!', '?', '+', '-', '/', '=', '<', + '>', '$', '(', ')', '@', '~', '`', '|', '#', '[', ']', '{', + '}', '&', '*', '^', '%']: + return char + elif char in ['"', '\'', '\\']: + return '\\{0}'.format(char) + elif char == '\n': + return '\\n' + elif char == '\r': + return '\\r' + elif char == '\t': + return '\\t' + else: + return '\\x{:02x}'.format(ord(char)) + + +def write_file(filename, content): + """Create the file with the given content""" + print 'Generating {0}'.format(filename) + with open(filename, 'wb') as out_f: + out_f.write(content) + + +def out_filename(template, n_val, mode): + """Determine the output filename""" + return '{0}_{1}_{2}.cpp'.format(template.name, n_val, mode.identifier) + + +def main(): + """The main function of the script""" + desc = 'Generate files to benchmark' + parser = argparse.ArgumentParser(description=desc) + parser.add_argument( + '--src', + dest='src_dir', + default='src', + help='The directory containing the templates' + ) + parser.add_argument( + '--out', + dest='out_dir', + default='generated', + help='The output directory' + ) + parser.add_argument( + '--seed', + dest='seed', + default='13', + help='The random seed (to ensure consistent regeneration)' + ) + + args = parser.parse_args() + + random.seed(int(args.seed)) + + mkdir_p(args.out_dir) + + for template in templates_in(args.src_dir): + modes = template.modes() + + n_range = template.range() + for n_value in n_range: + base = template.instantiate(n_value) + for mode in modes: + write_file( + os.path.join( + args.out_dir, + out_filename(template, n_value, mode) + ), + mode.convert_from(base) + ) + write_file( + os.path.join(args.out_dir, '{0}.json'.format(template.name)), + json.dumps({ + 'files': { + n: { + m.identifier: out_filename(template, n, m) + for m in modes + } for n in n_range + }, + 'name': template.name, + 'x_axis_label': template.property('x_axis_label'), + 'desc': template.property('desc'), + 'modes': {m.identifier: m.description() for m in modes} + }) + ) + + +if __name__ == '__main__': + main() diff --git a/src/boost/libs/metaparse/tools/benchmark/include/benchmark_util.hpp b/src/boost/libs/metaparse/tools/benchmark/include/benchmark_util.hpp new file mode 100644 index 000000000..eba88c925 --- /dev/null +++ b/src/boost/libs/metaparse/tools/benchmark/include/benchmark_util.hpp @@ -0,0 +1,281 @@ +// Copyright Szabolcs Toth (thszabi@gmail.com) 2016. +// Copyright Abel Sinkovics (abel@sinkovics.hu) 2016. +// 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) + +#include + +template +struct to_upper_char; + +template <> struct to_upper_char<-128> : boost::mpl::char_<95> {}; +template <> struct to_upper_char<-127> : boost::mpl::char_<96> {}; +template <> struct to_upper_char<-126> : boost::mpl::char_<97> {}; +template <> struct to_upper_char<-125> : boost::mpl::char_<98> {}; +template <> struct to_upper_char<-124> : boost::mpl::char_<99> {}; +template <> struct to_upper_char<-123> : boost::mpl::char_<100> {}; +template <> struct to_upper_char<-122> : boost::mpl::char_<101> {}; +template <> struct to_upper_char<-121> : boost::mpl::char_<102> {}; +template <> struct to_upper_char<-120> : boost::mpl::char_<103> {}; +template <> struct to_upper_char<-119> : boost::mpl::char_<104> {}; +template <> struct to_upper_char<-118> : boost::mpl::char_<105> {}; +template <> struct to_upper_char<-117> : boost::mpl::char_<106> {}; +template <> struct to_upper_char<-116> : boost::mpl::char_<107> {}; +template <> struct to_upper_char<-115> : boost::mpl::char_<108> {}; +template <> struct to_upper_char<-114> : boost::mpl::char_<109> {}; +template <> struct to_upper_char<-113> : boost::mpl::char_<110> {}; +template <> struct to_upper_char<-112> : boost::mpl::char_<111> {}; +template <> struct to_upper_char<-111> : boost::mpl::char_<112> {}; +template <> struct to_upper_char<-110> : boost::mpl::char_<113> {}; +template <> struct to_upper_char<-109> : boost::mpl::char_<114> {}; +template <> struct to_upper_char<-108> : boost::mpl::char_<115> {}; +template <> struct to_upper_char<-107> : boost::mpl::char_<116> {}; +template <> struct to_upper_char<-106> : boost::mpl::char_<117> {}; +template <> struct to_upper_char<-105> : boost::mpl::char_<118> {}; +template <> struct to_upper_char<-104> : boost::mpl::char_<119> {}; +template <> struct to_upper_char<-103> : boost::mpl::char_<120> {}; +template <> struct to_upper_char<-102> : boost::mpl::char_<121> {}; +template <> struct to_upper_char<-101> : boost::mpl::char_<122> {}; +template <> struct to_upper_char<-100> : boost::mpl::char_<123> {}; +template <> struct to_upper_char<-99> : boost::mpl::char_<124> {}; +template <> struct to_upper_char<-98> : boost::mpl::char_<125> {}; +template <> struct to_upper_char<-97> : boost::mpl::char_<126> {}; +template <> struct to_upper_char<-96> : boost::mpl::char_<127> {}; +template <> struct to_upper_char<-95> : boost::mpl::char_<-127> {}; +template <> struct to_upper_char<-94> : boost::mpl::char_<-126> {}; +template <> struct to_upper_char<-93> : boost::mpl::char_<-125> {}; +template <> struct to_upper_char<-92> : boost::mpl::char_<-124> {}; +template <> struct to_upper_char<-91> : boost::mpl::char_<-123> {}; +template <> struct to_upper_char<-90> : boost::mpl::char_<-122> {}; +template <> struct to_upper_char<-89> : boost::mpl::char_<-121> {}; +template <> struct to_upper_char<-88> : boost::mpl::char_<-120> {}; +template <> struct to_upper_char<-87> : boost::mpl::char_<-119> {}; +template <> struct to_upper_char<-86> : boost::mpl::char_<-118> {}; +template <> struct to_upper_char<-85> : boost::mpl::char_<-117> {}; +template <> struct to_upper_char<-84> : boost::mpl::char_<-116> {}; +template <> struct to_upper_char<-83> : boost::mpl::char_<-115> {}; +template <> struct to_upper_char<-82> : boost::mpl::char_<-114> {}; +template <> struct to_upper_char<-81> : boost::mpl::char_<-113> {}; +template <> struct to_upper_char<-80> : boost::mpl::char_<-112> {}; +template <> struct to_upper_char<-79> : boost::mpl::char_<-111> {}; +template <> struct to_upper_char<-78> : boost::mpl::char_<-110> {}; +template <> struct to_upper_char<-77> : boost::mpl::char_<-109> {}; +template <> struct to_upper_char<-76> : boost::mpl::char_<-108> {}; +template <> struct to_upper_char<-75> : boost::mpl::char_<-107> {}; +template <> struct to_upper_char<-74> : boost::mpl::char_<-106> {}; +template <> struct to_upper_char<-73> : boost::mpl::char_<-105> {}; +template <> struct to_upper_char<-72> : boost::mpl::char_<-104> {}; +template <> struct to_upper_char<-71> : boost::mpl::char_<-103> {}; +template <> struct to_upper_char<-70> : boost::mpl::char_<-102> {}; +template <> struct to_upper_char<-69> : boost::mpl::char_<-101> {}; +template <> struct to_upper_char<-68> : boost::mpl::char_<-100> {}; +template <> struct to_upper_char<-67> : boost::mpl::char_<-99> {}; +template <> struct to_upper_char<-66> : boost::mpl::char_<-98> {}; +template <> struct to_upper_char<-65> : boost::mpl::char_<-97> {}; +template <> struct to_upper_char<-64> : boost::mpl::char_<-96> {}; +template <> struct to_upper_char<-63> : boost::mpl::char_<-95> {}; +template <> struct to_upper_char<-62> : boost::mpl::char_<-94> {}; +template <> struct to_upper_char<-61> : boost::mpl::char_<-93> {}; +template <> struct to_upper_char<-60> : boost::mpl::char_<-92> {}; +template <> struct to_upper_char<-59> : boost::mpl::char_<-91> {}; +template <> struct to_upper_char<-58> : boost::mpl::char_<-90> {}; +template <> struct to_upper_char<-57> : boost::mpl::char_<-89> {}; +template <> struct to_upper_char<-56> : boost::mpl::char_<-88> {}; +template <> struct to_upper_char<-55> : boost::mpl::char_<-87> {}; +template <> struct to_upper_char<-54> : boost::mpl::char_<-86> {}; +template <> struct to_upper_char<-53> : boost::mpl::char_<-85> {}; +template <> struct to_upper_char<-52> : boost::mpl::char_<-84> {}; +template <> struct to_upper_char<-51> : boost::mpl::char_<-83> {}; +template <> struct to_upper_char<-50> : boost::mpl::char_<-82> {}; +template <> struct to_upper_char<-49> : boost::mpl::char_<-81> {}; +template <> struct to_upper_char<-48> : boost::mpl::char_<-80> {}; +template <> struct to_upper_char<-47> : boost::mpl::char_<-79> {}; +template <> struct to_upper_char<-46> : boost::mpl::char_<-78> {}; +template <> struct to_upper_char<-45> : boost::mpl::char_<-77> {}; +template <> struct to_upper_char<-44> : boost::mpl::char_<-76> {}; +template <> struct to_upper_char<-43> : boost::mpl::char_<-75> {}; +template <> struct to_upper_char<-42> : boost::mpl::char_<-74> {}; +template <> struct to_upper_char<-41> : boost::mpl::char_<-73> {}; +template <> struct to_upper_char<-40> : boost::mpl::char_<-72> {}; +template <> struct to_upper_char<-39> : boost::mpl::char_<-71> {}; +template <> struct to_upper_char<-38> : boost::mpl::char_<-70> {}; +template <> struct to_upper_char<-37> : boost::mpl::char_<-69> {}; +template <> struct to_upper_char<-36> : boost::mpl::char_<-68> {}; +template <> struct to_upper_char<-35> : boost::mpl::char_<-67> {}; +template <> struct to_upper_char<-34> : boost::mpl::char_<-66> {}; +template <> struct to_upper_char<-33> : boost::mpl::char_<-65> {}; +template <> struct to_upper_char<-32> : boost::mpl::char_<-64> {}; +template <> struct to_upper_char<-31> : boost::mpl::char_<-63> {}; +template <> struct to_upper_char<-30> : boost::mpl::char_<-62> {}; +template <> struct to_upper_char<-29> : boost::mpl::char_<-61> {}; +template <> struct to_upper_char<-28> : boost::mpl::char_<-60> {}; +template <> struct to_upper_char<-27> : boost::mpl::char_<-59> {}; +template <> struct to_upper_char<-26> : boost::mpl::char_<-58> {}; +template <> struct to_upper_char<-25> : boost::mpl::char_<-57> {}; +template <> struct to_upper_char<-24> : boost::mpl::char_<-56> {}; +template <> struct to_upper_char<-23> : boost::mpl::char_<-55> {}; +template <> struct to_upper_char<-22> : boost::mpl::char_<-54> {}; +template <> struct to_upper_char<-21> : boost::mpl::char_<-53> {}; +template <> struct to_upper_char<-20> : boost::mpl::char_<-52> {}; +template <> struct to_upper_char<-19> : boost::mpl::char_<-51> {}; +template <> struct to_upper_char<-18> : boost::mpl::char_<-50> {}; +template <> struct to_upper_char<-17> : boost::mpl::char_<-49> {}; +template <> struct to_upper_char<-16> : boost::mpl::char_<-48> {}; +template <> struct to_upper_char<-15> : boost::mpl::char_<-47> {}; +template <> struct to_upper_char<-14> : boost::mpl::char_<-46> {}; +template <> struct to_upper_char<-13> : boost::mpl::char_<-45> {}; +template <> struct to_upper_char<-12> : boost::mpl::char_<-44> {}; +template <> struct to_upper_char<-11> : boost::mpl::char_<-43> {}; +template <> struct to_upper_char<-10> : boost::mpl::char_<-42> {}; +template <> struct to_upper_char<-9> : boost::mpl::char_<-41> {}; +template <> struct to_upper_char<-8> : boost::mpl::char_<-40> {}; +template <> struct to_upper_char<-7> : boost::mpl::char_<-39> {}; +template <> struct to_upper_char<-6> : boost::mpl::char_<-38> {}; +template <> struct to_upper_char<-5> : boost::mpl::char_<-37> {}; +template <> struct to_upper_char<-4> : boost::mpl::char_<-36> {}; +template <> struct to_upper_char<-3> : boost::mpl::char_<-35> {}; +template <> struct to_upper_char<-2> : boost::mpl::char_<-34> {}; +template <> struct to_upper_char<-1> : boost::mpl::char_<-33> {}; +template <> struct to_upper_char<0> : boost::mpl::char_<-32> {}; +template <> struct to_upper_char<1> : boost::mpl::char_<-31> {}; +template <> struct to_upper_char<2> : boost::mpl::char_<-30> {}; +template <> struct to_upper_char<3> : boost::mpl::char_<-29> {}; +template <> struct to_upper_char<4> : boost::mpl::char_<-28> {}; +template <> struct to_upper_char<5> : boost::mpl::char_<-27> {}; +template <> struct to_upper_char<6> : boost::mpl::char_<-26> {}; +template <> struct to_upper_char<7> : boost::mpl::char_<-25> {}; +template <> struct to_upper_char<8> : boost::mpl::char_<-24> {}; +template <> struct to_upper_char<9> : boost::mpl::char_<-23> {}; +template <> struct to_upper_char<10> : boost::mpl::char_<-22> {}; +template <> struct to_upper_char<11> : boost::mpl::char_<-21> {}; +template <> struct to_upper_char<12> : boost::mpl::char_<-20> {}; +template <> struct to_upper_char<13> : boost::mpl::char_<-19> {}; +template <> struct to_upper_char<14> : boost::mpl::char_<-18> {}; +template <> struct to_upper_char<15> : boost::mpl::char_<-17> {}; +template <> struct to_upper_char<16> : boost::mpl::char_<-16> {}; +template <> struct to_upper_char<17> : boost::mpl::char_<-15> {}; +template <> struct to_upper_char<18> : boost::mpl::char_<-14> {}; +template <> struct to_upper_char<19> : boost::mpl::char_<-13> {}; +template <> struct to_upper_char<20> : boost::mpl::char_<-12> {}; +template <> struct to_upper_char<21> : boost::mpl::char_<-11> {}; +template <> struct to_upper_char<22> : boost::mpl::char_<-10> {}; +template <> struct to_upper_char<23> : boost::mpl::char_<-9> {}; +template <> struct to_upper_char<24> : boost::mpl::char_<-8> {}; +template <> struct to_upper_char<25> : boost::mpl::char_<-7> {}; +template <> struct to_upper_char<26> : boost::mpl::char_<-6> {}; +template <> struct to_upper_char<27> : boost::mpl::char_<-5> {}; +template <> struct to_upper_char<28> : boost::mpl::char_<-4> {}; +template <> struct to_upper_char<29> : boost::mpl::char_<-3> {}; +template <> struct to_upper_char<30> : boost::mpl::char_<-2> {}; +template <> struct to_upper_char<31> : boost::mpl::char_<-1> {}; +template <> struct to_upper_char<32> : boost::mpl::char_<0> {}; +template <> struct to_upper_char<33> : boost::mpl::char_<1> {}; +template <> struct to_upper_char<34> : boost::mpl::char_<2> {}; +template <> struct to_upper_char<35> : boost::mpl::char_<3> {}; +template <> struct to_upper_char<36> : boost::mpl::char_<4> {}; +template <> struct to_upper_char<37> : boost::mpl::char_<5> {}; +template <> struct to_upper_char<38> : boost::mpl::char_<6> {}; +template <> struct to_upper_char<39> : boost::mpl::char_<7> {}; +template <> struct to_upper_char<40> : boost::mpl::char_<8> {}; +template <> struct to_upper_char<41> : boost::mpl::char_<9> {}; +template <> struct to_upper_char<42> : boost::mpl::char_<10> {}; +template <> struct to_upper_char<43> : boost::mpl::char_<11> {}; +template <> struct to_upper_char<44> : boost::mpl::char_<12> {}; +template <> struct to_upper_char<45> : boost::mpl::char_<13> {}; +template <> struct to_upper_char<46> : boost::mpl::char_<14> {}; +template <> struct to_upper_char<47> : boost::mpl::char_<15> {}; +template <> struct to_upper_char<48> : boost::mpl::char_<16> {}; +template <> struct to_upper_char<49> : boost::mpl::char_<17> {}; +template <> struct to_upper_char<50> : boost::mpl::char_<18> {}; +template <> struct to_upper_char<51> : boost::mpl::char_<19> {}; +template <> struct to_upper_char<52> : boost::mpl::char_<20> {}; +template <> struct to_upper_char<53> : boost::mpl::char_<21> {}; +template <> struct to_upper_char<54> : boost::mpl::char_<22> {}; +template <> struct to_upper_char<55> : boost::mpl::char_<23> {}; +template <> struct to_upper_char<56> : boost::mpl::char_<24> {}; +template <> struct to_upper_char<57> : boost::mpl::char_<25> {}; +template <> struct to_upper_char<58> : boost::mpl::char_<26> {}; +template <> struct to_upper_char<59> : boost::mpl::char_<27> {}; +template <> struct to_upper_char<60> : boost::mpl::char_<28> {}; +template <> struct to_upper_char<61> : boost::mpl::char_<29> {}; +template <> struct to_upper_char<62> : boost::mpl::char_<30> {}; +template <> struct to_upper_char<63> : boost::mpl::char_<31> {}; +template <> struct to_upper_char<64> : boost::mpl::char_<32> {}; +template <> struct to_upper_char<65> : boost::mpl::char_<33> {}; +template <> struct to_upper_char<66> : boost::mpl::char_<34> {}; +template <> struct to_upper_char<67> : boost::mpl::char_<35> {}; +template <> struct to_upper_char<68> : boost::mpl::char_<36> {}; +template <> struct to_upper_char<69> : boost::mpl::char_<37> {}; +template <> struct to_upper_char<70> : boost::mpl::char_<38> {}; +template <> struct to_upper_char<71> : boost::mpl::char_<39> {}; +template <> struct to_upper_char<72> : boost::mpl::char_<40> {}; +template <> struct to_upper_char<73> : boost::mpl::char_<41> {}; +template <> struct to_upper_char<74> : boost::mpl::char_<42> {}; +template <> struct to_upper_char<75> : boost::mpl::char_<43> {}; +template <> struct to_upper_char<76> : boost::mpl::char_<44> {}; +template <> struct to_upper_char<77> : boost::mpl::char_<45> {}; +template <> struct to_upper_char<78> : boost::mpl::char_<46> {}; +template <> struct to_upper_char<79> : boost::mpl::char_<47> {}; +template <> struct to_upper_char<80> : boost::mpl::char_<48> {}; +template <> struct to_upper_char<81> : boost::mpl::char_<49> {}; +template <> struct to_upper_char<82> : boost::mpl::char_<50> {}; +template <> struct to_upper_char<83> : boost::mpl::char_<51> {}; +template <> struct to_upper_char<84> : boost::mpl::char_<52> {}; +template <> struct to_upper_char<85> : boost::mpl::char_<53> {}; +template <> struct to_upper_char<86> : boost::mpl::char_<54> {}; +template <> struct to_upper_char<87> : boost::mpl::char_<55> {}; +template <> struct to_upper_char<88> : boost::mpl::char_<56> {}; +template <> struct to_upper_char<89> : boost::mpl::char_<57> {}; +template <> struct to_upper_char<90> : boost::mpl::char_<58> {}; +template <> struct to_upper_char<91> : boost::mpl::char_<59> {}; +template <> struct to_upper_char<92> : boost::mpl::char_<60> {}; +template <> struct to_upper_char<93> : boost::mpl::char_<61> {}; +template <> struct to_upper_char<94> : boost::mpl::char_<62> {}; +template <> struct to_upper_char<95> : boost::mpl::char_<63> {}; +template <> struct to_upper_char<96> : boost::mpl::char_<64> {}; +template <> struct to_upper_char<97> : boost::mpl::char_<65> {}; +template <> struct to_upper_char<98> : boost::mpl::char_<66> {}; +template <> struct to_upper_char<99> : boost::mpl::char_<67> {}; +template <> struct to_upper_char<100> : boost::mpl::char_<68> {}; +template <> struct to_upper_char<101> : boost::mpl::char_<69> {}; +template <> struct to_upper_char<102> : boost::mpl::char_<70> {}; +template <> struct to_upper_char<103> : boost::mpl::char_<71> {}; +template <> struct to_upper_char<104> : boost::mpl::char_<72> {}; +template <> struct to_upper_char<105> : boost::mpl::char_<73> {}; +template <> struct to_upper_char<106> : boost::mpl::char_<74> {}; +template <> struct to_upper_char<107> : boost::mpl::char_<75> {}; +template <> struct to_upper_char<108> : boost::mpl::char_<76> {}; +template <> struct to_upper_char<109> : boost::mpl::char_<77> {}; +template <> struct to_upper_char<110> : boost::mpl::char_<78> {}; +template <> struct to_upper_char<111> : boost::mpl::char_<79> {}; +template <> struct to_upper_char<112> : boost::mpl::char_<80> {}; +template <> struct to_upper_char<113> : boost::mpl::char_<81> {}; +template <> struct to_upper_char<114> : boost::mpl::char_<82> {}; +template <> struct to_upper_char<115> : boost::mpl::char_<83> {}; +template <> struct to_upper_char<116> : boost::mpl::char_<84> {}; +template <> struct to_upper_char<117> : boost::mpl::char_<85> {}; +template <> struct to_upper_char<118> : boost::mpl::char_<86> {}; +template <> struct to_upper_char<119> : boost::mpl::char_<87> {}; +template <> struct to_upper_char<120> : boost::mpl::char_<88> {}; +template <> struct to_upper_char<121> : boost::mpl::char_<89> {}; +template <> struct to_upper_char<122> : boost::mpl::char_<90> {}; +template <> struct to_upper_char<123> : boost::mpl::char_<91> {}; +template <> struct to_upper_char<124> : boost::mpl::char_<92> {}; +template <> struct to_upper_char<125> : boost::mpl::char_<93> {}; +template <> struct to_upper_char<126> : boost::mpl::char_<94> {}; +template <> struct to_upper_char<127> : boost::mpl::char_<95> {}; + +template +struct to_upper; + +template +struct to_upper> : + boost::metaparse::string::value...> +{}; + +#define CAT_IMPL(a, b) a ## b +#define CAT(a, b) CAT_IMPL(a, b) + +#define TEST_STRING(...) to_upper< __VA_ARGS__ >::type CAT(v, __LINE__); + diff --git a/src/boost/libs/metaparse/tools/benchmark/src/length128.cpp b/src/boost/libs/metaparse/tools/benchmark/src/length128.cpp new file mode 100644 index 000000000..768485f19 --- /dev/null +++ b/src/boost/libs/metaparse/tools/benchmark/src/length128.cpp @@ -0,0 +1,18 @@ +// Copyright Abel Sinkovics (abel@sinkovics.hu) 2016. +// 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) + +// n in [0..2048), step 2 +// x_axis_label: Length of the 128 strings +// desc: 128 strings with increasing length. +// modes: BOOST_METAPARSE_STRING, manual + +\#define BOOST_METAPARSE_LIMIT_STRING_SIZE $n + +\#include + +#for j in range(0, 128) +TEST_STRING($random_string($n)) +#end for + diff --git a/src/boost/libs/metaparse/tools/benchmark/src/max_length.cpp b/src/boost/libs/metaparse/tools/benchmark/src/max_length.cpp new file mode 100644 index 000000000..5ea79beb3 --- /dev/null +++ b/src/boost/libs/metaparse/tools/benchmark/src/max_length.cpp @@ -0,0 +1,21 @@ +// Copyright Abel Sinkovics (abel@sinkovics.hu) 2016. +// 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) + +// n in [1..2048), step 2 +// x_axis_label: Maximum length of strings +// desc: 100 one character long strings with increasing maximum length. +// modes: BOOST_METAPARSE_STRING + +\#define BOOST_METAPARSE_LIMIT_STRING_SIZE $n + +\#include + +#for j in range(0, 10) +TEST_STRING(BOOST_METAPARSE_STRING("\x0$j")) +#end for +#for j in range(10, 100) +TEST_STRING(BOOST_METAPARSE_STRING("\x$j")) +#end for + diff --git a/src/boost/libs/metaparse/tools/benchmark/src/number.cpp b/src/boost/libs/metaparse/tools/benchmark/src/number.cpp new file mode 100644 index 000000000..f15bdd230 --- /dev/null +++ b/src/boost/libs/metaparse/tools/benchmark/src/number.cpp @@ -0,0 +1,18 @@ +// Copyright Abel Sinkovics (abel@sinkovics.hu) 2016. +// 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) + +// n in [0..1024), step 2 +// x_axis_label: Number of strings +// desc: Increasing number of strings with 64 length. +// modes: BOOST_METAPARSE_STRING, manual + +\#define BOOST_METAPARSE_LIMIT_STRING_SIZE 32 + +\#include + +#for j in range(0, $n) +TEST_STRING($random_string(32)) +#end for + diff --git a/src/boost/libs/metaparse/tools/build_environment.py b/src/boost/libs/metaparse/tools/build_environment.py new file mode 100755 index 000000000..b104fb35b --- /dev/null +++ b/src/boost/libs/metaparse/tools/build_environment.py @@ -0,0 +1,134 @@ +#!/usr/bin/python + +# Copyright Abel Sinkovics (abel@sinkovics.hu) 2016. +# 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) + +import os +import subprocess +import json +import argparse + + +def load_json(filename): + with open(filename, 'r') as f: + return json.load(f) + + +class ChildProcess: + def __init__(self, cmd, cwd = os.getcwd()): + self.cmd = cmd + self.cwd = cwd + + def run(self, cmd): + cmd_string = ' '.join(cmd) + print 'Running {0}'.format(cmd_string) + proc = subprocess.Popen( + self.cmd + cmd, + cwd = self.cwd, + stdout = subprocess.PIPE + ) + out = proc.communicate()[0] + if proc.returncode == 0: + return out + else: + raise Exception( + 'Command {0} exited with {1}'.format( + cmd_string, + proc.returncode + ) + ) + + def in_dir(self, cwd): + return ChildProcess(self.cmd, cwd) + + def in_subdir(self, subdir): + return self.in_dir(os.path.join(self.cwd, subdir)) + + +def head_of_master(submodule, git, ref): + git.run(['fetch']) + return git.run(['show-ref', ref]).split()[0] + + +def build_environment(submodules_file, out_dir, git, repo, action, ref): + submodules = load_json(submodules_file) + git.run(['clone', repo, out_dir]) + git_in_boost = git.in_dir(out_dir) + + git_in_boost.run( + ['submodule', 'init', '--'] + [k for k in submodules.keys() if k != ''] + ) + git_in_boost.run(['submodule', 'update']) + if action == 'update': + with open(submodules_file, 'w') as f: + f.write(json.dumps( + dict([ + (k, head_of_master(k, git_in_boost.in_subdir(k), ref)) + for k, v in submodules.iteritems() + ]), + sort_keys=True, + indent=2 + )) + elif action == 'checkout': + for name, commit in submodules.iteritems(): + git_in_boost.in_subdir(name).run(['checkout', commit]) + else: + raise Exception('Invalid action {0}'.format(action)) + + +def main(): + """The main function of the utility""" + parser = argparse.ArgumentParser( + description='Manage the build environment of Boost.Metaparse' + ) + parser.add_argument( + '--dep_json', + required=True, + help='The json file describing the dependencies' + ) + parser.add_argument( + '--git', + required=False, + default='git', + help='The git command to use' + ) + parser.add_argument( + '--out', + required=False, + default='boost', + help='The directory to clone into' + ) + parser.add_argument( + '--action', + required=True, + choices=['update', 'checkout'], + help='The action to do with the dependencies' + ) + parser.add_argument( + '--boost_repository', + required=False, + default='https://github.com/boostorg/boost.git', + help='The Boost repository to clone' + ) + parser.add_argument( + '--ref', + required=False, + default='origin/master', + help='The reference to set to in update' + ) + args = parser.parse_args() + + build_environment( + args.dep_json, + args.out, + ChildProcess([args.git]), + args.boost_repository, + args.action, + args.ref + ) + + +if __name__ == '__main__': + main() diff --git a/src/boost/libs/metaparse/tools/deps.json b/src/boost/libs/metaparse/tools/deps.json new file mode 100644 index 000000000..60e9e5a72 --- /dev/null +++ b/src/boost/libs/metaparse/tools/deps.json @@ -0,0 +1,60 @@ +{ + "": "0438955e7ac39cbb270bb803b3199353c50bf837", + "libs/algorithm": "ea13506795980290842d43d6e8b34c75cf7f362a", + "libs/align": "1f829685e08d4c6b8c96e08b043bf8e03d27ae49", + "libs/any": "3b7c34998d7364aa312a46f6578622ae79d0378f", + "libs/array": "9678f6aa3bee620a91d536cdba92bf0d4b7e02fc", + "libs/assert": "066d8933c4061fb865210de71b4df16839bc1c8d", + "libs/bind": "4300db5db83be5804785b4bf581f9abbcb193caf", + "libs/chrono": "621b6faaf19d5c0b5ffd0a313e696b81495316a4", + "libs/concept_check": "504ea0b18d02e32c223ec8cbaa036806e3ffe6e3", + "libs/config": "74bcf32eca2a81fb8cccb06b81addae3815581fe", + "libs/container": "08e768f1d89289f0783b5bab9ea9f2eb0753ed70", + "libs/conversion": "da8b2fe695cffda506059b49a4782ede01fba10f", + "libs/core": "3add966877646d0c6f43e0ec37587f52d2a757d9", + "libs/detail": "b0a2809915964f504adfad818794fc418a2e39e9", + "libs/exception": "e5e4652b75792d18e595aa2aba1ee1c5c7c69611", + "libs/filesystem": "26540a5338240ca0fae31dba432ff654c0ca93c4", + "libs/foreach": "a19bc0a6dd02249ded12d90cd38f28c8294bd64d", + "libs/function": "42f2a7c714a2c1254b0eb77c9fea870a47f32e80", + "libs/functional": "df98d4fd1ca9d8842da2653fb235ee3dcb2d5e73", + "libs/fusion": "53ba3de15aef744e72d86e91269e2cd90cff8140", + "libs/integer": "14020f6f6c99891aac407618f0c19d383524f02d", + "libs/io": "5458fd86d5a8e667513d34ea50b18883eae5ea14", + "libs/iostreams": "a5b52f079b29dd8fe61ff13d896ec24c48248d49", + "libs/iterator": "22dd100dfded2e8e450b8a079ff2b482f46a9ccc", + "libs/lexical_cast": "038e80ec7a7f34f61379c8885f386b230ef09624", + "libs/math": "e7ca10d04e070ca1c18cc0d5dc21ae1218baf36e", + "libs/move": "87ba5a1fcd6a87d37bb57679b15c63fbcfab88a1", + "libs/mpl": "f023a68f786652749a0809584af1f205f0c2c820", + "libs/numeric/conversion": "f4c6bd971154449e9c76f3f0573799cea772d70a", + "libs/optional": "ede89602f7553a0c76700a57ee519b7f0e4a0d3f", + "libs/predef": "e98eff209ba64fc772cb78b8f67637c08bb97e91", + "libs/preprocessor": "4e29a160b9260c6708d41ce895b499a28c31d5d6", + "libs/program_options": "fae2d4c57b6c70e19e00cd6b93f4ef4f4c6681e2", + "libs/proto": "990af3a70015e037e09103f5d6dbc4eeb833594e", + "libs/range": "0e931f4a80521acb00ff76c03237b0804b2cc572", + "libs/ratio": "d7773512aa7c123309d0f50fe55ab6b6c724357c", + "libs/rational": "d64b2c1b71d1f766cc4f3122462ac063135781c2", + "libs/smart_ptr": "4db7219c32022e025b228f7a487b91b5914aede6", + "libs/spirit": "25c00abf36a1bdce32177632d7e0bbcb03869051", + "libs/static_assert": "87f3be4a8fe6fa32646aa01782dda29e6eeb0b4c", + "libs/system": "e5da5ce2cfef69630687434b292507af9fda83d9", + "libs/test": "b3d233a360e104c146619d5fc93149d361cfef59", + "libs/throw_exception": "c89a2db1122302e90ebad9cec0b49d77283a6566", + "libs/timer": "65d06352434dcb7812c866014f4f05e337bfa900", + "libs/tokenizer": "1d204ae9798edf38caf7e6107099c5edff905a3c", + "libs/tuple": "d77e569c899f7eb3d1f255889e739d586ba5900f", + "libs/type_index": "1ff942f3297e83bbf915bd0a943dbd54e2d332de", + "libs/type_traits": "a0140edf50b5e527bc17fe170c7ad3f7a9e85b32", + "libs/typeof": "6aea11f3df0689b6e5c2035e42bfa5df237df0b5", + "libs/unordered": "84dd473a5dfbb5bc7f353fd3448e00da7425f2aa", + "libs/utility": "1caa745dd72b2cffebafa904658fde0e9cac1232", + "libs/wave": "421a43e9fb9b914c0651e89051523033dc987b36", + "libs/winapi": "463842aa4a45fae68375da6ad441d3c97fab8330", + "libs/xpressive": "2f5bf84198c48f8561918cf0241c5c7af0991981", + "tools/boostbook": "22c94baebb4ea7d7b0b47e0e1017e69623874569", + "tools/build": "9a8453e3b586cc3dd88d609040bd7ae8529bfea1", + "tools/inspect": "b0386f5c64da235d8912bb45dfa55475f2ef7545", + "tools/quickbook": "08663596f8fd32046c346ebded75dcdc505c9bbe" +} diff --git a/src/boost/libs/metaparse/tools/generate_all.py b/src/boost/libs/metaparse/tools/generate_all.py new file mode 100755 index 000000000..66a5267da --- /dev/null +++ b/src/boost/libs/metaparse/tools/generate_all.py @@ -0,0 +1,295 @@ +#!/usr/bin/python + +# Copyright Abel Sinkovics (abel@sinkovics.hu) 2015. +# 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) + +import sys +import argparse +import re +import os + +def remove_last_dot(s): + if s.endswith('.'): + return s[:-1] + else: + return s + +def remove_newline(s): + return re.sub('[\r\n]', '', s) + +def is_definition(s): + cmd = s.strip() + + def_prefixes = ['#include ', 'using ', 'struct ', 'template '] + return any([cmd.startswith(s) for s in def_prefixes]) or cmd.endswith(';') + +def prefix_lines(prefix, s): + return '\n'.join(['%s%s' % (prefix, l) for l in s.split('\n')]) + +def protect_metashell(s): + if s.startswith('#include [^ ]') + metashell_prompt = re.compile('^(\.\.\.|)>') + msh_cmd = '' + for l in qbk: + if l.startswith(' '): + ll = l[2:] + if not in_cpp_snippet: + in_msh_cpp_snippet = True + if in_msh_cpp_snippet: + if metashell_command.match(ll) or msh_cmd != '': + cmd = metashell_prompt.sub('', remove_newline(ll)) + if msh_cmd != '': + msh_cmd = msh_cmd + '\n' + msh_cmd = msh_cmd + cmd + if msh_cmd.endswith('\\'): + msh_cmd = msh_cmd[:-1].strip() + ' ' + else: + if not is_definition(msh_cmd): + msh_cmd = '// query:\n%s' % (prefix_lines('// ', msh_cmd)) + defs.append((current_section, protect_metashell(msh_cmd.strip()))) + msh_cmd = '' + elif not in_cpp_snippet: + in_msh_cpp_snippet = False + in_cpp_snippet = True + else: + in_cpp_snippet = False + m = numbered_section_header.match(l) + if m: + current_section = remove_last_dot(m.group(1)).replace('.', '_') + sections.append(current_section) + + sections.sort(key = lambda s: [int(n) for n in s.split('_')]) + return (sections, defs) + +def delete_old_headers(path): + for f in os.listdir(path): + if f.endswith('.hpp'): + os.remove(os.path.join(path, f)) + +def gen_headers(sections, defs, path): + files = {} + + prev_section = '' + for s in sections: + prev_name = prev_section.replace('_', '.') + include_guard = 'BOOST_METAPARSE_GETTING_STARTED_%s_HPP' % (s) + if prev_section == '': + prev_include = '' + else: + prev_include = \ + '// Definitions before section {0}\n'.format(prev_name) + \ + '#include "{0}.hpp"\n'.format(prev_section) + \ + '\n' + + files[os.path.join(path, s + '.hpp')] = \ + '#ifndef {0}\n'.format(include_guard) + \ + '#define {0}\n'.format(include_guard) + \ + '\n' + \ + '// Automatically generated header file\n' + \ + '\n' + \ + prev_include + \ + '// Definitions of section {0}\n'.format(prev_name) + \ + '\n'.join( \ + ['%s\n' % (d) for (sec, d) in defs if sec == prev_section] \ + ) + \ + '\n' + \ + '#endif\n' + \ + '\n' + prev_section = s + return files + +def remove_metashell_protection(s): + prefix = '#ifdef __METASHELL\n' + suffix = '#endif' + return \ + s[len(prefix):-len(suffix)] \ + if s.startswith(prefix) and s.endswith(suffix) \ + else s + +def make_code_snippet(s): + return '\n'.join([' {0}'.format(l) for l in s.split('\n')]) + +def what_we_have_so_far_docs(doc_dir, qbk, defs, sections): + files = {} + so_far = '' + sections_with_definition = [] + for s in sections: + if so_far != '': + files[os.path.join(doc_dir, 'before_{0}.qbk'.format(s))] = \ + '[#before_{0}]\n[\'Definitions before section {1}]\n\n{2}\n'.format( + s, + s.replace('_', '.') + '.', + so_far + ) + sections_with_definition.append(s) + + so_far = so_far + '\n'.join([ + '{0}\n'.format(make_code_snippet(remove_metashell_protection(d))) + for (sec, d) in defs + if sec == s and not d.startswith('//') + ]) + + is_section = re.compile('^\[section (([0-9]\.)+)') + note_prefix = \ + '[note Note that you can find everything that has been included and' \ + ' defined so far [link before_' + + in_definitions_before_each_section = False + + result = [] + for l in qbk: + if in_definitions_before_each_section: + if l.strip() == '[endsect]': + in_definitions_before_each_section = False + result.append(l) + elif l.strip() == '[section Definitions before each section]': + in_definitions_before_each_section = True + result.append(l) + result.append('\n') + for s in sections_with_definition: + result.append('[include before_{0}.qbk]\n'.format(s)) + result.append('\n') + elif not l.startswith(note_prefix): + result.append(l) + m = is_section.match(l) + if m: + section_number = m.group(1).replace('.', '_')[:-1] + if section_number in sections_with_definition: + result.append('{0}{1} here].]\n'.format(note_prefix, section_number)) + + return (files, result) + +def strip_not_finished_line(s): + s = s.strip() + return s[:-1] if s.endswith('\\') else s + +def make_copy_paste_friendly(lines): + result = [] + for l in lines: + if l.startswith('> '): + result.append(l[2:]) + elif l.startswith('...> '): + result[-1] = strip_not_finished_line(result[-1]) + l[5:].lstrip() + return result + +def extract_code_snippets(qbk, fn_base): + code_prefix = ' ' + + files = {} + + result = [] + in_cpp_code = False + counter = 0 + in_copy_paste_friendly_examples = False + skip_empty_lines = False + for l in qbk: + if l.strip() != '' or not skip_empty_lines: + skip_empty_lines = False + if in_copy_paste_friendly_examples: + if 'endsect' in l: + in_copy_paste_friendly_examples = False + result.append('\n') + result.extend([ + '[include {0}_{1}.qbk]\n'.format(re.sub('^.*/', '', fn_base), i) \ + for i in range(0, counter) + ]) + result.append('\n') + result.append(l) + in_copy_paste_friendly_examples = False + elif '[section Copy-paste friendly code examples]' in l: + in_copy_paste_friendly_examples = True + result.append(l) + elif 'copy-paste friendly version' in l: + skip_empty_lines = True + else: + result.append(l) + + if in_cpp_code: + if not l.startswith(code_prefix): + in_cpp_code = False + if len(code) > 1: + f = '{0}_{1}'.format(fn_base, counter) + basename_f = re.sub('^.*/', '', f) + files['{0}.qbk'.format(f)] = \ + '[#{0}]\n\n{1}\n'.format( + basename_f, + ''.join( + [code_prefix + s for s in make_copy_paste_friendly(code)] + ) + ) + result.append( + '[link {0} copy-paste friendly version]\n'.format(basename_f) + ) + result.append('\n') + counter = counter + 1 + elif \ + l.startswith(code_prefix + '> ') \ + or l.startswith(code_prefix + '...> '): + code.append(l[len(code_prefix):]) + elif l.startswith(code_prefix): + in_cpp_code = True + code = [l[len(code_prefix):]] + + return (files, result) + +def write_file(fn, content): + with open(fn, 'w') as f: + f.write(content) + +def write_files(files): + for fn in files: + write_file(fn, files[fn]) + +def main(): + desc = 'Generate headers with the definitions of a Getting Started guide' + parser = argparse.ArgumentParser(description=desc) + parser.add_argument( + '--src', + dest='src', + default='doc/getting_started.qbk', + help='The .qbk source of the Getting Started guide' + ) + parser.add_argument( + '--dst', + dest='dst', + default='example/getting_started', + help='The target directory to generate into (all headers in that directory will be deleted!)' + ) + + args = parser.parse_args() + + qbk = open(args.src, 'r').readlines() + + delete_old_headers(args.dst) + doc_dir = os.path.dirname(args.src) + + (sections, defs) = parse_md(qbk) + files1 = gen_headers(sections, defs, args.dst) + (files2, qbk) = what_we_have_so_far_docs(doc_dir, qbk, defs, sections) + (files3, qbk) = \ + extract_code_snippets( + qbk, + args.src[:-4] if args.src.endswith('.qbk') else args.src + ) + + write_files(files1) + write_files(files2) + write_files(files3) + write_file(args.src, ''.join(qbk)) + +if __name__ == "__main__": + main() + diff --git a/src/boost/libs/metaparse/tools/string_headers.py b/src/boost/libs/metaparse/tools/string_headers.py new file mode 100755 index 000000000..43ef052f1 --- /dev/null +++ b/src/boost/libs/metaparse/tools/string_headers.py @@ -0,0 +1,347 @@ +#!/usr/bin/python +"""Utility to generate the header files for BOOST_METAPARSE_STRING""" + +# Copyright Abel Sinkovics (abel@sinkovics.hu) 2016. +# 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) + +import argparse +import math +import os +import sys + + +VERSION = 1 + + +class Namespace(object): + """Generate namespace definition""" + + def __init__(self, out_f, names): + self.out_f = out_f + self.names = names + + def begin(self): + """Generate the beginning part""" + self.out_f.write('\n') + for depth, name in enumerate(self.names): + self.out_f.write( + '{0}namespace {1}\n{0}{{\n'.format(self.prefix(depth), name) + ) + + def end(self): + """Generate the closing part""" + for depth in xrange(len(self.names) - 1, -1, -1): + self.out_f.write('{0}}}\n'.format(self.prefix(depth))) + + def prefix(self, depth=None): + """Returns the prefix of a given depth. Returns the prefix code inside + the namespace should use when depth is None.""" + if depth is None: + depth = len(self.names) + return ' ' * depth + + def __enter__(self): + self.begin() + return self + + def __exit__(self, typ, value, traceback): + self.end() + + +def write_autogen_info(out_f): + """Write the comment about the file being autogenerated""" + out_f.write( + '\n' + '// This is an automatically generated header file.\n' + '// Generated with the tools/string_headers.py utility of\n' + '// Boost.Metaparse\n' + ) + + +class IncludeGuard(object): + """Generate include guards""" + + def __init__(self, out_f): + self.out_f = out_f + + def begin(self): + """Generate the beginning part""" + name = 'BOOST_METAPARSE_V1_CPP11_IMPL_STRING_HPP' + self.out_f.write('#ifndef {0}\n#define {0}\n'.format(name)) + write_autogen_info(self.out_f) + + def end(self): + """Generate the closing part""" + self.out_f.write('\n#endif\n') + + def __enter__(self): + self.begin() + return self + + def __exit__(self, typ, value, traceback): + self.end() + + +def macro_name(name): + """Generate the full macro name""" + return 'BOOST_METAPARSE_V{0}_{1}'.format(VERSION, name) + + +def define_macro(out_f, (name, args, body), undefine=False, check=True): + """Generate a macro definition or undefinition""" + if undefine: + out_f.write( + '#undef {0}\n' + .format(macro_name(name)) + ) + else: + if args: + arg_list = '({0})'.format(', '.join(args)) + else: + arg_list = '' + + if check: + out_f.write( + '#ifdef {0}\n' + '# error {0} already defined.\n' + '#endif\n' + .format(macro_name(name)) + ) + + out_f.write( + '#define {0}{1} {2}\n'.format(macro_name(name), arg_list, body) + ) + + +def filename(out_dir, name, undefine=False): + """Generate the filename""" + if undefine: + prefix = 'undef_' + else: + prefix = '' + return os.path.join(out_dir, '{0}{1}.hpp'.format(prefix, name.lower())) + + +def length_limits(max_length_limit, length_limit_step): + """Generates the length limits""" + string_len = len(str(max_length_limit)) + return [ + str(i).zfill(string_len) for i in + xrange( + length_limit_step, + max_length_limit + length_limit_step - 1, + length_limit_step + ) + ] + + +def unique_names(count): + """Generate count unique variable name""" + return ('C{0}'.format(i) for i in xrange(0, count)) + + +def generate_take(out_f, steps, line_prefix): + """Generate the take function""" + out_f.write( + '{0}constexpr inline int take(int n_)\n' + '{0}{{\n' + '{0} return {1} 0 {2};\n' + '{0}}}\n' + '\n'.format( + line_prefix, + ''.join('n_ >= {0} ? {0} : ('.format(s) for s in steps), + ')' * len(steps) + ) + ) + + +def generate_make_string(out_f, max_step): + """Generate the make_string template""" + steps = [2 ** n for n in xrange(int(math.log(max_step, 2)), -1, -1)] + + with Namespace( + out_f, + ['boost', 'metaparse', 'v{0}'.format(VERSION), 'impl'] + ) as nsp: + generate_take(out_f, steps, nsp.prefix()) + + out_f.write( + '{0}template \n' + '{0}struct make_string;\n' + '\n' + '{0}template ' + ' struct make_string<0, 0, Cs...> : string<> {{}};\n' + .format(nsp.prefix()) + ) + + disable_sun = False + for i in reversed(steps): + if i > 64 and not disable_sun: + out_f.write('#ifndef __SUNPRO_CC\n') + disable_sun = True + out_f.write( + '{0}template ' + ' struct make_string<{2},LenRemaining,{3}Cs...> :' + ' concat,' + ' typename make_string::type> {{}};\n' + .format( + nsp.prefix(), + ''.join('char {0},'.format(n) for n in unique_names(i)), + i, + ''.join('{0},'.format(n) for n in unique_names(i)), + ','.join(unique_names(i)) + ) + ) + if disable_sun: + out_f.write('#endif\n') + + +def generate_string(out_dir, limits): + """Generate string.hpp""" + max_limit = max((int(v) for v in limits)) + + with open(filename(out_dir, 'string'), 'wb') as out_f: + with IncludeGuard(out_f): + out_f.write( + '\n' + '#include \n' + '#include \n' + .format(VERSION) + ) + + generate_make_string(out_f, 512) + + out_f.write( + '\n' + '#ifndef BOOST_METAPARSE_LIMIT_STRING_SIZE\n' + '# error BOOST_METAPARSE_LIMIT_STRING_SIZE not defined\n' + '#endif\n' + '\n' + '#if BOOST_METAPARSE_LIMIT_STRING_SIZE > {0}\n' + '# error BOOST_METAPARSE_LIMIT_STRING_SIZE is greater than' + ' {0}. To increase the limit run tools/string_headers.py of' + ' Boost.Metaparse against your Boost headers.\n' + '#endif\n' + '\n' + .format(max_limit) + ) + + define_macro(out_f, ( + 'STRING', + ['s'], + '{0}::make_string< ' + '{0}::take(sizeof(s)-1), sizeof(s)-1-{0}::take(sizeof(s)-1),' + 'BOOST_PP_CAT({1}, BOOST_METAPARSE_LIMIT_STRING_SIZE)(s)' + '>::type' + .format( + '::boost::metaparse::v{0}::impl'.format(VERSION), + macro_name('I') + ) + )) + + out_f.write('\n') + for limit in xrange(0, max_limit + 1): + out_f.write( + '#define {0} {1}\n' + .format( + macro_name('I{0}'.format(limit)), + macro_name('INDEX_STR{0}'.format( + min(int(l) for l in limits if int(l) >= limit) + )) + ) + ) + out_f.write('\n') + + prev_macro = None + prev_limit = 0 + for length_limit in (int(l) for l in limits): + this_macro = macro_name('INDEX_STR{0}'.format(length_limit)) + out_f.write( + '#define {0}(s) {1}{2}\n' + .format( + this_macro, + '{0}(s),'.format(prev_macro) if prev_macro else '', + ','.join( + '{0}((s), {1})' + .format(macro_name('STRING_AT'), i) + for i in xrange(prev_limit, length_limit) + ) + ) + ) + prev_macro = this_macro + prev_limit = length_limit + + +def positive_integer(value): + """Throws when the argument is not a positive integer""" + val = int(value) + if val > 0: + return val + else: + raise argparse.ArgumentTypeError("A positive number is expected") + + +def existing_path(value): + """Throws when the path does not exist""" + if os.path.exists(value): + return value + else: + raise argparse.ArgumentTypeError("Path {0} not found".format(value)) + + +def main(): + """The main function of the script""" + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument( + '--boost_dir', + required=False, + type=existing_path, + help='The path to the include/boost directory of Metaparse' + ) + parser.add_argument( + '--max_length_limit', + required=False, + default=2048, + type=positive_integer, + help='The maximum supported length limit' + ) + parser.add_argument( + '--length_limit_step', + required=False, + default=128, + type=positive_integer, + help='The longest step at which headers are generated' + ) + args = parser.parse_args() + + if args.boost_dir is None: + tools_path = os.path.dirname(os.path.abspath(__file__)) + boost_dir = os.path.join( + os.path.dirname(tools_path), + 'include', + 'boost' + ) + else: + boost_dir = args.boost_dir + + if args.max_length_limit < 1: + sys.stderr.write('Invalid maximum length limit') + sys.exit(-1) + + generate_string( + os.path.join( + boost_dir, + 'metaparse', + 'v{0}'.format(VERSION), + 'cpp11', + 'impl' + ), + length_limits(args.max_length_limit, args.length_limit_step) + ) + + +if __name__ == '__main__': + main() -- cgit v1.2.3