File: generate_cpp17.py

package info (click to toggle)
boost1.90 1.90.0-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 593,120 kB
  • sloc: cpp: 4,190,908; xml: 196,648; python: 34,618; ansic: 23,145; asm: 5,468; sh: 3,774; makefile: 1,161; perl: 1,020; sql: 728; ruby: 676; yacc: 478; java: 77; lisp: 24; csh: 6
file content (176 lines) | stat: -rw-r--r-- 6,708 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
#!/usr/bin/python

# Copyright (c) 2016-2025 Antony Polukhin
# Copyright (c) 2023 Denis Mikhailov
#
# 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 string

# Skipping some letters that may produce keywords or are hard to read, or shadow template parameters
ascii_letters = string.ascii_letters.replace("o", "").replace("O", "").replace("i", "").replace("I", "").replace("T", "")
WORKAROUND_CAST_EXPRESSIONS_LIMIT_PER_LINE = 3

PROLOGUE = """// Copyright (c) 2016-2025 Antony Polukhin
// Copyright (c) 2023 Denis Mikhailov
//
// 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)


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////// THIS HEADER IS AUTO GENERATED BY misc/generate_cpp17.py                                    ////////////////
//////////////// MODIFY AND RUN THE misc/generate_cpp17.py INSTEAD OF DIRECTLY MODIFYING THE GENERATED FILE ////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef BOOST_PFR_DETAIL_CORE17_GENERATED_HPP
#define BOOST_PFR_DETAIL_CORE17_GENERATED_HPP
#pragma once

#include <boost/pfr/detail/config.hpp>
#if !BOOST_PFR_USE_CPP17
#   error C++17 is required for this header.
#endif

#include <boost/pfr/detail/sequence_tuple.hpp>
#include <boost/pfr/detail/size_t_.hpp>

#if !defined(BOOST_PFR_INTERFACE_UNIT)
#include <type_traits> // for std::conditional_t, std::is_reference
#endif

namespace boost { namespace pfr { namespace detail {

template <class... Args>
constexpr auto make_tuple_of_references(Args&&... args) noexcept {
  return sequence_tuple::tuple<Args&...>{ args... };
}

template<typename T, typename Arg>
constexpr decltype(auto) add_cv_like(Arg& arg) noexcept {
    if constexpr (std::is_const<T>::value && std::is_volatile<T>::value) {
        return const_cast<const volatile Arg&>(arg);
    }
    else if constexpr (std::is_const<T>::value) {
        return const_cast<const Arg&>(arg);
    }
    else if constexpr (std::is_volatile<T>::value) {
        return const_cast<volatile Arg&>(arg);
    }
    else {
        return const_cast<Arg&>(arg);
    }
}

// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78939
template<typename T, typename Sb, typename Arg>
constexpr decltype(auto) workaround_cast(Arg& arg) noexcept {
    using output_arg_t = std::conditional_t<!std::is_reference<Sb>(), decltype(detail::add_cv_like<T>(arg)), Sb>;
    return const_cast<output_arg_t>(arg);
}

template <class T>
constexpr auto tie_as_tuple(T& /*val*/, size_t_<0>) noexcept {
  return sequence_tuple::tuple<>{};
}

template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<1>, std::enable_if_t<std::is_class< std::remove_cv_t<T> >::value>* = nullptr) noexcept {
  auto& [a] = const_cast<std::remove_cv_t<T>&>(val); // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
  return ::boost::pfr::detail::make_tuple_of_references(detail::workaround_cast<T, decltype(a)>(a));
}


template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<1>, std::enable_if_t<!std::is_class< std::remove_cv_t<T> >::value>* = nullptr) noexcept {
  return ::boost::pfr::detail::make_tuple_of_references( val );
}

"""

############################################################################################################################
EPILOGUE = """
template <class T, std::size_t I>
constexpr void tie_as_tuple(T& /*val*/, size_t_<I>) noexcept {
  static_assert(sizeof(T) && false,
                "====================> Boost.PFR: Too many fields in a structure T. Regenerate include/boost/pfr/detail/core17_generated.hpp file for appropriate count of fields. For example: `python ./misc/generate_cpp17.py 300 > include/boost/pfr/detail/core17_generated.hpp`");
}

}}} // namespace boost::pfr::detail

#endif // BOOST_PFR_DETAIL_CORE17_GENERATED_HPP
"""

############################################################################################################################

def fold_workaround_cast(indexes, divider):
    WORKAROUND_CAST_TEMPLATE = """
detail::workaround_cast<T, decltype({arg})>({arg})
"""
    lines = []
    div = ''
    tokens = [x.strip() for x in indexes.split(',')]
    casts = [WORKAROUND_CAST_TEMPLATE.strip().format(arg=tok)
             for tok in tokens]
    for i in range(0, len(casts)):
        if i%WORKAROUND_CAST_EXPRESSIONS_LIMIT_PER_LINE==0:
            div = ''
            lines.append('')
        lines[-1] += div + casts[i]
        div = ','
    return divider.join(lines)

def calc_indexes_count(indexes):
    tokens = [x.strip() for x in indexes.split(',')]
    return len(tokens)

class EmptyLinePrinter:
    def print_once(self):
        if not self.printed:
            print("")
            self.printed = True
    printed = False

indexes = "    a"
print(PROLOGUE)
funcs_count = 200 if len(sys.argv) == 1 else int(sys.argv[1])
max_args_on_a_line = len(ascii_letters)
for i in range(1, funcs_count):
    if i % max_args_on_a_line == 0:
        indexes += ",\n    "
    else:
        indexes += ","

    if i >= max_args_on_a_line:
        indexes += ascii_letters[i // max_args_on_a_line - 1]
    indexes += ascii_letters[i % max_args_on_a_line]

    printed_casts = fold_workaround_cast(indexes.strip(), ",\n    ")
    indexes_count = calc_indexes_count(indexes.strip())
    empty_printer = EmptyLinePrinter()

    print("template <class T>")
    print("constexpr auto tie_as_tuple(T& val, size_t_<" + str(i + 1) + ">) noexcept {")
    if i < max_args_on_a_line:
        print("  auto& [" + indexes.strip() + "] = const_cast<std::remove_cv_t<T>&>(val); // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.")
    else:
        print("  auto& [")
        print(indexes)
        print("  ] = const_cast<std::remove_cv_t<T>&>(val); // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.")
        empty_printer.print_once()
 
    if indexes_count < WORKAROUND_CAST_EXPRESSIONS_LIMIT_PER_LINE:
        print("  return ::boost::pfr::detail::make_tuple_of_references(" + printed_casts + ");")
    else:
        empty_printer.print_once()
        print("  return ::boost::pfr::detail::make_tuple_of_references(")
        print("    " + printed_casts)
        print("  );")

    print("}\n")

print(EPILOGUE)