OSDN Git Service

2006-09-27 Benjamin Kosnik <bkoz@redhat.com>
[pf3gnuchains/gcc-fork.git] / libstdc++-v3 / include / ext / pb_ds / detail / cc_hash_table_map_ / cc_ht_map_.hpp
1 // -*- C++ -*-
2
3 // Copyright (C) 2005, 2006 Free Software Foundation, Inc.
4 //
5 // This file is part of the GNU ISO C++ Library.  This library is free
6 // software; you can redistribute it and/or modify it under the terms
7 // of the GNU General Public License as published by the Free Software
8 // Foundation; either version 2, or (at your option) any later
9 // version.
10
11 // This library is distributed in the hope that it will be useful, but
12 // WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // General Public License for more details.
15
16 // You should have received a copy of the GNU General Public License
17 // along with this library; see the file COPYING.  If not, write to
18 // the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
19 // MA 02111-1307, USA.
20
21 // As a special exception, you may use this file as part of a free
22 // software library without restriction.  Specifically, if other files
23 // instantiate templates or use macros or inline functions from this
24 // file, or you compile this file and link it with other files to
25 // produce an executable, this file does not by itself cause the
26 // resulting executable to be covered by the GNU General Public
27 // License.  This exception does not however invalidate any other
28 // reasons why the executable file might be covered by the GNU General
29 // Public License.
30
31 // Copyright (C) 2004 Ami Tavory and Vladimir Dreizin, IBM-HRL.
32
33 // Permission to use, copy, modify, sell, and distribute this software
34 // is hereby granted without fee, provided that the above copyright
35 // notice appears in all copies, and that both that copyright notice
36 // and this permission notice appear in supporting documentation. None
37 // of the above authors, nor IBM Haifa Research Laboratories, make any
38 // representation about the suitability of this software for any
39 // purpose. It is provided "as is" without express or implied
40 // warranty.
41
42 /**
43  * @file cc_ht_map_.hpp
44  * Contains an implementation class for cc_ht_map_.
45  */
46
47 #include <utility>
48 #include <iterator>
49 #include <ext/pb_ds/detail/cond_dealtor.hpp>
50 #include <ext/pb_ds/tag_and_trait.hpp>
51 #include <ext/pb_ds/detail/hash_fn/ranged_hash_fn.hpp>
52 #include <ext/pb_ds/detail/types_traits.hpp>
53 #include <ext/pb_ds/exception.hpp>
54 #include <ext/pb_ds/detail/eq_fn/hash_eq_fn.hpp>
55 #ifdef _GLIBCXX_DEBUG
56 #include <ext/pb_ds/detail/map_debug_base.hpp>
57 #endif 
58 #ifdef PB_DS_HT_MAP_TRACE_
59 #include <iostream>
60 #endif 
61 #include <debug/debug.h>
62
63 namespace pb_ds
64 {
65   namespace detail
66   {
67
68 #define PB_DS_CLASS_T_DEC \
69     template<typename Key, typename Mapped, typename Hash_Fn, \
70              typename Eq_Fn, typename Allocator, bool Store_Hash, \
71              typename Comb_Hash_Fn, typename Resize_Policy>
72
73 #ifdef PB_DS_DATA_TRUE_INDICATOR
74 #define PB_DS_CLASS_NAME cc_ht_map_data_
75 #endif 
76
77 #ifdef PB_DS_DATA_FALSE_INDICATOR
78 #define PB_DS_CLASS_NAME cc_ht_map_no_data_
79 #endif 
80
81 #define PB_DS_CLASS_C_DEC \
82     PB_DS_CLASS_NAME<Key, Mapped, Hash_Fn, Eq_Fn, Allocator,    \
83                      Store_Hash, Comb_Hash_Fn, Resize_Policy>
84
85 #define PB_DS_HASH_EQ_FN_C_DEC \
86     hash_eq_fn<Key, Eq_Fn, Allocator, Store_Hash>
87
88 #define PB_DS_RANGED_HASH_FN_C_DEC \
89     ranged_hash_fn<Key, Hash_Fn, Allocator, Comb_Hash_Fn, Store_Hash>
90
91 #define PB_DS_TYPES_TRAITS_C_DEC \
92     types_traits<Key, Mapped, Allocator, Store_Hash>
93
94 #ifdef _GLIBCXX_DEBUG
95 #define PB_DS_MAP_DEBUG_BASE_C_DEC \
96     map_debug_base<Key, Eq_Fn, typename Allocator::template rebind<Key>::other::const_reference>
97 #endif 
98
99 #ifdef PB_DS_DATA_TRUE_INDICATOR
100 #define PB_DS_V2F(X) (X).first
101 #define PB_DS_V2S(X) (X).second
102 #endif 
103
104 #ifdef PB_DS_DATA_FALSE_INDICATOR
105 #define PB_DS_V2F(X) (X)
106 #define PB_DS_V2S(X) Mapped_Data()
107 #endif 
108
109 #define PB_DS_STATIC_ASSERT(UNIQUE, E) \
110     typedef static_assert_dumclass<sizeof(static_assert<(bool)(E)>)> \
111     UNIQUE##static_assert_type
112
113     // <011i$i0|\|-<|-|4i|\|i|\|g |-|4$|-| 74813.
114     template<typename Key,
115              typename Mapped,
116              typename Hash_Fn,
117              typename Eq_Fn,
118              typename Allocator,
119              bool Store_Hash,
120              typename Comb_Hash_Fn,
121              typename Resize_Policy >
122     class PB_DS_CLASS_NAME:
123 #ifdef _GLIBCXX_DEBUG
124       protected PB_DS_MAP_DEBUG_BASE_C_DEC,
125 #endif 
126       public PB_DS_HASH_EQ_FN_C_DEC,
127       public Resize_Policy,
128       public PB_DS_RANGED_HASH_FN_C_DEC,
129       public PB_DS_TYPES_TRAITS_C_DEC
130     {
131     private:
132       typedef PB_DS_TYPES_TRAITS_C_DEC traits_base;
133       typedef typename traits_base::comp_hash comp_hash;
134       typedef typename traits_base::value_type value_type_;
135       typedef typename traits_base::pointer pointer_;
136       typedef typename traits_base::const_pointer const_pointer_;
137       typedef typename traits_base::reference reference_;
138       typedef typename traits_base::const_reference const_reference_;
139       typedef typename traits_base::store_extra_false_type store_hash_false_type;
140       typedef typename traits_base::store_extra_true_type store_hash_true_type;
141       typedef typename traits_base::no_throw_copies_false_type no_throw_copies_false_type;
142       typedef typename traits_base::no_throw_copies_true_type no_throw_copies_true_type;
143
144       struct entry : public traits_base::stored_value_type
145       {
146         typename Allocator::template rebind<entry>::other::pointer m_p_next;
147       };
148
149       typedef cond_dealtor<entry, Allocator> cond_dealtor_t;
150
151       typedef typename Allocator::template rebind<entry>::other entry_allocator;
152       typedef typename entry_allocator::pointer entry_pointer;
153       typedef typename entry_allocator::const_pointer const_entry_pointer;
154       typedef typename entry_allocator::reference entry_reference;
155       typedef typename entry_allocator::const_reference const_entry_reference;
156
157       typedef typename Allocator::template rebind<entry_pointer>::other entry_pointer_allocator;
158       typedef typename entry_pointer_allocator::pointer entry_pointer_array;
159
160       typedef PB_DS_RANGED_HASH_FN_C_DEC ranged_hash_fn_base;
161       typedef PB_DS_HASH_EQ_FN_C_DEC hash_eq_fn_base;
162       typedef Resize_Policy resize_base;
163
164 #ifdef _GLIBCXX_DEBUG
165       typedef PB_DS_MAP_DEBUG_BASE_C_DEC map_debug_base;
166 #endif 
167
168 #define PB_DS_GEN_POS std::pair<entry_pointer, typename Allocator::size_type>
169
170 #include <ext/pb_ds/detail/unordered_iterator/const_point_iterator.hpp>
171 #include <ext/pb_ds/detail/unordered_iterator/point_iterator.hpp>
172 #include <ext/pb_ds/detail/unordered_iterator/const_iterator.hpp>
173 #include <ext/pb_ds/detail/unordered_iterator/iterator.hpp>
174
175 #undef PB_DS_GEN_POS
176
177     public:
178       typedef Allocator allocator;
179       typedef typename Allocator::size_type size_type;
180       typedef typename Allocator::difference_type difference_type;
181       typedef Hash_Fn hash_fn;
182       typedef Eq_Fn eq_fn;
183       typedef Comb_Hash_Fn comb_hash_fn;
184       typedef Resize_Policy resize_policy;
185
186       enum
187         {
188           store_hash = Store_Hash
189         };
190
191       typedef typename traits_base::key_type key_type;
192       typedef typename traits_base::key_pointer key_pointer;
193       typedef typename traits_base::const_key_pointer const_key_pointer;
194       typedef typename traits_base::key_reference key_reference;
195       typedef typename traits_base::const_key_reference const_key_reference;
196       typedef typename traits_base::mapped_type mapped_type;
197       typedef typename traits_base::mapped_pointer mapped_pointer;
198       typedef typename traits_base::const_mapped_pointer const_mapped_pointer;
199       typedef typename traits_base::mapped_reference mapped_reference;
200       typedef typename traits_base::const_mapped_reference const_mapped_reference;
201       typedef typename traits_base::value_type value_type;
202       typedef typename traits_base::pointer pointer;
203       typedef typename traits_base::const_pointer const_pointer;
204       typedef typename traits_base::reference reference;
205       typedef typename traits_base::const_reference const_reference;
206
207 #ifdef PB_DS_DATA_TRUE_INDICATOR
208       typedef point_iterator_ point_iterator;
209 #endif 
210
211 #ifdef PB_DS_DATA_FALSE_INDICATOR
212       typedef const_point_iterator_ point_iterator;
213 #endif 
214
215       typedef const_point_iterator_ const_point_iterator;
216
217 #ifdef PB_DS_DATA_TRUE_INDICATOR
218       typedef iterator_ iterator;
219 #endif 
220
221 #ifdef PB_DS_DATA_FALSE_INDICATOR
222       typedef const_iterator_ iterator;
223 #endif 
224
225       typedef const_iterator_ const_iterator;
226
227       PB_DS_CLASS_NAME();
228
229       PB_DS_CLASS_NAME(const Hash_Fn&);
230
231       PB_DS_CLASS_NAME(const Hash_Fn&, const Eq_Fn&);
232
233       PB_DS_CLASS_NAME(const Hash_Fn&, const Eq_Fn&, const Comb_Hash_Fn&);
234
235       PB_DS_CLASS_NAME(const Hash_Fn&, const Eq_Fn&, const Comb_Hash_Fn&, 
236                        const Resize_Policy&);
237
238       PB_DS_CLASS_NAME(const PB_DS_CLASS_C_DEC&);
239
240       virtual
241       ~PB_DS_CLASS_NAME();
242
243       void
244       swap(PB_DS_CLASS_C_DEC&);
245
246       template<typename It>
247       void
248       copy_from_range(It, It);
249
250       void
251       initialize();
252
253       inline size_type
254       size() const;
255
256       inline size_type
257       max_size() const;
258
259       inline bool
260       empty() const;
261
262       Hash_Fn& 
263       get_hash_fn();
264
265       const Hash_Fn& 
266       get_hash_fn() const;
267
268       Eq_Fn& 
269       get_eq_fn();
270
271       const Eq_Fn& 
272       get_eq_fn() const;
273
274       Comb_Hash_Fn& 
275       get_comb_hash_fn();
276
277       const Comb_Hash_Fn& 
278       get_comb_hash_fn() const;
279
280       Resize_Policy& 
281       get_resize_policy();
282
283       const Resize_Policy& 
284       get_resize_policy() const;
285
286       inline std::pair<point_iterator, bool>
287       insert(const_reference r_val)
288       { return insert_imp(r_val, traits_base::m_store_extra_indicator); }
289
290       inline mapped_reference
291       operator[](const_key_reference r_key)
292       {
293 #ifdef PB_DS_DATA_TRUE_INDICATOR
294         return (subscript_imp(r_key, traits_base::m_store_extra_indicator));
295 #else 
296         insert(r_key);
297         return traits_base::s_null_mapped;
298 #endif 
299       }
300
301       inline point_iterator
302       find(const_key_reference);
303
304       inline const_point_iterator
305       find(const_key_reference) const;
306
307       inline point_iterator
308       find_end();
309
310       inline const_point_iterator
311       find_end() const;
312
313       inline bool
314       erase(const_key_reference);
315
316       template<typename Pred>
317       inline size_type
318       erase_if(Pred);
319
320       void
321       clear();
322
323       inline iterator
324       begin();
325
326       inline const_iterator
327       begin() const;
328
329       inline iterator
330       end();
331
332       inline const_iterator
333       end() const;
334
335 #ifdef _GLIBCXX_DEBUG
336       void
337       assert_valid() const;
338 #endif 
339
340 #ifdef PB_DS_HT_MAP_TRACE_
341       void
342       trace() const;
343 #endif 
344
345     private:
346       void
347       deallocate_all();
348
349       inline bool
350       do_resize_if_needed();
351
352       inline void
353       do_resize_if_needed_no_throw();
354
355       void
356       resize_imp(size_type new_size);
357
358       void
359       do_resize(size_type new_size);
360
361       void
362       resize_imp_no_exceptions(size_type, entry_pointer_array, size_type);
363
364       inline entry_pointer
365       resize_imp_no_exceptions_reassign_pointer(entry_pointer, entry_pointer_array, store_hash_false_type);
366
367       inline entry_pointer
368       resize_imp_no_exceptions_reassign_pointer(entry_pointer, entry_pointer_array, store_hash_true_type);
369
370       void
371       deallocate_links_in_list(entry_pointer);
372
373       inline entry_pointer
374       get_entry(const_reference, no_throw_copies_false_type);
375
376       inline entry_pointer
377       get_entry(const_reference, no_throw_copies_true_type);
378
379       inline void
380       rels_entry(entry_pointer);
381
382 #ifdef PB_DS_DATA_TRUE_INDICATOR
383       inline mapped_reference
384       subscript_imp(const_key_reference r_key, store_hash_false_type)
385       {
386         _GLIBCXX_DEBUG_ONLY(assert_valid();)
387         const size_type pos = ranged_hash_fn_base::operator()(r_key);
388         entry_pointer p_e = m_entries[pos];
389         resize_base::notify_insert_search_start();
390
391         while (p_e != NULL 
392                && !hash_eq_fn_base::operator()(p_e->m_value.first, r_key))
393           {
394             resize_base::notify_insert_search_collision();
395             p_e = p_e->m_p_next;
396           }
397
398         resize_base::notify_insert_search_end();
399         if (p_e != NULL)
400           {
401             _GLIBCXX_DEBUG_ONLY(map_debug_base::check_key_exists(r_key);)
402             return (p_e->m_value.second);
403           }
404
405         _GLIBCXX_DEBUG_ONLY(map_debug_base::check_key_does_not_exist(r_key);)
406         return insert_new_imp(value_type(r_key, mapped_type()), pos)->second;
407       }
408
409       inline mapped_reference
410       subscript_imp(const_key_reference r_key, store_hash_true_type)
411       {
412         _GLIBCXX_DEBUG_ONLY(assert_valid();)
413         comp_hash pos_hash_pair = ranged_hash_fn_base::operator()(r_key);
414         entry_pointer p_e = m_entries[pos_hash_pair.first];
415         resize_base::notify_insert_search_start();
416         while (p_e != NULL && 
417                !hash_eq_fn_base::operator()(p_e->m_value.first, p_e->m_hash, r_key, pos_hash_pair.second))
418           {
419             resize_base::notify_insert_search_collision();
420             p_e = p_e->m_p_next;
421           }
422
423         resize_base::notify_insert_search_end();
424         if (p_e != NULL)
425           {
426             _GLIBCXX_DEBUG_ONLY(map_debug_base::check_key_exists(r_key);)
427             return p_e->m_value.second;
428           }
429
430         _GLIBCXX_DEBUG_ONLY(map_debug_base::check_key_does_not_exist(r_key);)
431         return insert_new_imp(value_type(r_key, mapped_type()), 
432                               pos_hash_pair)->second;
433       }
434 #endif 
435
436       inline std::pair<point_iterator, bool>
437       insert_imp(const_reference, store_hash_false_type);
438
439       inline std::pair<point_iterator, bool>
440       insert_imp(const_reference, store_hash_true_type);
441
442       inline pointer
443       insert_new_imp(const_reference r_val, size_type pos)
444       {
445         if (do_resize_if_needed())
446           pos = ranged_hash_fn_base::operator()(PB_DS_V2F(r_val));
447
448         // Following lines might throw an exception.
449         entry_pointer p_e = get_entry(r_val, traits_base::m_no_throw_copies_indicator);
450
451         // At this point no exceptions can be thrown.
452         p_e->m_p_next = m_entries[pos];
453         m_entries[pos] = p_e;
454         resize_base::notify_inserted(++m_num_used_e);
455
456         _GLIBCXX_DEBUG_ONLY(map_debug_base::insert_new(PB_DS_V2F(r_val));)
457         _GLIBCXX_DEBUG_ONLY(assert_valid();)
458         return &p_e->m_value;
459       }
460
461       inline pointer
462       insert_new_imp(const_reference r_val, comp_hash& r_pos_hash_pair)
463       {
464         // Following lines might throw an exception.
465         if (do_resize_if_needed())
466           r_pos_hash_pair = ranged_hash_fn_base::operator()(PB_DS_V2F(r_val));
467
468         entry_pointer p_e = get_entry(r_val, traits_base::m_no_throw_copies_indicator);
469
470         // At this point no exceptions can be thrown.
471         p_e->m_hash = r_pos_hash_pair.second;
472         p_e->m_p_next = m_entries[r_pos_hash_pair.first];
473         m_entries[r_pos_hash_pair.first] = p_e;
474         resize_base::notify_inserted(++m_num_used_e);
475         _GLIBCXX_DEBUG_ONLY(map_debug_base::insert_new(PB_DS_V2F(r_val));)
476         _GLIBCXX_DEBUG_ONLY(assert_valid();)
477         return &p_e->m_value;
478       }
479
480       inline pointer
481       find_key_pointer(const_key_reference r_key, store_hash_false_type)
482       {
483         entry_pointer p_e = m_entries[ranged_hash_fn_base::operator()(r_key)];
484         resize_base::notify_find_search_start();
485         while (p_e != NULL && 
486                !hash_eq_fn_base::operator()(PB_DS_V2F(p_e->m_value), r_key))
487           {
488             resize_base::notify_find_search_collision();
489             p_e = p_e->m_p_next;
490           }
491
492         resize_base::notify_find_search_end();
493
494 #ifdef _GLIBCXX_DEBUG
495         if (p_e == NULL)
496           map_debug_base::check_key_does_not_exist(r_key);
497         else
498           map_debug_base::check_key_exists(r_key);
499 #endif 
500         return &p_e->m_value;
501       }
502
503       inline pointer
504       find_key_pointer(const_key_reference r_key, store_hash_true_type)
505       {
506         comp_hash pos_hash_pair = ranged_hash_fn_base::operator()(r_key);
507         entry_pointer p_e = m_entries[pos_hash_pair.first];
508         resize_base::notify_find_search_start();
509         while (p_e != NULL && 
510                !hash_eq_fn_base::operator()(PB_DS_V2F(p_e->m_value),
511                                             p_e->m_hash,
512                                             r_key, pos_hash_pair.second))
513           {
514             resize_base::notify_find_search_collision();
515             p_e = p_e->m_p_next;
516           }
517
518         resize_base::notify_find_search_end();
519
520 #ifdef _GLIBCXX_DEBUG
521         if (p_e == NULL)
522           map_debug_base::check_key_does_not_exist(r_key);
523         else
524           map_debug_base::check_key_exists(r_key);
525 #endif 
526         return &p_e->m_value;
527       }
528
529       inline bool
530       erase_in_pos_imp(const_key_reference, size_type);
531
532       inline bool
533       erase_in_pos_imp(const_key_reference, const comp_hash&);
534
535       inline void
536       erase_entry_pointer(entry_pointer&);
537
538 #ifdef PB_DS_DATA_TRUE_INDICATOR
539       void
540       inc_it_state(pointer& r_p_value, 
541                    std::pair<entry_pointer, size_type>& r_pos) const
542       {
543         inc_it_state((const_mapped_pointer& )r_p_value, r_pos);
544       }
545 #endif 
546
547       void
548       inc_it_state(const_pointer& r_p_value, 
549                    std::pair<entry_pointer, size_type>& r_pos) const
550       {
551         _GLIBCXX_DEBUG_ASSERT(r_p_value != NULL);
552         r_pos.first = r_pos.first->m_p_next;
553         if (r_pos.first != NULL)
554           {
555             r_p_value = &r_pos.first->m_value;
556             return;
557           }
558
559         for (++r_pos.second; r_pos.second < m_num_e; ++r_pos.second)
560           if (m_entries[r_pos.second] != NULL)
561             {
562               r_pos.first = m_entries[r_pos.second];
563               r_p_value = &r_pos.first->m_value;
564               return;
565             }
566         r_p_value = NULL;
567       }
568
569       void
570       get_start_it_state(pointer& r_p_value, 
571                          std::pair<entry_pointer, size_type>& r_pos) const
572       {
573         for (r_pos.second = 0; r_pos.second < m_num_e; ++r_pos.second)
574           if (m_entries[r_pos.second] != NULL)
575             {
576               r_pos.first = m_entries[r_pos.second];
577               r_p_value = &r_pos.first->m_value;
578               return;
579             }
580         r_p_value = NULL;
581       }
582
583 #ifdef _GLIBCXX_DEBUG
584       void
585       assert_entry_pointer_array_valid(const entry_pointer_array) const;
586
587       void
588       assert_entry_pointer_valid(const entry_pointer, 
589                                  store_hash_true_type) const;
590
591       void
592       assert_entry_pointer_valid(const entry_pointer, 
593                                  store_hash_false_type) const;
594 #endif 
595
596 #ifdef PB_DS_HT_MAP_TRACE_
597       void
598       trace_list(const_entry_pointer p_l) const;
599 #endif 
600
601     private:
602 #ifdef PB_DS_DATA_TRUE_INDICATOR
603       friend class iterator_;
604 #endif 
605
606       friend class const_iterator_;
607
608       static entry_allocator            s_entry_allocator;
609       static entry_pointer_allocator    s_entry_pointer_allocator;
610       static iterator                   s_end_it;
611       static const_iterator             s_const_end_it;
612       static point_iterator             s_find_end_it;
613       static const_point_iterator       s_const_find_end_it;
614
615       size_type                         m_num_e;
616       size_type                         m_num_used_e;
617       entry_pointer_array               m_entries;
618
619       enum
620         {
621           store_hash_ok = !Store_Hash 
622                           || !is_same<Hash_Fn, pb_ds::null_hash_fn>::value
623         };
624
625       PB_DS_STATIC_ASSERT(sth, store_hash_ok);
626     };
627
628 #include <ext/pb_ds/detail/cc_hash_table_map_/constructor_destructor_fn_imps.hpp>
629 #include <ext/pb_ds/detail/cc_hash_table_map_/entry_list_fn_imps.hpp>
630 #include <ext/pb_ds/detail/cc_hash_table_map_/find_fn_imps.hpp>
631 #include <ext/pb_ds/detail/cc_hash_table_map_/resize_fn_imps.hpp>
632 #include <ext/pb_ds/detail/cc_hash_table_map_/debug_fn_imps.hpp>
633 #include <ext/pb_ds/detail/cc_hash_table_map_/size_fn_imps.hpp>
634 #include <ext/pb_ds/detail/cc_hash_table_map_/policy_access_fn_imps.hpp>
635 #include <ext/pb_ds/detail/cc_hash_table_map_/erase_fn_imps.hpp>
636 #include <ext/pb_ds/detail/cc_hash_table_map_/iterators_fn_imps.hpp>
637 #include <ext/pb_ds/detail/cc_hash_table_map_/insert_fn_imps.hpp>
638 #include <ext/pb_ds/detail/cc_hash_table_map_/trace_fn_imps.hpp>
639
640 #undef PB_DS_CLASS_T_DEC
641 #undef PB_DS_CLASS_C_DEC
642 #undef PB_DS_HASH_EQ_FN_C_DEC
643 #undef PB_DS_RANGED_HASH_FN_C_DEC
644 #undef PB_DS_TYPES_TRAITS_C_DEC
645 #undef PB_DS_MAP_DEBUG_BASE_C_DEC
646 #undef PB_DS_CLASS_NAME
647 #undef PB_DS_V2F
648 #undef PB_DS_V2S
649 #undef PB_DS_STATIC_ASSERT
650
651   } // namespace detail
652 } // namespace pb_ds
653