OmniSciDB  72c90bc290
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
StdOptionalSerializer.h
Go to the documentation of this file.
1 /*
2  * Copyright 2022 HEAVY.AI, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <optional>
20 
21 #include <boost/archive/text_iarchive.hpp>
22 #include <boost/archive/text_oarchive.hpp>
23 #include <boost/serialization/optional.hpp>
24 
25 namespace boost {
26 namespace serialization {
27 
39 // NOTE: uncomment if we find that a more recent gcc or boost works. For more, see
40 // comments below
41 
42 // template <class Archive, typename T> void save(Archive& ar, const
43 // std::optional<T>& in_opt, const unsigned int version) {
44 // boost::optional<T> boost_opt;
45 // if (in_opt) {
46 // boost_opt = *in_opt;
47 // }
48 // ar& boost_opt;
49 // }
50 
51 // NOTE: uncomment if we find that a more recent gcc or boost works. For more, see
52 // comments below.
53 
54 // template <class Archive, typename T>
55 // void load(Archive& ar, std::optional<T>& out_opt, const unsigned int version) {
56 // boost::optional<T> boost_opt;
57 // ar& boost_opt;
58 
59 // if (boost_opt) {
60 // out_opt = *boost_opt;
61 // } else {
62 // // probably unnecessary
63 // out_opt.reset();
64 // }
65 // }
66 
67 template <class Archive, class T>
68 void serialize(Archive& ar, std::optional<T>& in_opt, const unsigned int version) {
69  // NOTE: uncomment if we find that a more recent gcc or boost works
70  // ::boost::serialization::split_free(ar, in_opt, version);
71 
72  // The if constexpr block below is a workaround to what appears to be a gcc v9.4.0 bug.
73  // The preferred way to split the load/save code paths is to use the
74  // boost::serialization::split_free:
75  // https://www.boost.org/doc/libs/1_74_0/libs/serialization/doc/serialization.html#splitting
76  //
77  // However, doing it the split_free way, which means overriding the save/load free
78  // functions for std::optional, results in a very strange compilation error.
79  // The parent header file for doing RelAlgDag serialization does a:
80  // #include <boost/serialization/shared_ptr.hpp>
81  //
82  // shared_ptr.hpp in turn does a:
83  // #include <boost/serialization/shared_ptr_helper.hpp>
84  // see:
85  // https://www.boost.org/doc/libs/1_74_0/boost/serialization/shared_ptr.hpp)
86  //
87  // shared_ptr_helper.hpp has this ifndef block:
88  //
89  // #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
90  // template<class Archive, template<class U> class SPT >
91  // void load(
92  // Archive & ar,
93  // SPT< class U > &t,
94  // const unsigned int file_version
95  // );
96  // #endif
97  //
98  // see: https://www.boost.org/doc/libs/1_74_0/boost/serialization/shared_ptr_helper.hpp
99  //
100  // That load free-function declaration confuses gcc, and you get a compilation error
101  // like this:
102  //
103  // clang-format off
104  //
105  // In file included from /usr/include/c++/9/bits/move.h:55,
106  // from /usr/include/c++/9/bits/stl_pair.h:59,
107  // from /usr/include/c++/9/utility:70,
108  // from /usr/include/c++/9/algorithm:60,
109  // from ../QueryEngine/Execute.h:20,
110  // from heavydb-internal/build/QueryEngine/CMakeFiles/QueryEngine.dir/cmake_pch.hxx:5,
111  // from <command-line>:
112  // /usr/include/c++/9/type_traits: In instantiation of ‘struct std::__is_trivially_copy_constructible_impl<boost::serialization::U, true>’:
113  // /usr/include/c++/9/type_traits:1157:12: required from ‘struct std::is_trivially_copy_constructible<boost::serialization::U>’
114  // /usr/include/c++/9/type_traits:2938:25: required from ‘constexpr const bool std::is_trivially_copy_constructible_v<boost::serialization::U>’
115  // /usr/include/c++/9/optional:469:12: required by substitution of ‘template<class Archive, template<class U> class SPT> void boost::serialization::load(Archive&, SPT<boost::serialization::U>&, unsigned int) [with Archive = boost::archive::text_iarchive; SPT = <missing>]’
116  // /usr/include/boost/serialization/split_free.hpp:58:13: required from ‘static void boost::serialization::free_loader<Archive, T>::invoke(Archive&, T&, unsigned int) [with Archive = boost::archive::text_iarchive; T = std::optional<long unsigned int>]’
117  // /usr/include/boost/serialization/split_free.hpp:74:18: required from ‘void boost::serialization::split_free(Archive&, T&, unsigned int) [with Archive = boost::archive::text_iarchive; T = std::optional<long unsigned int>]’
118  // ../QueryEngine/RelAlgSerializerOptional.h:52:37: [ skipping 42 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
119  // /usr/include/boost/archive/detail/iserializer.hpp:624:18: required from ‘void boost::archive::load(Archive&, T&) [with Archive = boost::archive::text_iarchive; T = RelAlgDag]’
120  // /usr/include/boost/archive/detail/common_iarchive.hpp:67:22: required from ‘void boost::archive::detail::common_iarchive<Archive>::load_override(T&) [with T = RelAlgDag; Archive = boost::archive::text_iarchive]’
121  // /usr/include/boost/archive/basic_text_iarchive.hpp:70:9: required from ‘void boost::archive::basic_text_iarchive<Archive>::load_override(T&) [with T = RelAlgDag; Archive = boost::archive::text_iarchive]’
122  // /usr/include/boost/archive/text_iarchive.hpp:82:52: required from ‘void boost::archive::text_iarchive_impl<Archive>::load_override(T&) [with T = RelAlgDag; Archive = boost::archive::text_iarchive]’
123  // /usr/include/boost/archive/detail/interface_iarchive.hpp:68:9: required from ‘Archive& boost::archive::detail::interface_iarchive<Archive>::operator>>(T&) [with T = RelAlgDag; Archive = boost::archive::text_iarchive]’
124  // ../QueryEngine/RelAlgDagSerializer/RelAlgDagSerializer.cpp:70:12: required from here
125  // /usr/include/c++/9/type_traits:1150:12: error: invalid use of incomplete type ‘class boost::serialization::U’
126  // 1150 | struct __is_trivially_copy_constructible_impl<_Tp, true>
127  // | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
128  // In file included from /usr/include/boost/serialization/shared_ptr.hpp:29,
129  // from ../QueryEngine/RelAlgDagSerializer/RelAlgDagSerializer.h:25,
130  // from ../QueryEngine/RelAlgDagSerializer/RelAlgDagSerializer.cpp:17:
131  // /usr/include/boost/serialization/shared_ptr_helper.hpp:45:16: note: forward declaration of ‘class boost::serialization::U’
132  // 45 | SPT< class U > &t,
133  // | ^
134  // In file included from /usr/include/c++/9/bits/move.h:55,
135  // from /usr/include/c++/9/bits/stl_pair.h:59,
136  // from /usr/include/c++/9/utility:70,
137  // from /usr/include/c++/9/algorithm:60,
138  // from ../QueryEngine/Execute.h:20,
139  // from heavydb-internal/build/QueryEngine/CMakeFiles/QueryEngine.dir/cmake_pch.hxx:5,
140  // from <command-line>:
141  //
142  //
143  // clang-format on
144  //
145  // It appears as tho there's a gcc bug that confuses the load() free function
146  // declaration in shared_ptr_helper.hpp when trying to resolve overrides with the
147  // two-argument template and somehow substitutes the second template argument with a
148  // boost::serialization::U class type, which does not exist.
149  //
150  // So the workaround is to use the if contexpr switch and pull the definitions of the
151  // load/save free functions for std::optional directly into the serialize override,
152  // which works fine and has no other conflicts.
153  //
154  // If we find that we upgrade to a more recent version of gcc and it works, we can move
155  // back to the split_free approach, which is commented out above.
156 
157  if constexpr (std::is_same_v<::boost::archive::text_iarchive, Archive>) {
158  // load case
159  boost::optional<T> boost_opt;
160  (ar & boost_opt);
161 
162  if (boost_opt) {
163  in_opt = *boost_opt;
164  } else {
165  // probably unnecessary
166  in_opt.reset();
167  }
168  } else {
169  // save case
170  static_assert(std::is_same_v<::boost::archive::text_oarchive, Archive>);
171  boost::optional<T> boost_opt;
172  if (in_opt) {
173  boost_opt = *in_opt;
174  }
175  (ar & boost_opt);
176  }
177 }
178 
179 } // namespace serialization
180 } // namespace boost
string version
Definition: setup.in.py:73
void serialize(Archive &ar, RegisteredQueryHint &query_hint, const unsigned int version)