summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/metaparse/tools
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 18:45:59 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 18:45:59 +0000
commit19fcec84d8d7d21e796c7624e521b60d28ee21ed (patch)
tree42d26aa27d1e3f7c0b8bd3fd14e7d7082f5008dc /src/boost/libs/metaparse/tools
parentInitial commit. (diff)
downloadceph-upstream.tar.xz
ceph-upstream.zip
Adding upstream version 16.2.11+ds.upstream/16.2.11+dsupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/boost/libs/metaparse/tools')
-rw-r--r--src/boost/libs/metaparse/tools/benchmark/README.md14
-rwxr-xr-xsrc/boost/libs/metaparse/tools/benchmark/benchmark.py354
-rwxr-xr-xsrc/boost/libs/metaparse/tools/benchmark/char_stat.py59
-rw-r--r--src/boost/libs/metaparse/tools/benchmark/chars.py1
-rwxr-xr-xsrc/boost/libs/metaparse/tools/benchmark/generate.py299
-rw-r--r--src/boost/libs/metaparse/tools/benchmark/include/benchmark_util.hpp281
-rw-r--r--src/boost/libs/metaparse/tools/benchmark/src/length128.cpp18
-rw-r--r--src/boost/libs/metaparse/tools/benchmark/src/max_length.cpp21
-rw-r--r--src/boost/libs/metaparse/tools/benchmark/src/number.cpp18
-rwxr-xr-xsrc/boost/libs/metaparse/tools/build_environment.py134
-rw-r--r--src/boost/libs/metaparse/tools/deps.json60
-rwxr-xr-xsrc/boost/libs/metaparse/tools/generate_all.py295
-rwxr-xr-xsrc/boost/libs/metaparse/tools/string_headers.py347
13 files changed, 1901 insertions, 0 deletions
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 <boost/metaparse/string.hpp>
+
+template <char C>
+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 <class S>
+struct to_upper;
+
+template <char... Cs>
+struct to_upper<boost::metaparse::string<Cs...>> :
+ boost::metaparse::string<to_upper_char<Cs>::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 <benchmark_util.hpp>
+
+#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 <benchmark_util.hpp>
+
+#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 <benchmark_util.hpp>
+
+#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'):
+ return '#ifdef __METASHELL\n%s\n#endif' % (s)
+ else:
+ return s
+
+def parse_md(qbk):
+ sections = []
+ defs = []
+ current_section = ''
+ in_cpp_snippet = False
+ numbered_section_header = re.compile('^\[section *([0-9.]+)')
+ metashell_command = re.compile('^> [^ ]')
+ 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 <int LenNow, int LenRemaining, char... Cs>\n'
+ '{0}struct make_string;\n'
+ '\n'
+ '{0}template <char... Cs>'
+ ' 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 <int LenRemaining,{1}char... Cs>'
+ ' struct make_string<{2},LenRemaining,{3}Cs...> :'
+ ' concat<string<{4}>,'
+ ' typename make_string<take(LenRemaining),'
+ 'LenRemaining-take(LenRemaining),Cs...>::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 <boost/metaparse/v{0}/cpp11/impl/concat.hpp>\n'
+ '#include <boost/preprocessor/cat.hpp>\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()