DAW JSON Link
daw_json_option_bits.h
Go to the documentation of this file.
1 // Copyright (c) Darrell Wright
2 //
3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
4 // file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
5 //
6 // Official repository: https://github.com/beached/daw_json_link
7 //
8 
9 #pragma once
10 
11 #include "version.h"
12 
13 #include <daw/cpp_17.h>
14 #include <daw/daw_attributes.h>
15 #include <daw/daw_traits.h>
16 
17 #include <climits>
18 #include <cstddef>
19 #include <cstdint>
20 #include <utility>
21 
22 namespace daw::json {
23  inline namespace DAW_JSON_VER {
24  using json_options_t = std::uint32_t;
25  namespace json_details {
26 
27  template<typename>
28  inline constexpr unsigned json_option_bits_width = 0;
29 
30  template<typename>
31  inline constexpr auto default_json_option_value = [] {
32  struct unknown_policy {};
33  return unknown_policy{ };
34  }( );
35 
36  template<typename Policy, typename Options>
37  struct option_bits_start_impl;
38 
39  template<typename Policy, typename... Options>
40  struct option_bits_start_impl<Policy, pack_list<Options...>> {
41  static constexpr auto idx =
42  daw::traits::pack_index_of_v<Policy, Options...>;
43  static_assert( idx >= 0, "Policy is not registered" );
44  using tp_policies = pack_list<Options...>;
45 
46  template<std::size_t Pos, int End>
47  static constexpr unsigned do_step( ) {
48  if constexpr( Pos >= static_cast<std::size_t>( End ) ) {
49  return 0U;
50  }
51  return json_option_bits_width<pack_element_t<Pos, tp_policies>>;
52  }
53 
54  template<std::size_t... Is>
55  DAW_ATTRIB_INLINE static constexpr unsigned
56  calc( std::index_sequence<Is...> ) {
57  return ( do_step<Is, idx>( ) + ... );
58  }
59  };
60 
61  template<typename... Options>
62  struct option_list_impl {
63  using type = pack_list<Options...>;
64 
65  static_assert(
66  ( json_option_bits_width<Options> + ... + 0 ) <=
67  ( sizeof( json_options_t ) * CHAR_BIT ),
68  "The size of json_options_t is not large enough "
69  "to safely hold all the bits of state. Use a larger size." );
70  };
71 
72  template<typename Option>
73  inline constexpr bool is_option_flag = json_option_bits_width<Option> > 0;
74 
75  template<typename... Options>
76  inline constexpr bool are_option_flags =
77  ( is_option_flag<Options> and ... );
78 
79  template<typename Option, typename Options>
80  inline constexpr unsigned basic_option_bits_start =
81  option_bits_start_impl<Option, Options>::template calc<>(
82  std::make_index_sequence<pack_size_v<Options>>{ } );
83 
84  template<typename... JsonOptions>
85  struct JsonOptionList;
86 
87  template<typename... OptionList, typename Option>
88  static constexpr json_options_t
89  set_bits_for( JsonOptionList<OptionList...>, Option e );
90 
91  template<typename... JsonOptions>
92  struct JsonOptionList {
93  using OptionList = typename option_list_impl<JsonOptions...>::type;
94 
95  template<typename Option>
96  static inline constexpr unsigned option_bits_start =
97  basic_option_bits_start<Option, OptionList>;
98 
99  template<typename... /*OptionList*/, typename Option>
100  static constexpr json_options_t set_bits_for( Option e ) {
101  static_assert( is_option_flag<Option>,
102  "Only registered policy types are allowed" );
103  auto new_bits = static_cast<json_options_t>( e );
104  new_bits <<= option_bits_start<Option>;
105  return new_bits;
106  }
107 
108  static constexpr json_options_t default_option_flag =
109  ( set_bits_for<JsonOptions>(
110  default_json_option_value<JsonOptions> ) |
111  ... | 0 );
112  /***
113  * Create the parser options flag for BasicParseOption
114  * @tparam Options Option types that satisfy the `is_option_flag`
115  * trait.
116  * @param policies A list of parser options to change from the defaults.
117  * @return A json_options_t that encodes the options for the parser
118  */
119  template<typename... Options>
120  static constexpr json_options_t options( Options... options ) {
121  static_assert( json_details::are_option_flags<Options...>,
122  "Only registered option types are allowed" );
123  auto result = default_option_flag;
124  if constexpr( sizeof...( Options ) > 0 ) {
125  result |= ( set_bits_for( options ) | ... );
126  }
127  return result;
128  }
129  };
130 
131  template<typename... OptionList, typename Option>
132  constexpr void set_bits_in( JsonOptionList<OptionList...>,
133  json_options_t &value, Option e ) {
134  static_assert( is_option_flag<Option>,
135  "Only registered policy types are allowed" );
136  auto new_bits = static_cast<unsigned>( e );
137  constexpr unsigned mask = (1U << json_option_bits_width<Option>)-1U;
138  new_bits &= mask;
139  new_bits <<=
140  JsonOptionList<OptionList...>::template option_bits_start<Option>;
141  value &= ~mask;
142  value |= new_bits;
143  }
144 
145  template<typename... OptionList, typename Option, typename... Options>
146  constexpr json_options_t set_bits( JsonOptionList<OptionList...>,
147  json_options_t value, Option pol,
148  Options... pols ) {
149  static_assert( are_option_flags<Options...>,
150  "Only registered policy types are allowed" );
151 
152  auto new_bits = static_cast<unsigned>( pol );
153  constexpr unsigned mask = ( (1U << json_option_bits_width<Option>)-1U );
154  new_bits &= mask;
155  new_bits <<=
156  JsonOptionList<OptionList...>::template option_bits_start<Option>;
157  value &= ~( mask << JsonOptionList<
158  OptionList...>::template option_bits_start<Option> );
159  value |= new_bits;
160  if constexpr( sizeof...( Options ) > 0 ) {
161  return set_bits( JsonOptionList<OptionList...>{ }, value, pols... );
162  } else {
163  return value;
164  }
165  }
166 
167  template<typename... OptionList, typename Option>
168  static constexpr json_options_t
169  set_bits_for( JsonOptionList<OptionList...>, Option e ) {
170  return JsonOptionList<OptionList...>::set_bits_for( e );
171  }
172 
173  template<typename Option, typename Result = Option,
174  typename... OptionList>
175  constexpr Result get_bits_for( JsonOptionList<OptionList...>,
176  json_options_t value ) {
177  static_assert( std::is_enum_v<Option>,
178  "Only enum options are allowed" );
179  static_assert( std::is_same_v<unsigned, std::underlying_type_t<Option>>,
180  "Looks like option was no specified correctly. "
181  "Underlying type should be unsigned" );
182  static_assert( is_option_flag<Option>,
183  "Only registered option types are allowed" );
184  constexpr unsigned mask =
185  ( 1U << (JsonOptionList<OptionList...>::template option_bits_start<
186  Option> +
187  json_option_bits_width<Option>)) -
188  1U;
189  value &= mask;
190  value >>=
191  JsonOptionList<OptionList...>::template option_bits_start<Option>;
192  return static_cast<Result>( Option{ value } );
193  }
194 
195  template<typename... OptionList, typename... Options>
196  constexpr json_options_t json_option( JsonOptionList<OptionList...>,
197  Options... options ) {
198  return JsonOptionList<OptionList...>::options( options... );
199  }
200 
201  template<typename>
202  struct default_option_flag_t;
203 
204  template<template<class...> class OptionList, typename... Options>
205  struct default_option_flag_t<OptionList<Options...>> {
206  static constexpr json_options_t value =
207  ( OptionList<Options...>::template set_bits_for<Options>(
208  default_json_option_value<Options> ) |
209  ... );
210  };
211 
212  /***
213  * The defaults for all known policies encoded as a json_options_t
214  */
215  template<typename OptionList>
216  static inline constexpr json_options_t default_option_flag =
217  default_option_flag_t<OptionList>::value;
218 
219  } // namespace json_details
220  } // namespace DAW_JSON_VER
221 } // namespace daw::json
Customization point traits.
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.
Definition: version.h:25