24 #ifndef FieldCodecManager20110405H
25 #define FieldCodecManager20110405H
27 #include <type_traits>
29 #include "field_codec.h"
30 #include "internal/field_codec_data.h"
31 #include "internal/type_helper.h"
33 #include "thread_safety.h"
54 template <
class Codec>
55 typename std::enable_if<
56 std::is_base_of<google::protobuf::Message, typename Codec::wire_type>::value &&
57 !std::is_same<google::protobuf::Message, typename Codec::wire_type>::value,
59 add(
const std::string& name);
66 template <
class Codec>
67 typename std::enable_if<
68 !(std::is_base_of<google::protobuf::Message, typename Codec::wire_type>::value &&
69 !std::is_same<google::protobuf::Message, typename Codec::wire_type>::value),
71 add(
const std::string& name);
78 template <
class Codec, google::protobuf::FieldDescriptor::Type type>
79 void add(
const std::string& name);
86 template <
class Codec>
87 typename std::enable_if<
88 std::is_base_of<google::protobuf::Message, typename Codec::wire_type>::value &&
89 !std::is_same<google::protobuf::Message, typename Codec::wire_type>::value,
91 remove(
const std::string& name);
98 template <
class Codec>
99 typename std::enable_if<
100 !(std::is_base_of<google::protobuf::Message, typename Codec::wire_type>::value &&
101 !std::is_same<google::protobuf::Message, typename Codec::wire_type>::value),
103 remove(
const std::string& name);
110 template <
class Codec, google::protobuf::FieldDescriptor::Type type>
111 void remove(
const std::string& name);
114 std::shared_ptr<FieldCodecBase>
find(
const google::protobuf::FieldDescriptor* field,
115 int codec_version,
bool has_codec_group,
116 const std::string& codec_group)
const
118 std::string name = __find_codec(field, has_codec_group, codec_group);
120 if (field->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE)
121 return find(field->message_type(), codec_version, name);
123 return __find(field->type(), codec_version, name,
"");
130 std::shared_ptr<FieldCodecBase>
find(
const google::protobuf::Descriptor* desc,
131 int codec_version = 0, std::string name =
"")
const
137 if (desc->options().GetExtension(dccl::msg).has_codec())
138 name = desc->options().GetExtension(dccl::msg).codec();
140 name = FieldCodecBase::codec_group(desc);
141 codec_version = desc->options().GetExtension(dccl::msg).codec_version();
144 return __find(google::protobuf::FieldDescriptor::TYPE_MESSAGE, codec_version, name,
148 std::shared_ptr<FieldCodecBase>
find(google::protobuf::FieldDescriptor::Type type,
149 int codec_version, std::string name)
const
151 return __find(type, codec_version, name,
"");
156 type_helper_.reset();
160 internal::TypeHelper& type_helper() {
return type_helper_; }
161 const internal::TypeHelper& type_helper()
const {
return type_helper_; }
163 internal::CodecData& codec_data() {
return codec_data_; }
164 const internal::CodecData& codec_data()
const {
return codec_data_; }
166 void set_hash(
const google::protobuf::Descriptor* desc, std::size_t hash)
168 hashes_[desc] = hash;
170 bool has_hash(
const google::protobuf::Descriptor* desc)
const {
return hashes_.count(desc); }
171 std::size_t hash(
const google::protobuf::Descriptor* desc)
const {
return hashes_.at(desc); }
174 std::shared_ptr<FieldCodecBase> __find(google::protobuf::FieldDescriptor::Type type,
175 int codec_version,
const std::string& codec_name,
176 const std::string& type_name)
const;
178 std::string __mangle_name(
const std::string& codec_name,
const std::string& type_name)
const
180 return type_name.empty() ? codec_name : codec_name +
"[" + type_name +
"]";
183 template <
typename WireType,
typename FieldType,
class Codec>
184 void add_all_types(
const std::string& name);
186 template <
class Codec>
187 void add_single_type(
const std::string& name,
188 google::protobuf::FieldDescriptor::Type field_type,
189 google::protobuf::FieldDescriptor::CppType wire_type);
191 void add_single_type(std::shared_ptr<FieldCodecBase> new_field_codec,
const std::string& name,
192 google::protobuf::FieldDescriptor::Type field_type,
193 google::protobuf::FieldDescriptor::CppType wire_type);
195 template <
typename WireType,
typename FieldType,
class Codec>
196 void remove_all_types(
const std::string& name);
198 template <
class Codec>
199 void remove_single_type(
const std::string& name,
200 google::protobuf::FieldDescriptor::Type field_type,
201 google::protobuf::FieldDescriptor::CppType wire_type);
203 std::string __find_codec(
const google::protobuf::FieldDescriptor* field,
bool has_codec_group,
204 const std::string& codec_group)
const
209 if (dccl_field_options.has_codec())
210 return dccl_field_options.codec();
212 else if (field->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE &&
213 field->message_type()->options().GetExtension(dccl::msg).has_codec())
214 return field->message_type()->options().GetExtension(dccl::msg).codec();
216 else if (has_codec_group)
220 return dccl_field_options.codec();
223 void check_deprecated(
const std::string& name)
const;
226 using InsideMap = std::map<std::string, std::shared_ptr<FieldCodecBase>>;
227 std::map<google::protobuf::FieldDescriptor::Type, InsideMap> codecs_;
229 internal::TypeHelper type_helper_;
230 internal::CodecData codec_data_;
232 std::map<const google::protobuf::Descriptor*, std::size_t> hashes_;
233 std::map<std::string, std::string> deprecated_names_;
239 template <
class Codec>
240 typename std::enable_if<
241 std::is_base_of<google::protobuf::Message, typename Codec::wire_type>::value &&
242 !std::is_same<google::protobuf::Message, typename Codec::wire_type>::value,
244 add(
const std::string& )
246 static_assert(
sizeof(
Codec) == 0,
247 "The global `FieldCodecManager::add<...>(...)` is no longer available. Use "
248 "`dccl::Codec codec; codec.manager().add<...>(...)` instead, or for the ID "
249 "Codec use `dccl::Codec codec(\"id_codec_name\", MyIDCodec())`.");
252 template <
class Codec>
253 typename std::enable_if<
254 !(std::is_base_of<google::protobuf::Message, typename Codec::wire_type>::value &&
255 !std::is_same<google::protobuf::Message, typename Codec::wire_type>::value),
257 add(
const std::string& )
259 static_assert(
sizeof(
Codec) == 0,
260 "The global `FieldCodecManager::add<...>(...)` is no longer available. Use "
261 "`dccl::Codec codec; codec.manager().add<...>(...)` instead.`");
264 template <
class Codec, google::protobuf::FieldDescriptor::Type type>
265 static void add(
const std::string& )
267 static_assert(
sizeof(
Codec) == 0,
268 "The global `FieldCodecManager::add<...>(...)` is no longer available. Use "
269 "`dccl::Codec codec; codec.manager().add<...>(...)` instead, or for the ID "
270 "Codec use `dccl::Codec codec(\"id_codec_name\", MyIDCodec())`.");
273 template <
class Codec>
274 typename std::enable_if<
275 std::is_base_of<google::protobuf::Message, typename Codec::wire_type>::value &&
276 !std::is_same<google::protobuf::Message, typename Codec::wire_type>::value,
278 remove(
const std::string& )
280 static_assert(
sizeof(
Codec) == 0,
281 "The global FieldCodecManager::remove<...>(...) is no longer available. Use "
282 "`dccl::Codec codec; codec.manager().remove<...>(...) instead");
285 template <
class Codec>
286 typename std::enable_if<
287 !(std::is_base_of<google::protobuf::Message, typename Codec::wire_type>::value &&
288 !std::is_same<google::protobuf::Message, typename Codec::wire_type>::value),
290 remove(
const std::string& )
292 static_assert(
sizeof(
Codec) == 0,
293 "The global FieldCodecManager::remove<...>(...) is no longer available. Use "
294 "`dccl::Codec codec; codec.manager().remove<...>(...) instead");
297 template <
class Codec, google::protobuf::FieldDescriptor::Type type>
298 static void remove(
const std::string& )
300 static_assert(
sizeof(
Codec) == 0,
301 "The global FieldCodecManager::remove<...>(...) is no longer available. Use "
302 "`dccl::Codec codec; codec.manager().remove<...>(...) instead");
308 template <
class Codec>
309 typename std::enable_if<
310 std::is_base_of<google::protobuf::Message, typename Codec::wire_type>::value &&
311 !std::is_same<google::protobuf::Message, typename Codec::wire_type>::value,
315 type_helper_.add<
typename Codec::wire_type>();
316 add_single_type<Codec>(__mangle_name(name, Codec::wire_type::descriptor()->full_name()),
317 google::protobuf::FieldDescriptor::TYPE_MESSAGE,
318 google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE);
321 template <
class Codec>
322 typename std::enable_if<
323 !(std::is_base_of<google::protobuf::Message, typename Codec::wire_type>::value &&
324 !std::is_same<google::protobuf::Message, typename Codec::wire_type>::value),
328 add_all_types<typename Codec::wire_type, typename Codec::field_type, Codec>(name);
331 template <
class Codec, google::protobuf::FieldDescriptor::Type type>
334 add_single_type<Codec>(name, type, google::protobuf::FieldDescriptor::TypeToCppType(type));
337 template <
typename WireType,
typename FieldType,
class Codec>
338 void dccl::FieldCodecManagerLocal::add_all_types(
const std::string& name)
340 using google::protobuf::FieldDescriptor;
344 for (
int i = 1, n = FieldDescriptor::MAX_TYPE; i <= n; ++i)
346 auto field_type =
static_cast<FieldDescriptor::Type
>(i);
347 if (FieldDescriptor::TypeToCppType(field_type) == cpp_field_type)
349 add_single_type<Codec>(name, field_type, cpp_wire_type);
354 template <
class Codec>
355 void dccl::FieldCodecManagerLocal::add_single_type(
356 const std::string& name, google::protobuf::FieldDescriptor::Type field_type,
357 google::protobuf::FieldDescriptor::CppType wire_type)
359 std::shared_ptr<FieldCodecBase> new_field_codec(
new Codec());
360 new_field_codec->set_name(name);
361 new_field_codec->set_field_type(field_type);
362 new_field_codec->set_wire_type(wire_type);
363 new_field_codec->set_manager(
this);
364 using google::protobuf::FieldDescriptor;
365 if (!codecs_[field_type].count(name))
367 codecs_[field_type][name] = new_field_codec;
368 dccl::dlog.
is(dccl::logger::DEBUG1) && dccl::dlog <<
"Adding codec " << *new_field_codec
373 dccl::dlog.
is(dccl::logger::DEBUG1) &&
374 dccl::dlog <<
"Trying to add: " << *new_field_codec
375 <<
", but already have duplicate codec (For `name`/`field type` pair) "
376 << *(codecs_[field_type].find(name)->second) << std::endl;
380 template <
class Codec>
381 typename std::enable_if<
382 std::is_base_of<google::protobuf::Message, typename Codec::wire_type>::value &&
383 !std::is_same<google::protobuf::Message, typename Codec::wire_type>::value,
387 type_helper_.remove<
typename Codec::wire_type>();
388 remove_single_type<Codec>(__mangle_name(name, Codec::wire_type::descriptor()->full_name()),
389 google::protobuf::FieldDescriptor::TYPE_MESSAGE,
390 google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE);
393 template <
class Codec>
394 typename std::enable_if<
395 !(std::is_base_of<google::protobuf::Message, typename Codec::wire_type>::value &&
396 !std::is_same<google::protobuf::Message, typename Codec::wire_type>::value),
400 remove_all_types<typename Codec::wire_type, typename Codec::field_type, Codec>(name);
403 template <
class Codec, google::protobuf::FieldDescriptor::Type type>
406 remove_single_type<Codec>(name, type, google::protobuf::FieldDescriptor::TypeToCppType(type));
409 template <
typename WireType,
typename FieldType,
class Codec>
410 void dccl::FieldCodecManagerLocal::remove_all_types(
const std::string& name)
412 using google::protobuf::FieldDescriptor;
416 for (
int i = 1, n = FieldDescriptor::MAX_TYPE; i <= n; ++i)
418 auto field_type =
static_cast<FieldDescriptor::Type
>(i);
419 if (FieldDescriptor::TypeToCppType(field_type) == cpp_field_type)
421 remove_single_type<Codec>(name, field_type, cpp_wire_type);
426 template <
class Codec>
427 void dccl::FieldCodecManagerLocal::remove_single_type(
428 const std::string& name, google::protobuf::FieldDescriptor::Type field_type,
429 google::protobuf::FieldDescriptor::CppType wire_type)
431 using google::protobuf::FieldDescriptor;
432 if (codecs_[field_type].count(name))
434 dccl::dlog.
is(dccl::logger::DEBUG1) &&
435 dccl::dlog <<
"Removing codec " << *codecs_[field_type][name] << std::endl;
436 codecs_[field_type].erase(name);
440 std::shared_ptr<FieldCodecBase> new_field_codec(
new Codec());
441 new_field_codec->set_name(name);
442 new_field_codec->set_field_type(field_type);
443 new_field_codec->set_wire_type(wire_type);
444 new_field_codec->set_manager(
this);
446 dccl::dlog.
is(dccl::logger::DEBUG1) && dccl::dlog
447 <<
"Trying to remove: " << *new_field_codec
448 <<
", but no such codec exists" << std::endl;