File: | build/gcc/vec.h |
Warning: | line 815, column 10 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* Data structure for the modref pass. | |||
2 | Copyright (C) 2020-2021 Free Software Foundation, Inc. | |||
3 | Contributed by David Cepelik and Jan Hubicka | |||
4 | ||||
5 | This file is part of GCC. | |||
6 | ||||
7 | GCC is free software; you can redistribute it and/or modify it under | |||
8 | the terms of the GNU General Public License as published by the Free | |||
9 | Software Foundation; either version 3, or (at your option) any later | |||
10 | version. | |||
11 | ||||
12 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |||
13 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |||
14 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |||
15 | for more details. | |||
16 | ||||
17 | You should have received a copy of the GNU General Public License | |||
18 | along with GCC; see the file COPYING3. If not see | |||
19 | <http://www.gnu.org/licenses/>. */ | |||
20 | ||||
21 | #include "config.h" | |||
22 | #include "system.h" | |||
23 | #include "coretypes.h" | |||
24 | #include "backend.h" | |||
25 | #include "tree.h" | |||
26 | #include "ipa-modref-tree.h" | |||
27 | #include "selftest.h" | |||
28 | ||||
29 | #if CHECKING_P1 | |||
30 | ||||
31 | namespace selftest { | |||
32 | ||||
33 | static void | |||
34 | test_insert_search_collapse () | |||
35 | { | |||
36 | modref_base_node<alias_set_type> *base_node; | |||
37 | modref_ref_node<alias_set_type> *ref_node; | |||
38 | modref_access_node a = unspecified_modref_access_node; | |||
39 | ||||
40 | modref_tree<alias_set_type> *t = new modref_tree<alias_set_type>(1, 2, 2); | |||
41 | ASSERT_FALSE (t->every_base)do { const char *desc_ = "ASSERT_FALSE (" "(t->every_base)" ")"; bool actual_ = ((t->every_base)); if (actual_) ::selftest ::fail (((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 41, __FUNCTION__))), desc_); else ::selftest::pass (((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 41, __FUNCTION__))), desc_); } while (0); | |||
42 | ||||
43 | /* Insert into an empty tree. */ | |||
44 | t->insert (1, 2, a); | |||
45 | ASSERT_NE (t->bases, NULL)do { const char *desc_ = "ASSERT_NE (" "t->bases" ", " "NULL" ")"; if ((t->bases) != (nullptr)) ::selftest::pass ((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 45, __FUNCTION__)), desc_); else ::selftest::fail ((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 45, __FUNCTION__)), desc_); } while (0); | |||
46 | ASSERT_EQ (t->bases->length (), 1)do { const char *desc_ = "ASSERT_EQ (" "(t->bases->length ())" ", " "(1)" ")"; if (((t->bases->length ())) == ((1))) :: selftest::pass ((((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 46, __FUNCTION__)))), desc_); else ::selftest::fail ((((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 46, __FUNCTION__)))), desc_); } while (0); | |||
47 | ASSERT_FALSE (t->every_base)do { const char *desc_ = "ASSERT_FALSE (" "(t->every_base)" ")"; bool actual_ = ((t->every_base)); if (actual_) ::selftest ::fail (((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 47, __FUNCTION__))), desc_); else ::selftest::pass (((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 47, __FUNCTION__))), desc_); } while (0); | |||
48 | ASSERT_EQ (t->search (2), NULL)do { const char *desc_ = "ASSERT_EQ (" "(t->search (2))" ", " "(nullptr)" ")"; if (((t->search (2))) == ((nullptr))) :: selftest::pass ((((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 48, __FUNCTION__)))), desc_); else ::selftest::fail ((((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 48, __FUNCTION__)))), desc_); } while (0); | |||
49 | ||||
50 | base_node = t->search (1); | |||
51 | ASSERT_NE (base_node, NULL)do { const char *desc_ = "ASSERT_NE (" "base_node" ", " "NULL" ")"; if ((base_node) != (nullptr)) ::selftest::pass ((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 51, __FUNCTION__)), desc_); else ::selftest::fail ((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 51, __FUNCTION__)), desc_); } while (0); | |||
52 | ASSERT_EQ (base_node->base, 1)do { const char *desc_ = "ASSERT_EQ (" "(base_node->base)" ", " "(1)" ")"; if (((base_node->base)) == ((1))) ::selftest ::pass ((((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 52, __FUNCTION__)))), desc_); else ::selftest::fail ((((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 52, __FUNCTION__)))), desc_); } while (0); | |||
53 | ASSERT_NE (base_node->refs, NULL)do { const char *desc_ = "ASSERT_NE (" "base_node->refs" ", " "NULL" ")"; if ((base_node->refs) != (nullptr)) ::selftest ::pass ((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 53, __FUNCTION__)), desc_); else ::selftest::fail ((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 53, __FUNCTION__)), desc_); } while (0); | |||
54 | ASSERT_EQ (base_node->refs->length (), 1)do { const char *desc_ = "ASSERT_EQ (" "(base_node->refs->length ())" ", " "(1)" ")"; if (((base_node->refs->length ())) == ( (1))) ::selftest::pass ((((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 54, __FUNCTION__)))), desc_); else ::selftest::fail ((((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 54, __FUNCTION__)))), desc_); } while (0); | |||
55 | ASSERT_EQ (base_node->search (1), NULL)do { const char *desc_ = "ASSERT_EQ (" "(base_node->search (1))" ", " "(nullptr)" ")"; if (((base_node->search (1))) == (( nullptr))) ::selftest::pass ((((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 55, __FUNCTION__)))), desc_); else ::selftest::fail ((((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 55, __FUNCTION__)))), desc_); } while (0); | |||
56 | ||||
57 | ref_node = base_node->search (2); | |||
58 | ASSERT_NE (ref_node, NULL)do { const char *desc_ = "ASSERT_NE (" "ref_node" ", " "NULL" ")"; if ((ref_node) != (nullptr)) ::selftest::pass ((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 58, __FUNCTION__)), desc_); else ::selftest::fail ((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 58, __FUNCTION__)), desc_); } while (0); | |||
59 | ASSERT_EQ (ref_node->ref, 2)do { const char *desc_ = "ASSERT_EQ (" "(ref_node->ref)" ", " "(2)" ")"; if (((ref_node->ref)) == ((2))) ::selftest::pass ((((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 59, __FUNCTION__)))), desc_); else ::selftest::fail ((((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 59, __FUNCTION__)))), desc_); } while (0); | |||
60 | ||||
61 | /* Insert when base exists but ref does not. */ | |||
62 | t->insert (1, 3, a); | |||
63 | ASSERT_NE (t->bases, NULL)do { const char *desc_ = "ASSERT_NE (" "t->bases" ", " "NULL" ")"; if ((t->bases) != (nullptr)) ::selftest::pass ((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 63, __FUNCTION__)), desc_); else ::selftest::fail ((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 63, __FUNCTION__)), desc_); } while (0); | |||
64 | ASSERT_EQ (t->bases->length (), 1)do { const char *desc_ = "ASSERT_EQ (" "(t->bases->length ())" ", " "(1)" ")"; if (((t->bases->length ())) == ((1))) :: selftest::pass ((((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 64, __FUNCTION__)))), desc_); else ::selftest::fail ((((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 64, __FUNCTION__)))), desc_); } while (0); | |||
65 | ASSERT_EQ (t->search (1), base_node)do { const char *desc_ = "ASSERT_EQ (" "(t->search (1))" ", " "(base_node)" ")"; if (((t->search (1))) == ((base_node)) ) ::selftest::pass ((((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 65, __FUNCTION__)))), desc_); else ::selftest::fail ((((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 65, __FUNCTION__)))), desc_); } while (0); | |||
66 | ASSERT_EQ (t->search (2), NULL)do { const char *desc_ = "ASSERT_EQ (" "(t->search (2))" ", " "(nullptr)" ")"; if (((t->search (2))) == ((nullptr))) :: selftest::pass ((((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 66, __FUNCTION__)))), desc_); else ::selftest::fail ((((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 66, __FUNCTION__)))), desc_); } while (0); | |||
67 | ASSERT_NE (base_node->refs, NULL)do { const char *desc_ = "ASSERT_NE (" "base_node->refs" ", " "NULL" ")"; if ((base_node->refs) != (nullptr)) ::selftest ::pass ((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 67, __FUNCTION__)), desc_); else ::selftest::fail ((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 67, __FUNCTION__)), desc_); } while (0); | |||
68 | ASSERT_EQ (base_node->refs->length (), 2)do { const char *desc_ = "ASSERT_EQ (" "(base_node->refs->length ())" ", " "(2)" ")"; if (((base_node->refs->length ())) == ( (2))) ::selftest::pass ((((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 68, __FUNCTION__)))), desc_); else ::selftest::fail ((((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 68, __FUNCTION__)))), desc_); } while (0); | |||
69 | ||||
70 | ref_node = base_node->search (3); | |||
71 | ASSERT_NE (ref_node, NULL)do { const char *desc_ = "ASSERT_NE (" "ref_node" ", " "NULL" ")"; if ((ref_node) != (nullptr)) ::selftest::pass ((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 71, __FUNCTION__)), desc_); else ::selftest::fail ((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 71, __FUNCTION__)), desc_); } while (0); | |||
72 | ||||
73 | /* Insert when base and ref exist, but access is not dominated by nor | |||
74 | dominates other accesses. */ | |||
75 | t->insert (1, 2, a); | |||
76 | ASSERT_EQ (t->bases->length (), 1)do { const char *desc_ = "ASSERT_EQ (" "(t->bases->length ())" ", " "(1)" ")"; if (((t->bases->length ())) == ((1))) :: selftest::pass ((((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 76, __FUNCTION__)))), desc_); else ::selftest::fail ((((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 76, __FUNCTION__)))), desc_); } while (0); | |||
77 | ASSERT_EQ (t->search (1), base_node)do { const char *desc_ = "ASSERT_EQ (" "(t->search (1))" ", " "(base_node)" ")"; if (((t->search (1))) == ((base_node)) ) ::selftest::pass ((((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 77, __FUNCTION__)))), desc_); else ::selftest::fail ((((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 77, __FUNCTION__)))), desc_); } while (0); | |||
78 | ||||
79 | ref_node = base_node->search (2); | |||
80 | ASSERT_NE (ref_node, NULL)do { const char *desc_ = "ASSERT_NE (" "ref_node" ", " "NULL" ")"; if ((ref_node) != (nullptr)) ::selftest::pass ((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 80, __FUNCTION__)), desc_); else ::selftest::fail ((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 80, __FUNCTION__)), desc_); } while (0); | |||
81 | ||||
82 | /* Insert when base and ref exist and access is dominated. */ | |||
83 | t->insert (1, 2, a); | |||
84 | ASSERT_EQ (t->search (1), base_node)do { const char *desc_ = "ASSERT_EQ (" "(t->search (1))" ", " "(base_node)" ")"; if (((t->search (1))) == ((base_node)) ) ::selftest::pass ((((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 84, __FUNCTION__)))), desc_); else ::selftest::fail ((((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 84, __FUNCTION__)))), desc_); } while (0); | |||
85 | ASSERT_EQ (base_node->search (2), ref_node)do { const char *desc_ = "ASSERT_EQ (" "(base_node->search (2))" ", " "(ref_node)" ")"; if (((base_node->search (2))) == ( (ref_node))) ::selftest::pass ((((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 85, __FUNCTION__)))), desc_); else ::selftest::fail ((((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 85, __FUNCTION__)))), desc_); } while (0); | |||
86 | ||||
87 | /* Insert ref to trigger ref list collapse for base 1. */ | |||
88 | t->insert (1, 4, a); | |||
89 | ASSERT_EQ (t->search (1), base_node)do { const char *desc_ = "ASSERT_EQ (" "(t->search (1))" ", " "(base_node)" ")"; if (((t->search (1))) == ((base_node)) ) ::selftest::pass ((((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 89, __FUNCTION__)))), desc_); else ::selftest::fail ((((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 89, __FUNCTION__)))), desc_); } while (0); | |||
90 | ASSERT_EQ (base_node->refs, NULL)do { const char *desc_ = "ASSERT_EQ (" "(base_node->refs)" ", " "(nullptr)" ")"; if (((base_node->refs)) == ((nullptr ))) ::selftest::pass ((((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 90, __FUNCTION__)))), desc_); else ::selftest::fail ((((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 90, __FUNCTION__)))), desc_); } while (0); | |||
91 | ASSERT_EQ (base_node->search (2), NULL)do { const char *desc_ = "ASSERT_EQ (" "(base_node->search (2))" ", " "(nullptr)" ")"; if (((base_node->search (2))) == (( nullptr))) ::selftest::pass ((((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 91, __FUNCTION__)))), desc_); else ::selftest::fail ((((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 91, __FUNCTION__)))), desc_); } while (0); | |||
92 | ASSERT_EQ (base_node->search (3), NULL)do { const char *desc_ = "ASSERT_EQ (" "(base_node->search (3))" ", " "(nullptr)" ")"; if (((base_node->search (3))) == (( nullptr))) ::selftest::pass ((((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 92, __FUNCTION__)))), desc_); else ::selftest::fail ((((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 92, __FUNCTION__)))), desc_); } while (0); | |||
93 | ASSERT_TRUE (base_node->every_ref)do { const char *desc_ = "ASSERT_TRUE (" "(base_node->every_ref)" ")"; bool actual_ = ((base_node->every_ref)); if (actual_ ) ::selftest::pass (((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 93, __FUNCTION__))), desc_); else ::selftest::fail (((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 93, __FUNCTION__))), desc_); } while (0); | |||
94 | ||||
95 | /* Further inserts to collapsed ref list are ignored. */ | |||
96 | t->insert (1, 5, a); | |||
97 | ASSERT_EQ (t->search (1), base_node)do { const char *desc_ = "ASSERT_EQ (" "(t->search (1))" ", " "(base_node)" ")"; if (((t->search (1))) == ((base_node)) ) ::selftest::pass ((((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 97, __FUNCTION__)))), desc_); else ::selftest::fail ((((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 97, __FUNCTION__)))), desc_); } while (0); | |||
98 | ASSERT_EQ (base_node->refs, NULL)do { const char *desc_ = "ASSERT_EQ (" "(base_node->refs)" ", " "(nullptr)" ")"; if (((base_node->refs)) == ((nullptr ))) ::selftest::pass ((((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 98, __FUNCTION__)))), desc_); else ::selftest::fail ((((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 98, __FUNCTION__)))), desc_); } while (0); | |||
99 | ASSERT_EQ (base_node->search (2), NULL)do { const char *desc_ = "ASSERT_EQ (" "(base_node->search (2))" ", " "(nullptr)" ")"; if (((base_node->search (2))) == (( nullptr))) ::selftest::pass ((((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 99, __FUNCTION__)))), desc_); else ::selftest::fail ((((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 99, __FUNCTION__)))), desc_); } while (0); | |||
100 | ASSERT_EQ (base_node->search (3), NULL)do { const char *desc_ = "ASSERT_EQ (" "(base_node->search (3))" ", " "(nullptr)" ")"; if (((base_node->search (3))) == (( nullptr))) ::selftest::pass ((((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 100, __FUNCTION__)))), desc_); else ::selftest::fail ((((:: selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 100, __FUNCTION__)))), desc_); } while (0); | |||
101 | ASSERT_TRUE (base_node->every_ref)do { const char *desc_ = "ASSERT_TRUE (" "(base_node->every_ref)" ")"; bool actual_ = ((base_node->every_ref)); if (actual_ ) ::selftest::pass (((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 101, __FUNCTION__))), desc_); else ::selftest::fail (((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 101, __FUNCTION__))), desc_); } while (0); | |||
102 | ||||
103 | /* Insert base to trigger base list collapse. */ | |||
104 | t->insert (5, 6, a); | |||
105 | ASSERT_TRUE (t->every_base)do { const char *desc_ = "ASSERT_TRUE (" "(t->every_base)" ")"; bool actual_ = ((t->every_base)); if (actual_) ::selftest ::pass (((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 105, __FUNCTION__))), desc_); else ::selftest::fail (((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 105, __FUNCTION__))), desc_); } while (0); | |||
106 | ASSERT_EQ (t->bases, NULL)do { const char *desc_ = "ASSERT_EQ (" "(t->bases)" ", " "(nullptr)" ")"; if (((t->bases)) == ((nullptr))) ::selftest::pass (( ((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 106, __FUNCTION__)))), desc_); else ::selftest::fail ((((:: selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 106, __FUNCTION__)))), desc_); } while (0); | |||
107 | ASSERT_EQ (t->search (1), NULL)do { const char *desc_ = "ASSERT_EQ (" "(t->search (1))" ", " "(nullptr)" ")"; if (((t->search (1))) == ((nullptr))) :: selftest::pass ((((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 107, __FUNCTION__)))), desc_); else ::selftest::fail ((((:: selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 107, __FUNCTION__)))), desc_); } while (0); | |||
108 | ||||
109 | /* Further inserts to collapsed base list are ignored. */ | |||
110 | t->insert (7, 8, a); | |||
111 | ASSERT_TRUE (t->every_base)do { const char *desc_ = "ASSERT_TRUE (" "(t->every_base)" ")"; bool actual_ = ((t->every_base)); if (actual_) ::selftest ::pass (((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 111, __FUNCTION__))), desc_); else ::selftest::fail (((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 111, __FUNCTION__))), desc_); } while (0); | |||
112 | ASSERT_EQ (t->bases, NULL)do { const char *desc_ = "ASSERT_EQ (" "(t->bases)" ", " "(nullptr)" ")"; if (((t->bases)) == ((nullptr))) ::selftest::pass (( ((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 112, __FUNCTION__)))), desc_); else ::selftest::fail ((((:: selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 112, __FUNCTION__)))), desc_); } while (0); | |||
113 | ASSERT_EQ (t->search (1), NULL)do { const char *desc_ = "ASSERT_EQ (" "(t->search (1))" ", " "(nullptr)" ")"; if (((t->search (1))) == ((nullptr))) :: selftest::pass ((((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 113, __FUNCTION__)))), desc_); else ::selftest::fail ((((:: selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 113, __FUNCTION__)))), desc_); } while (0); | |||
114 | ||||
115 | delete t; | |||
116 | } | |||
117 | ||||
118 | static void | |||
119 | test_merge () | |||
120 | { | |||
121 | modref_tree<alias_set_type> *t1, *t2; | |||
122 | modref_base_node<alias_set_type> *base_node; | |||
123 | modref_access_node a = unspecified_modref_access_node; | |||
124 | ||||
125 | t1 = new modref_tree<alias_set_type>(3, 4, 1); | |||
126 | t1->insert (1, 1, a); | |||
127 | t1->insert (1, 2, a); | |||
128 | t1->insert (1, 3, a); | |||
129 | t1->insert (2, 1, a); | |||
130 | t1->insert (3, 1, a); | |||
131 | ||||
132 | t2 = new modref_tree<alias_set_type>(10, 10, 10); | |||
133 | t2->insert (1, 2, a); | |||
134 | t2->insert (1, 3, a); | |||
135 | t2->insert (1, 4, a); | |||
136 | t2->insert (3, 2, a); | |||
137 | t2->insert (3, 3, a); | |||
138 | t2->insert (3, 4, a); | |||
139 | t2->insert (3, 5, a); | |||
140 | ||||
141 | t1->merge (t2, NULLnullptr); | |||
142 | ||||
143 | ASSERT_FALSE (t1->every_base)do { const char *desc_ = "ASSERT_FALSE (" "(t1->every_base)" ")"; bool actual_ = ((t1->every_base)); if (actual_) ::selftest ::fail (((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 143, __FUNCTION__))), desc_); else ::selftest::pass (((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 143, __FUNCTION__))), desc_); } while (0); | |||
144 | ASSERT_NE (t1->bases, NULL)do { const char *desc_ = "ASSERT_NE (" "t1->bases" ", " "NULL" ")"; if ((t1->bases) != (nullptr)) ::selftest::pass ((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 144, __FUNCTION__)), desc_); else ::selftest::fail ((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 144, __FUNCTION__)), desc_); } while (0); | |||
145 | ASSERT_EQ (t1->bases->length (), 3)do { const char *desc_ = "ASSERT_EQ (" "(t1->bases->length ())" ", " "(3)" ")"; if (((t1->bases->length ())) == ((3))) ::selftest::pass ((((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 145, __FUNCTION__)))), desc_); else ::selftest::fail ((((:: selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 145, __FUNCTION__)))), desc_); } while (0); | |||
146 | ||||
147 | base_node = t1->search (1); | |||
148 | ASSERT_NE (base_node->refs, NULL)do { const char *desc_ = "ASSERT_NE (" "base_node->refs" ", " "NULL" ")"; if ((base_node->refs) != (nullptr)) ::selftest ::pass ((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 148, __FUNCTION__)), desc_); else ::selftest::fail ((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 148, __FUNCTION__)), desc_); } while (0); | |||
149 | ASSERT_FALSE (base_node->every_ref)do { const char *desc_ = "ASSERT_FALSE (" "(base_node->every_ref)" ")"; bool actual_ = ((base_node->every_ref)); if (actual_ ) ::selftest::fail (((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 149, __FUNCTION__))), desc_); else ::selftest::pass (((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 149, __FUNCTION__))), desc_); } while (0); | |||
150 | ASSERT_EQ (base_node->refs->length (), 4)do { const char *desc_ = "ASSERT_EQ (" "(base_node->refs->length ())" ", " "(4)" ")"; if (((base_node->refs->length ())) == ( (4))) ::selftest::pass ((((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 150, __FUNCTION__)))), desc_); else ::selftest::fail ((((:: selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 150, __FUNCTION__)))), desc_); } while (0); | |||
151 | ||||
152 | base_node = t1->search (2); | |||
153 | ASSERT_NE (base_node->refs, NULL)do { const char *desc_ = "ASSERT_NE (" "base_node->refs" ", " "NULL" ")"; if ((base_node->refs) != (nullptr)) ::selftest ::pass ((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 153, __FUNCTION__)), desc_); else ::selftest::fail ((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 153, __FUNCTION__)), desc_); } while (0); | |||
154 | ASSERT_FALSE (base_node->every_ref)do { const char *desc_ = "ASSERT_FALSE (" "(base_node->every_ref)" ")"; bool actual_ = ((base_node->every_ref)); if (actual_ ) ::selftest::fail (((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 154, __FUNCTION__))), desc_); else ::selftest::pass (((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 154, __FUNCTION__))), desc_); } while (0); | |||
155 | ASSERT_EQ (base_node->refs->length (), 1)do { const char *desc_ = "ASSERT_EQ (" "(base_node->refs->length ())" ", " "(1)" ")"; if (((base_node->refs->length ())) == ( (1))) ::selftest::pass ((((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 155, __FUNCTION__)))), desc_); else ::selftest::fail ((((:: selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 155, __FUNCTION__)))), desc_); } while (0); | |||
156 | ||||
157 | base_node = t1->search (3); | |||
158 | ASSERT_EQ (base_node->refs, NULL)do { const char *desc_ = "ASSERT_EQ (" "(base_node->refs)" ", " "(nullptr)" ")"; if (((base_node->refs)) == ((nullptr ))) ::selftest::pass ((((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 158, __FUNCTION__)))), desc_); else ::selftest::fail ((((:: selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 158, __FUNCTION__)))), desc_); } while (0); | |||
159 | ASSERT_TRUE (base_node->every_ref)do { const char *desc_ = "ASSERT_TRUE (" "(base_node->every_ref)" ")"; bool actual_ = ((base_node->every_ref)); if (actual_ ) ::selftest::pass (((::selftest::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 159, __FUNCTION__))), desc_); else ::selftest::fail (((::selftest ::location ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.c" , 159, __FUNCTION__))), desc_); } while (0); | |||
160 | ||||
161 | delete t1; | |||
162 | delete t2; | |||
163 | } | |||
164 | ||||
165 | ||||
166 | void | |||
167 | ipa_modref_tree_c_tests () | |||
168 | { | |||
169 | test_insert_search_collapse (); | |||
170 | test_merge (); | |||
| ||||
171 | } | |||
172 | ||||
173 | } // namespace selftest | |||
174 | ||||
175 | #endif | |||
176 | ||||
177 | void | |||
178 | gt_ggc_mx (modref_tree < int >*const &tt) | |||
179 | { | |||
180 | if (tt->bases) | |||
181 | { | |||
182 | ggc_test_and_set_mark (tt->bases)((tt->bases) != nullptr && ((void *) (tt->bases )) != (void *) 1 && ! ggc_set_mark (tt->bases)); | |||
183 | gt_ggc_mx (tt->bases); | |||
184 | } | |||
185 | } | |||
186 | ||||
187 | void | |||
188 | gt_ggc_mx (modref_tree < tree_node * >*const &tt) | |||
189 | { | |||
190 | if (tt->bases) | |||
191 | { | |||
192 | ggc_test_and_set_mark (tt->bases)((tt->bases) != nullptr && ((void *) (tt->bases )) != (void *) 1 && ! ggc_set_mark (tt->bases)); | |||
193 | gt_ggc_mx (tt->bases); | |||
194 | } | |||
195 | } | |||
196 | ||||
197 | void gt_pch_nx (modref_tree<int>* const&) {} | |||
198 | void gt_pch_nx (modref_tree<tree_node*>* const&) {} | |||
199 | void gt_pch_nx (modref_tree<int>* const&, gt_pointer_operator, void *) {} | |||
200 | void gt_pch_nx (modref_tree<tree_node*>* const&, gt_pointer_operator, void *) {} | |||
201 | ||||
202 | void gt_ggc_mx (modref_base_node<int>* &b) | |||
203 | { | |||
204 | ggc_test_and_set_mark (b)((b) != nullptr && ((void *) (b)) != (void *) 1 && ! ggc_set_mark (b)); | |||
205 | if (b->refs) | |||
206 | { | |||
207 | ggc_test_and_set_mark (b->refs)((b->refs) != nullptr && ((void *) (b->refs)) != (void *) 1 && ! ggc_set_mark (b->refs)); | |||
208 | gt_ggc_mx (b->refs); | |||
209 | } | |||
210 | } | |||
211 | ||||
212 | void gt_ggc_mx (modref_base_node<tree_node*>* &b) | |||
213 | { | |||
214 | ggc_test_and_set_mark (b)((b) != nullptr && ((void *) (b)) != (void *) 1 && ! ggc_set_mark (b)); | |||
215 | if (b->refs) | |||
216 | { | |||
217 | ggc_test_and_set_mark (b->refs)((b->refs) != nullptr && ((void *) (b->refs)) != (void *) 1 && ! ggc_set_mark (b->refs)); | |||
218 | gt_ggc_mx (b->refs); | |||
219 | } | |||
220 | if (b->base) | |||
221 | gt_ggc_mx (b->base); | |||
222 | } | |||
223 | ||||
224 | void gt_pch_nx (modref_base_node<int>*) {} | |||
225 | void gt_pch_nx (modref_base_node<tree_node*>*) {} | |||
226 | void gt_pch_nx (modref_base_node<int>*, gt_pointer_operator, void *) {} | |||
227 | void gt_pch_nx (modref_base_node<tree_node*>*, gt_pointer_operator, void *) {} | |||
228 | ||||
229 | void gt_ggc_mx (modref_ref_node<int>* &r) | |||
230 | { | |||
231 | ggc_test_and_set_mark (r)((r) != nullptr && ((void *) (r)) != (void *) 1 && ! ggc_set_mark (r)); | |||
232 | if (r->accesses) | |||
233 | { | |||
234 | ggc_test_and_set_mark (r->accesses)((r->accesses) != nullptr && ((void *) (r->accesses )) != (void *) 1 && ! ggc_set_mark (r->accesses)); | |||
235 | gt_ggc_mx (r->accesses); | |||
236 | } | |||
237 | } | |||
238 | ||||
239 | void gt_ggc_mx (modref_ref_node<tree_node*>* &r) | |||
240 | { | |||
241 | ggc_test_and_set_mark (r)((r) != nullptr && ((void *) (r)) != (void *) 1 && ! ggc_set_mark (r)); | |||
242 | if (r->accesses) | |||
243 | { | |||
244 | ggc_test_and_set_mark (r->accesses)((r->accesses) != nullptr && ((void *) (r->accesses )) != (void *) 1 && ! ggc_set_mark (r->accesses)); | |||
245 | gt_ggc_mx (r->accesses); | |||
246 | } | |||
247 | if (r->ref) | |||
248 | gt_ggc_mx (r->ref); | |||
249 | } | |||
250 | ||||
251 | void gt_pch_nx (modref_ref_node<int>* ) {} | |||
252 | void gt_pch_nx (modref_ref_node<tree_node*>*) {} | |||
253 | void gt_pch_nx (modref_ref_node<int>*, gt_pointer_operator, void *) {} | |||
254 | void gt_pch_nx (modref_ref_node<tree_node*>*, gt_pointer_operator, void *) {} | |||
255 | ||||
256 | void gt_ggc_mx (modref_access_node &) | |||
257 | { | |||
258 | } |
1 | /* Data structure for the modref pass. | ||||||
2 | Copyright (C) 2020-2021 Free Software Foundation, Inc. | ||||||
3 | Contributed by David Cepelik and Jan Hubicka | ||||||
4 | |||||||
5 | This file is part of GCC. | ||||||
6 | |||||||
7 | GCC is free software; you can redistribute it and/or modify it under | ||||||
8 | the terms of the GNU General Public License as published by the Free | ||||||
9 | Software Foundation; either version 3, or (at your option) any later | ||||||
10 | version. | ||||||
11 | |||||||
12 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY | ||||||
13 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||||
14 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||||||
15 | for more details. | ||||||
16 | |||||||
17 | You should have received a copy of the GNU General Public License | ||||||
18 | along with GCC; see the file COPYING3. If not see | ||||||
19 | <http://www.gnu.org/licenses/>. */ | ||||||
20 | |||||||
21 | /* modref_tree represent a decision tree that can be used by alias analysis | ||||||
22 | oracle to determine whether given memory access can be affected by a function | ||||||
23 | call. For every function we collect two trees, one for loads and other | ||||||
24 | for stores. Tree consist of following levels: | ||||||
25 | |||||||
26 | 1) Base: this level represent base alias set of the access and refers | ||||||
27 | to sons (ref nodes). Flag all_refs means that all possible references | ||||||
28 | are aliasing. | ||||||
29 | |||||||
30 | Because for LTO streaming we need to stream types rather than alias sets | ||||||
31 | modref_base_node is implemented as a template. | ||||||
32 | 2) Ref: this level represent ref alias set and links to accesses unless | ||||||
33 | all_refs flag is set. | ||||||
34 | Again ref is an template to allow LTO streaming. | ||||||
35 | 3) Access: this level represent info about individual accesses. Presently | ||||||
36 | we record whether access is through a dereference of a function parameter | ||||||
37 | */ | ||||||
38 | |||||||
39 | #ifndef GCC_MODREF_TREE_H | ||||||
40 | #define GCC_MODREF_TREE_H | ||||||
41 | |||||||
42 | struct ipa_modref_summary; | ||||||
43 | |||||||
44 | /* Memory access. */ | ||||||
45 | struct GTY(()) modref_access_node | ||||||
46 | { | ||||||
47 | |||||||
48 | /* Access range information (in bits). */ | ||||||
49 | poly_int64 offset; | ||||||
50 | poly_int64 size; | ||||||
51 | poly_int64 max_size; | ||||||
52 | |||||||
53 | /* Offset from parameter pointer to the base of the access (in bytes). */ | ||||||
54 | poly_int64 parm_offset; | ||||||
55 | |||||||
56 | /* Index of parameter which specifies the base of access. -1 if base is not | ||||||
57 | a function parameter. */ | ||||||
58 | int parm_index; | ||||||
59 | bool parm_offset_known; | ||||||
60 | |||||||
61 | /* Return true if access node holds no useful info. */ | ||||||
62 | bool useful_p () const | ||||||
63 | { | ||||||
64 | return parm_index != -1; | ||||||
65 | } | ||||||
66 | /* Return true if range info is useful. */ | ||||||
67 | bool range_info_useful_p () const | ||||||
68 | { | ||||||
69 | return parm_index != -1 && parm_offset_known; | ||||||
70 | } | ||||||
71 | /* Return true if both accesses are the same. */ | ||||||
72 | bool operator == (modref_access_node &a) const | ||||||
73 | { | ||||||
74 | if (parm_index != a.parm_index) | ||||||
75 | return false; | ||||||
76 | if (parm_index >= 0) | ||||||
77 | { | ||||||
78 | if (parm_offset_known != a.parm_offset_known) | ||||||
79 | return false; | ||||||
80 | if (parm_offset_known | ||||||
81 | && !known_eq (parm_offset, a.parm_offset)(!maybe_ne (parm_offset, a.parm_offset))) | ||||||
82 | return false; | ||||||
83 | } | ||||||
84 | if (range_info_useful_p () | ||||||
85 | && (!known_eq (a.offset, offset)(!maybe_ne (a.offset, offset)) | ||||||
86 | || !known_eq (a.size, size)(!maybe_ne (a.size, size)) | ||||||
87 | || !known_eq (a.max_size, max_size)(!maybe_ne (a.max_size, max_size)))) | ||||||
88 | return false; | ||||||
89 | return true; | ||||||
90 | } | ||||||
91 | }; | ||||||
92 | |||||||
93 | /* Access node specifying no useful info. */ | ||||||
94 | const modref_access_node unspecified_modref_access_node | ||||||
95 | = {0, -1, -1, 0, -1, false}; | ||||||
96 | |||||||
97 | template <typename T> | ||||||
98 | struct GTY((user)) modref_ref_node | ||||||
99 | { | ||||||
100 | T ref; | ||||||
101 | bool every_access; | ||||||
102 | vec <modref_access_node, va_gc> *accesses; | ||||||
103 | |||||||
104 | modref_ref_node (T ref): | ||||||
105 | ref (ref), | ||||||
106 | every_access (false), | ||||||
107 | accesses (NULLnullptr) | ||||||
108 | {} | ||||||
109 | |||||||
110 | /* Search REF; return NULL if failed. */ | ||||||
111 | modref_access_node *search (modref_access_node access) | ||||||
112 | { | ||||||
113 | size_t i; | ||||||
114 | modref_access_node *a; | ||||||
115 | FOR_EACH_VEC_SAFE_ELT (accesses, i, a)for (i = 0; vec_safe_iterate ((accesses), (i), &(a)); ++( i)) | ||||||
116 | if (*a == access) | ||||||
117 | return a; | ||||||
118 | return NULLnullptr; | ||||||
119 | } | ||||||
120 | |||||||
121 | /* Collapse the tree. */ | ||||||
122 | void collapse () | ||||||
123 | { | ||||||
124 | vec_free (accesses); | ||||||
125 | accesses = NULLnullptr; | ||||||
126 | every_access = true; | ||||||
127 | } | ||||||
128 | |||||||
129 | /* Insert access with OFFSET and SIZE. | ||||||
130 | Collapse tree if it has more than MAX_ACCESSES entries. | ||||||
131 | Return true if record was changed. */ | ||||||
132 | bool insert_access (modref_access_node a, size_t max_accesses) | ||||||
133 | { | ||||||
134 | /* If this base->ref pair has no access information, bail out. */ | ||||||
135 | if (every_access) | ||||||
136 | return false; | ||||||
137 | |||||||
138 | /* Otherwise, insert a node for the ref of the access under the base. */ | ||||||
139 | modref_access_node *access_node = search (a); | ||||||
140 | if (access_node) | ||||||
141 | return false; | ||||||
142 | |||||||
143 | /* If this base->ref pair has too many accesses stored, we will clear | ||||||
144 | all accesses and bail out. */ | ||||||
145 | if ((accesses && accesses->length () >= max_accesses) | ||||||
146 | || !a.useful_p ()) | ||||||
147 | { | ||||||
148 | if (dump_file && a.useful_p ()) | ||||||
149 | fprintf (dump_file, | ||||||
150 | "--param param=modref-max-accesses limit reached\n"); | ||||||
151 | collapse (); | ||||||
152 | return true; | ||||||
153 | } | ||||||
154 | vec_safe_push (accesses, a); | ||||||
155 | return true; | ||||||
156 | } | ||||||
157 | }; | ||||||
158 | |||||||
159 | /* Base of an access. */ | ||||||
160 | template <typename T> | ||||||
161 | struct GTY((user)) modref_base_node | ||||||
162 | { | ||||||
163 | T base; | ||||||
164 | vec <modref_ref_node <T> *, va_gc> *refs; | ||||||
165 | bool every_ref; | ||||||
166 | |||||||
167 | modref_base_node (T base): | ||||||
168 | base (base), | ||||||
169 | refs (NULLnullptr), | ||||||
170 | every_ref (false) {} | ||||||
171 | |||||||
172 | /* Search REF; return NULL if failed. */ | ||||||
173 | modref_ref_node <T> *search (T ref) | ||||||
174 | { | ||||||
175 | size_t i; | ||||||
176 | modref_ref_node <T> *n; | ||||||
177 | FOR_EACH_VEC_SAFE_ELT (refs, i, n)for (i = 0; vec_safe_iterate ((refs), (i), &(n)); ++(i)) | ||||||
178 | if (n->ref == ref) | ||||||
179 | return n; | ||||||
180 | return NULLnullptr; | ||||||
181 | } | ||||||
182 | |||||||
183 | /* Insert REF; collapse tree if there are more than MAX_REFS. | ||||||
184 | Return inserted ref and if CHANGED is non-null set it to true if | ||||||
185 | something changed. */ | ||||||
186 | modref_ref_node <T> *insert_ref (T ref, size_t max_refs, | ||||||
187 | bool *changed = NULLnullptr) | ||||||
188 | { | ||||||
189 | modref_ref_node <T> *ref_node; | ||||||
190 | |||||||
191 | /* If the node is collapsed, don't do anything. */ | ||||||
192 | if (every_ref) | ||||||
193 | return NULLnullptr; | ||||||
194 | |||||||
195 | /* Otherwise, insert a node for the ref of the access under the base. */ | ||||||
196 | ref_node = search (ref); | ||||||
197 | if (ref_node) | ||||||
198 | return ref_node; | ||||||
199 | |||||||
200 | if (changed) | ||||||
201 | *changed = true; | ||||||
202 | |||||||
203 | /* Collapse the node if too full already. */ | ||||||
204 | if (refs && refs->length () >= max_refs) | ||||||
205 | { | ||||||
206 | if (dump_file) | ||||||
207 | fprintf (dump_file, "--param param=modref-max-refs limit reached\n"); | ||||||
208 | collapse (); | ||||||
209 | return NULLnullptr; | ||||||
210 | } | ||||||
211 | |||||||
212 | ref_node = new (ggc_alloc <modref_ref_node <T> > ())modref_ref_node <T> | ||||||
213 | (ref); | ||||||
214 | vec_safe_push (refs, ref_node); | ||||||
215 | return ref_node; | ||||||
216 | } | ||||||
217 | |||||||
218 | void collapse () | ||||||
219 | { | ||||||
220 | size_t i; | ||||||
221 | modref_ref_node <T> *r; | ||||||
222 | |||||||
223 | if (refs) | ||||||
224 | { | ||||||
225 | FOR_EACH_VEC_SAFE_ELT (refs, i, r)for (i = 0; vec_safe_iterate ((refs), (i), &(r)); ++(i)) | ||||||
226 | { | ||||||
227 | r->collapse (); | ||||||
228 | ggc_free (r); | ||||||
229 | } | ||||||
230 | vec_free (refs); | ||||||
231 | } | ||||||
232 | refs = NULLnullptr; | ||||||
233 | every_ref = true; | ||||||
234 | } | ||||||
235 | }; | ||||||
236 | |||||||
237 | /* Map translating parameters across function call. */ | ||||||
238 | |||||||
239 | struct modref_parm_map | ||||||
240 | { | ||||||
241 | /* Index of parameter we translate to. | ||||||
242 | -1 indicates that parameter is unknown | ||||||
243 | -2 indicates that parameter points to local memory and access can be | ||||||
244 | discarded. */ | ||||||
245 | int parm_index; | ||||||
246 | bool parm_offset_known; | ||||||
247 | poly_int64 parm_offset; | ||||||
248 | }; | ||||||
249 | |||||||
250 | /* Access tree for a single function. */ | ||||||
251 | template <typename T> | ||||||
252 | struct GTY((user)) modref_tree | ||||||
253 | { | ||||||
254 | vec <modref_base_node <T> *, va_gc> *bases; | ||||||
255 | size_t max_bases; | ||||||
256 | size_t max_refs; | ||||||
257 | size_t max_accesses; | ||||||
258 | bool every_base; | ||||||
259 | |||||||
260 | modref_tree (size_t max_bases, size_t max_refs, size_t max_accesses): | ||||||
261 | bases (NULLnullptr), | ||||||
262 | max_bases (max_bases), | ||||||
263 | max_refs (max_refs), | ||||||
264 | max_accesses (max_accesses), | ||||||
265 | every_base (false) {} | ||||||
266 | |||||||
267 | /* Insert BASE; collapse tree if there are more than MAX_REFS. | ||||||
268 | Return inserted base and if CHANGED is non-null set it to true if | ||||||
269 | something changed. */ | ||||||
270 | |||||||
271 | modref_base_node <T> *insert_base (T base, bool *changed = NULLnullptr) | ||||||
272 | { | ||||||
273 | modref_base_node <T> *base_node; | ||||||
274 | |||||||
275 | /* If the node is collapsed, don't do anything. */ | ||||||
276 | if (every_base
| ||||||
277 | return NULLnullptr; | ||||||
278 | |||||||
279 | /* Otherwise, insert a node for the base of the access into the tree. */ | ||||||
280 | base_node = search (base); | ||||||
281 | if (base_node
| ||||||
282 | return base_node; | ||||||
283 | |||||||
284 | if (changed
| ||||||
285 | *changed = true; | ||||||
286 | |||||||
287 | /* Collapse the node if too full already. */ | ||||||
288 | if (bases
| ||||||
289 | { | ||||||
290 | if (dump_file) | ||||||
291 | fprintf (dump_file, "--param param=modref-max-bases limit reached\n"); | ||||||
292 | collapse (); | ||||||
293 | return NULLnullptr; | ||||||
294 | } | ||||||
295 | |||||||
296 | base_node = new (ggc_alloc <modref_base_node <T> > ()) | ||||||
297 | modref_base_node <T> (base); | ||||||
298 | vec_safe_push (bases, base_node); | ||||||
299 | return base_node; | ||||||
300 | } | ||||||
301 | |||||||
302 | /* Insert memory access to the tree. | ||||||
303 | Return true if something changed. */ | ||||||
304 | bool insert (T base, T ref, modref_access_node a) | ||||||
305 | { | ||||||
306 | if (every_base
| ||||||
307 | return false; | ||||||
308 | |||||||
309 | bool changed = false; | ||||||
310 | |||||||
311 | /* No useful information tracked; collapse everything. */ | ||||||
312 | if (!base
| ||||||
313 | { | ||||||
314 | collapse (); | ||||||
315 | return true; | ||||||
316 | } | ||||||
317 | |||||||
318 | modref_base_node <T> *base_node = insert_base (base, &changed); | ||||||
319 | if (!base_node || base_node->every_ref) | ||||||
320 | return changed; | ||||||
321 | gcc_checking_assert (search (base) != NULL)((void)(!(search (base) != nullptr) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.h" , 321, __FUNCTION__), 0 : 0)); | ||||||
322 | |||||||
323 | /* No useful ref info tracked; collapse base. */ | ||||||
324 | if (!ref && !a.useful_p ()) | ||||||
325 | { | ||||||
326 | base_node->collapse (); | ||||||
327 | return true; | ||||||
328 | } | ||||||
329 | |||||||
330 | modref_ref_node <T> *ref_node = base_node->insert_ref (ref, max_refs, | ||||||
331 | &changed); | ||||||
332 | |||||||
333 | /* If we failed to insert ref, just see if there is a cleanup possible. */ | ||||||
334 | if (!ref_node) | ||||||
335 | { | ||||||
336 | /* No useful ref information and no useful base; collapse everything. */ | ||||||
337 | if (!base && base_node->every_ref) | ||||||
338 | { | ||||||
339 | collapse (); | ||||||
340 | gcc_checking_assert (changed)((void)(!(changed) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.h" , 340, __FUNCTION__), 0 : 0)); | ||||||
341 | } | ||||||
342 | else if (changed) | ||||||
343 | cleanup (); | ||||||
344 | } | ||||||
345 | else | ||||||
346 | { | ||||||
347 | if (ref_node->every_access) | ||||||
348 | return changed; | ||||||
349 | changed |= ref_node->insert_access (a, max_accesses); | ||||||
350 | /* See if we failed to add useful access. */ | ||||||
351 | if (ref_node->every_access) | ||||||
352 | { | ||||||
353 | /* Collapse everything if there is no useful base and ref. */ | ||||||
354 | if (!base && !ref) | ||||||
355 | { | ||||||
356 | collapse (); | ||||||
357 | gcc_checking_assert (changed)((void)(!(changed) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.h" , 357, __FUNCTION__), 0 : 0)); | ||||||
358 | } | ||||||
359 | /* Collapse base if there is no useful ref. */ | ||||||
360 | else if (!ref) | ||||||
361 | { | ||||||
362 | base_node->collapse (); | ||||||
363 | gcc_checking_assert (changed)((void)(!(changed) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/ipa-modref-tree.h" , 363, __FUNCTION__), 0 : 0)); | ||||||
364 | } | ||||||
365 | } | ||||||
366 | } | ||||||
367 | return changed; | ||||||
368 | } | ||||||
369 | |||||||
370 | /* Remove tree branches that are not useful (i.e. they will always pass). */ | ||||||
371 | |||||||
372 | void cleanup () | ||||||
373 | { | ||||||
374 | size_t i, j; | ||||||
375 | modref_base_node <T> *base_node; | ||||||
376 | modref_ref_node <T> *ref_node; | ||||||
377 | |||||||
378 | if (!bases) | ||||||
379 | return; | ||||||
380 | |||||||
381 | for (i = 0; vec_safe_iterate (bases, i, &base_node);) | ||||||
382 | { | ||||||
383 | if (base_node->refs) | ||||||
384 | for (j = 0; vec_safe_iterate (base_node->refs, j, &ref_node);) | ||||||
385 | { | ||||||
386 | if (!ref_node->every_access | ||||||
387 | && (!ref_node->accesses | ||||||
388 | || !ref_node->accesses->length ())) | ||||||
389 | { | ||||||
390 | base_node->refs->unordered_remove (j); | ||||||
391 | vec_free (ref_node->accesses); | ||||||
392 | ggc_delete (ref_node); | ||||||
393 | } | ||||||
394 | else | ||||||
395 | j++; | ||||||
396 | } | ||||||
397 | if (!base_node->every_ref | ||||||
398 | && (!base_node->refs || !base_node->refs->length ())) | ||||||
399 | { | ||||||
400 | bases->unordered_remove (i); | ||||||
401 | vec_free (base_node->refs); | ||||||
402 | ggc_delete (base_node); | ||||||
403 | } | ||||||
404 | else | ||||||
405 | i++; | ||||||
406 | } | ||||||
407 | if (bases && !bases->length ()) | ||||||
408 | { | ||||||
409 | vec_free (bases); | ||||||
410 | bases = NULLnullptr; | ||||||
411 | } | ||||||
412 | } | ||||||
413 | |||||||
414 | /* Merge OTHER into the tree. | ||||||
415 | PARM_MAP, if non-NULL, maps parm indexes of callee to caller. -2 is used | ||||||
416 | to signalize that parameter is local and does not need to be tracked. | ||||||
417 | Return true if something has changed. */ | ||||||
418 | bool merge (modref_tree <T> *other, vec <modref_parm_map> *parm_map) | ||||||
419 | { | ||||||
420 | if (!other || every_base) | ||||||
421 | return false; | ||||||
422 | if (other->every_base) | ||||||
423 | { | ||||||
424 | collapse (); | ||||||
425 | return true; | ||||||
426 | } | ||||||
427 | |||||||
428 | bool changed = false; | ||||||
429 | size_t i, j, k; | ||||||
430 | modref_base_node <T> *base_node, *my_base_node; | ||||||
431 | modref_ref_node <T> *ref_node; | ||||||
432 | modref_access_node *access_node; | ||||||
433 | bool release = false; | ||||||
434 | |||||||
435 | /* For self-recursive functions we may end up merging summary into itself; | ||||||
436 | produce copy first so we do not modify summary under our own hands. */ | ||||||
437 | if (other == this) | ||||||
438 | { | ||||||
439 | release = true; | ||||||
440 | other = modref_tree<T>::create_ggc (max_bases, max_refs, max_accesses); | ||||||
441 | other->copy_from (this); | ||||||
442 | } | ||||||
443 | |||||||
444 | FOR_EACH_VEC_SAFE_ELT (other->bases, i, base_node)for (i = 0; vec_safe_iterate ((other->bases), (i), &(base_node )); ++(i)) | ||||||
445 | { | ||||||
446 | if (base_node->every_ref) | ||||||
447 | { | ||||||
448 | my_base_node = insert_base (base_node->base, &changed); | ||||||
449 | if (my_base_node && !my_base_node->every_ref) | ||||||
450 | { | ||||||
451 | my_base_node->collapse (); | ||||||
452 | cleanup (); | ||||||
453 | changed = true; | ||||||
454 | } | ||||||
455 | } | ||||||
456 | else | ||||||
457 | FOR_EACH_VEC_SAFE_ELT (base_node->refs, j, ref_node)for (j = 0; vec_safe_iterate ((base_node->refs), (j), & (ref_node)); ++(j)) | ||||||
458 | { | ||||||
459 | if (ref_node->every_access) | ||||||
460 | { | ||||||
461 | changed |= insert (base_node->base, | ||||||
462 | ref_node->ref, | ||||||
463 | unspecified_modref_access_node); | ||||||
464 | } | ||||||
465 | else | ||||||
466 | FOR_EACH_VEC_SAFE_ELT (ref_node->accesses, k, access_node)for (k = 0; vec_safe_iterate ((ref_node->accesses), (k), & (access_node)); ++(k)) | ||||||
467 | { | ||||||
468 | modref_access_node a = *access_node; | ||||||
469 | |||||||
470 | if (a.parm_index != -1 && parm_map) | ||||||
471 | { | ||||||
472 | if (a.parm_index >= (int)parm_map->length ()) | ||||||
473 | a.parm_index = -1; | ||||||
474 | else if ((*parm_map) [a.parm_index].parm_index == -2) | ||||||
475 | continue; | ||||||
476 | else | ||||||
477 | { | ||||||
478 | a.parm_offset | ||||||
479 | += (*parm_map) [a.parm_index].parm_offset; | ||||||
480 | a.parm_offset_known | ||||||
481 | &= (*parm_map) | ||||||
482 | [a.parm_index].parm_offset_known; | ||||||
483 | a.parm_index | ||||||
484 | = (*parm_map) [a.parm_index].parm_index; | ||||||
485 | } | ||||||
486 | } | ||||||
487 | changed |= insert (base_node->base, ref_node->ref, a); | ||||||
488 | } | ||||||
489 | } | ||||||
490 | } | ||||||
491 | if (release) | ||||||
492 | ggc_delete (other); | ||||||
493 | return changed; | ||||||
494 | } | ||||||
495 | |||||||
496 | /* Copy OTHER to THIS. */ | ||||||
497 | void copy_from (modref_tree <T> *other) | ||||||
498 | { | ||||||
499 | merge (other, NULLnullptr); | ||||||
500 | } | ||||||
501 | |||||||
502 | /* Search BASE in tree; return NULL if failed. */ | ||||||
503 | modref_base_node <T> *search (T base) | ||||||
504 | { | ||||||
505 | size_t i; | ||||||
506 | modref_base_node <T> *n; | ||||||
507 | FOR_EACH_VEC_SAFE_ELT (bases, i, n)for (i = 0; vec_safe_iterate ((bases), (i), &(n)); ++(i)) | ||||||
508 | if (n->base == base) | ||||||
509 | return n; | ||||||
510 | return NULLnullptr; | ||||||
511 | } | ||||||
512 | |||||||
513 | /* Return ggc allocated instance. We explicitly call destructors via | ||||||
514 | ggc_delete and do not want finalizers to be registered and | ||||||
515 | called at the garbage collection time. */ | ||||||
516 | static modref_tree<T> *create_ggc (size_t max_bases, size_t max_refs, | ||||||
517 | size_t max_accesses) | ||||||
518 | { | ||||||
519 | return new (ggc_alloc_no_dtor<modref_tree<T>> ()) | ||||||
520 | modref_tree<T> (max_bases, max_refs, max_accesses); | ||||||
521 | } | ||||||
522 | |||||||
523 | /* Remove all records and mark tree to alias with everything. */ | ||||||
524 | void collapse () | ||||||
525 | { | ||||||
526 | size_t i; | ||||||
527 | modref_base_node <T> *n; | ||||||
528 | |||||||
529 | if (bases) | ||||||
530 | { | ||||||
531 | FOR_EACH_VEC_SAFE_ELT (bases, i, n)for (i = 0; vec_safe_iterate ((bases), (i), &(n)); ++(i)) | ||||||
532 | { | ||||||
533 | n->collapse (); | ||||||
534 | ggc_free (n); | ||||||
535 | } | ||||||
536 | vec_free (bases); | ||||||
537 | } | ||||||
538 | bases = NULLnullptr; | ||||||
539 | every_base = true; | ||||||
540 | } | ||||||
541 | |||||||
542 | /* Release memory. */ | ||||||
543 | ~modref_tree () | ||||||
544 | { | ||||||
545 | collapse (); | ||||||
546 | } | ||||||
547 | |||||||
548 | /* Update parameter indexes in TT according to MAP. */ | ||||||
549 | void | ||||||
550 | remap_params (vec <int> *map) | ||||||
551 | { | ||||||
552 | size_t i; | ||||||
553 | modref_base_node <T> *base_node; | ||||||
554 | FOR_EACH_VEC_SAFE_ELT (bases, i, base_node)for (i = 0; vec_safe_iterate ((bases), (i), &(base_node)) ; ++(i)) | ||||||
555 | { | ||||||
556 | size_t j; | ||||||
557 | modref_ref_node <T> *ref_node; | ||||||
558 | FOR_EACH_VEC_SAFE_ELT (base_node->refs, j, ref_node)for (j = 0; vec_safe_iterate ((base_node->refs), (j), & (ref_node)); ++(j)) | ||||||
559 | { | ||||||
560 | size_t k; | ||||||
561 | modref_access_node *access_node; | ||||||
562 | FOR_EACH_VEC_SAFE_ELT (ref_node->accesses, k, access_node)for (k = 0; vec_safe_iterate ((ref_node->accesses), (k), & (access_node)); ++(k)) | ||||||
563 | if (access_node->parm_index > 0) | ||||||
564 | { | ||||||
565 | if (access_node->parm_index < (int)map->length ()) | ||||||
566 | access_node->parm_index = (*map)[access_node->parm_index]; | ||||||
567 | else | ||||||
568 | access_node->parm_index = -1; | ||||||
569 | } | ||||||
570 | } | ||||||
571 | } | ||||||
572 | } | ||||||
573 | }; | ||||||
574 | |||||||
575 | void modref_c_tests (); | ||||||
576 | |||||||
577 | void gt_ggc_mx (modref_tree <int>* const&); | ||||||
578 | void gt_ggc_mx (modref_tree <tree_node*>* const&); | ||||||
579 | void gt_pch_nx (modref_tree <int>* const&); | ||||||
580 | void gt_pch_nx (modref_tree <tree_node*>* const&); | ||||||
581 | void gt_pch_nx (modref_tree <int>* const&, gt_pointer_operator op, void *cookie); | ||||||
582 | void gt_pch_nx (modref_tree <tree_node*>* const&, gt_pointer_operator op, | ||||||
583 | void *cookie); | ||||||
584 | |||||||
585 | void gt_ggc_mx (modref_base_node <int>*); | ||||||
586 | void gt_ggc_mx (modref_base_node <tree_node*>* &); | ||||||
587 | void gt_pch_nx (modref_base_node <int>* const&); | ||||||
588 | void gt_pch_nx (modref_base_node <tree_node*>* const&); | ||||||
589 | void gt_pch_nx (modref_base_node <int>* const&, gt_pointer_operator op, | ||||||
590 | void *cookie); | ||||||
591 | void gt_pch_nx (modref_base_node <tree_node*>* const&, gt_pointer_operator op, | ||||||
592 | void *cookie); | ||||||
593 | |||||||
594 | void gt_ggc_mx (modref_ref_node <int>*); | ||||||
595 | void gt_ggc_mx (modref_ref_node <tree_node*>* &); | ||||||
596 | void gt_pch_nx (modref_ref_node <int>* const&); | ||||||
597 | void gt_pch_nx (modref_ref_node <tree_node*>* const&); | ||||||
598 | void gt_pch_nx (modref_ref_node <int>* const&, gt_pointer_operator op, | ||||||
599 | void *cookie); | ||||||
600 | void gt_pch_nx (modref_ref_node <tree_node*>* const&, gt_pointer_operator op, | ||||||
601 | void *cookie); | ||||||
602 | |||||||
603 | #endif |
1 | /* Vector API for GNU compiler. | ||||||
2 | Copyright (C) 2004-2021 Free Software Foundation, Inc. | ||||||
3 | Contributed by Nathan Sidwell <nathan@codesourcery.com> | ||||||
4 | Re-implemented in C++ by Diego Novillo <dnovillo@google.com> | ||||||
5 | |||||||
6 | This file is part of GCC. | ||||||
7 | |||||||
8 | GCC is free software; you can redistribute it and/or modify it under | ||||||
9 | the terms of the GNU General Public License as published by the Free | ||||||
10 | Software Foundation; either version 3, or (at your option) any later | ||||||
11 | version. | ||||||
12 | |||||||
13 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY | ||||||
14 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||||
15 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||||||
16 | for more details. | ||||||
17 | |||||||
18 | You should have received a copy of the GNU General Public License | ||||||
19 | along with GCC; see the file COPYING3. If not see | ||||||
20 | <http://www.gnu.org/licenses/>. */ | ||||||
21 | |||||||
22 | #ifndef GCC_VEC_H | ||||||
23 | #define GCC_VEC_H | ||||||
24 | |||||||
25 | /* Some gen* file have no ggc support as the header file gtype-desc.h is | ||||||
26 | missing. Provide these definitions in case ggc.h has not been included. | ||||||
27 | This is not a problem because any code that runs before gengtype is built | ||||||
28 | will never need to use GC vectors.*/ | ||||||
29 | |||||||
30 | extern void ggc_free (void *); | ||||||
31 | extern size_t ggc_round_alloc_size (size_t requested_size); | ||||||
32 | extern void *ggc_realloc (void *, size_t MEM_STAT_DECL); | ||||||
33 | |||||||
34 | /* Templated vector type and associated interfaces. | ||||||
35 | |||||||
36 | The interface functions are typesafe and use inline functions, | ||||||
37 | sometimes backed by out-of-line generic functions. The vectors are | ||||||
38 | designed to interoperate with the GTY machinery. | ||||||
39 | |||||||
40 | There are both 'index' and 'iterate' accessors. The index accessor | ||||||
41 | is implemented by operator[]. The iterator returns a boolean | ||||||
42 | iteration condition and updates the iteration variable passed by | ||||||
43 | reference. Because the iterator will be inlined, the address-of | ||||||
44 | can be optimized away. | ||||||
45 | |||||||
46 | Each operation that increases the number of active elements is | ||||||
47 | available in 'quick' and 'safe' variants. The former presumes that | ||||||
48 | there is sufficient allocated space for the operation to succeed | ||||||
49 | (it dies if there is not). The latter will reallocate the | ||||||
50 | vector, if needed. Reallocation causes an exponential increase in | ||||||
51 | vector size. If you know you will be adding N elements, it would | ||||||
52 | be more efficient to use the reserve operation before adding the | ||||||
53 | elements with the 'quick' operation. This will ensure there are at | ||||||
54 | least as many elements as you ask for, it will exponentially | ||||||
55 | increase if there are too few spare slots. If you want reserve a | ||||||
56 | specific number of slots, but do not want the exponential increase | ||||||
57 | (for instance, you know this is the last allocation), use the | ||||||
58 | reserve_exact operation. You can also create a vector of a | ||||||
59 | specific size from the get go. | ||||||
60 | |||||||
61 | You should prefer the push and pop operations, as they append and | ||||||
62 | remove from the end of the vector. If you need to remove several | ||||||
63 | items in one go, use the truncate operation. The insert and remove | ||||||
64 | operations allow you to change elements in the middle of the | ||||||
65 | vector. There are two remove operations, one which preserves the | ||||||
66 | element ordering 'ordered_remove', and one which does not | ||||||
67 | 'unordered_remove'. The latter function copies the end element | ||||||
68 | into the removed slot, rather than invoke a memmove operation. The | ||||||
69 | 'lower_bound' function will determine where to place an item in the | ||||||
70 | array using insert that will maintain sorted order. | ||||||
71 | |||||||
72 | Vectors are template types with three arguments: the type of the | ||||||
73 | elements in the vector, the allocation strategy, and the physical | ||||||
74 | layout to use | ||||||
75 | |||||||
76 | Four allocation strategies are supported: | ||||||
77 | |||||||
78 | - Heap: allocation is done using malloc/free. This is the | ||||||
79 | default allocation strategy. | ||||||
80 | |||||||
81 | - GC: allocation is done using ggc_alloc/ggc_free. | ||||||
82 | |||||||
83 | - GC atomic: same as GC with the exception that the elements | ||||||
84 | themselves are assumed to be of an atomic type that does | ||||||
85 | not need to be garbage collected. This means that marking | ||||||
86 | routines do not need to traverse the array marking the | ||||||
87 | individual elements. This increases the performance of | ||||||
88 | GC activities. | ||||||
89 | |||||||
90 | Two physical layouts are supported: | ||||||
91 | |||||||
92 | - Embedded: The vector is structured using the trailing array | ||||||
93 | idiom. The last member of the structure is an array of size | ||||||
94 | 1. When the vector is initially allocated, a single memory | ||||||
95 | block is created to hold the vector's control data and the | ||||||
96 | array of elements. These vectors cannot grow without | ||||||
97 | reallocation (see discussion on embeddable vectors below). | ||||||
98 | |||||||
99 | - Space efficient: The vector is structured as a pointer to an | ||||||
100 | embedded vector. This is the default layout. It means that | ||||||
101 | vectors occupy a single word of storage before initial | ||||||
102 | allocation. Vectors are allowed to grow (the internal | ||||||
103 | pointer is reallocated but the main vector instance does not | ||||||
104 | need to relocate). | ||||||
105 | |||||||
106 | The type, allocation and layout are specified when the vector is | ||||||
107 | declared. | ||||||
108 | |||||||
109 | If you need to directly manipulate a vector, then the 'address' | ||||||
110 | accessor will return the address of the start of the vector. Also | ||||||
111 | the 'space' predicate will tell you whether there is spare capacity | ||||||
112 | in the vector. You will not normally need to use these two functions. | ||||||
113 | |||||||
114 | Notes on the different layout strategies | ||||||
115 | |||||||
116 | * Embeddable vectors (vec<T, A, vl_embed>) | ||||||
117 | |||||||
118 | These vectors are suitable to be embedded in other data | ||||||
119 | structures so that they can be pre-allocated in a contiguous | ||||||
120 | memory block. | ||||||
121 | |||||||
122 | Embeddable vectors are implemented using the trailing array | ||||||
123 | idiom, thus they are not resizeable without changing the address | ||||||
124 | of the vector object itself. This means you cannot have | ||||||
125 | variables or fields of embeddable vector type -- always use a | ||||||
126 | pointer to a vector. The one exception is the final field of a | ||||||
127 | structure, which could be a vector type. | ||||||
128 | |||||||
129 | You will have to use the embedded_size & embedded_init calls to | ||||||
130 | create such objects, and they will not be resizeable (so the | ||||||
131 | 'safe' allocation variants are not available). | ||||||
132 | |||||||
133 | Properties of embeddable vectors: | ||||||
134 | |||||||
135 | - The whole vector and control data are allocated in a single | ||||||
136 | contiguous block. It uses the trailing-vector idiom, so | ||||||
137 | allocation must reserve enough space for all the elements | ||||||
138 | in the vector plus its control data. | ||||||
139 | - The vector cannot be re-allocated. | ||||||
140 | - The vector cannot grow nor shrink. | ||||||
141 | - No indirections needed for access/manipulation. | ||||||
142 | - It requires 2 words of storage (prior to vector allocation). | ||||||
143 | |||||||
144 | |||||||
145 | * Space efficient vector (vec<T, A, vl_ptr>) | ||||||
146 | |||||||
147 | These vectors can grow dynamically and are allocated together | ||||||
148 | with their control data. They are suited to be included in data | ||||||
149 | structures. Prior to initial allocation, they only take a single | ||||||
150 | word of storage. | ||||||
151 | |||||||
152 | These vectors are implemented as a pointer to embeddable vectors. | ||||||
153 | The semantics allow for this pointer to be NULL to represent | ||||||
154 | empty vectors. This way, empty vectors occupy minimal space in | ||||||
155 | the structure containing them. | ||||||
156 | |||||||
157 | Properties: | ||||||
158 | |||||||
159 | - The whole vector and control data are allocated in a single | ||||||
160 | contiguous block. | ||||||
161 | - The whole vector may be re-allocated. | ||||||
162 | - Vector data may grow and shrink. | ||||||
163 | - Access and manipulation requires a pointer test and | ||||||
164 | indirection. | ||||||
165 | - It requires 1 word of storage (prior to vector allocation). | ||||||
166 | |||||||
167 | An example of their use would be, | ||||||
168 | |||||||
169 | struct my_struct { | ||||||
170 | // A space-efficient vector of tree pointers in GC memory. | ||||||
171 | vec<tree, va_gc, vl_ptr> v; | ||||||
172 | }; | ||||||
173 | |||||||
174 | struct my_struct *s; | ||||||
175 | |||||||
176 | if (s->v.length ()) { we have some contents } | ||||||
177 | s->v.safe_push (decl); // append some decl onto the end | ||||||
178 | for (ix = 0; s->v.iterate (ix, &elt); ix++) | ||||||
179 | { do something with elt } | ||||||
180 | */ | ||||||
181 | |||||||
182 | /* Support function for statistics. */ | ||||||
183 | extern void dump_vec_loc_statistics (void); | ||||||
184 | |||||||
185 | /* Hashtable mapping vec addresses to descriptors. */ | ||||||
186 | extern htab_t vec_mem_usage_hash; | ||||||
187 | |||||||
188 | /* Control data for vectors. This contains the number of allocated | ||||||
189 | and used slots inside a vector. */ | ||||||
190 | |||||||
191 | struct vec_prefix | ||||||
192 | { | ||||||
193 | /* FIXME - These fields should be private, but we need to cater to | ||||||
194 | compilers that have stricter notions of PODness for types. */ | ||||||
195 | |||||||
196 | /* Memory allocation support routines in vec.c. */ | ||||||
197 | void register_overhead (void *, size_t, size_t CXX_MEM_STAT_INFO); | ||||||
198 | void release_overhead (void *, size_t, size_t, bool CXX_MEM_STAT_INFO); | ||||||
199 | static unsigned calculate_allocation (vec_prefix *, unsigned, bool); | ||||||
200 | static unsigned calculate_allocation_1 (unsigned, unsigned); | ||||||
201 | |||||||
202 | /* Note that vec_prefix should be a base class for vec, but we use | ||||||
203 | offsetof() on vector fields of tree structures (e.g., | ||||||
204 | tree_binfo::base_binfos), and offsetof only supports base types. | ||||||
205 | |||||||
206 | To compensate, we make vec_prefix a field inside vec and make | ||||||
207 | vec a friend class of vec_prefix so it can access its fields. */ | ||||||
208 | template <typename, typename, typename> friend struct vec; | ||||||
209 | |||||||
210 | /* The allocator types also need access to our internals. */ | ||||||
211 | friend struct va_gc; | ||||||
212 | friend struct va_gc_atomic; | ||||||
213 | friend struct va_heap; | ||||||
214 | |||||||
215 | unsigned m_alloc : 31; | ||||||
216 | unsigned m_using_auto_storage : 1; | ||||||
217 | unsigned m_num; | ||||||
218 | }; | ||||||
219 | |||||||
220 | /* Calculate the number of slots to reserve a vector, making sure that | ||||||
221 | RESERVE slots are free. If EXACT grow exactly, otherwise grow | ||||||
222 | exponentially. PFX is the control data for the vector. */ | ||||||
223 | |||||||
224 | inline unsigned | ||||||
225 | vec_prefix::calculate_allocation (vec_prefix *pfx, unsigned reserve, | ||||||
226 | bool exact) | ||||||
227 | { | ||||||
228 | if (exact) | ||||||
229 | return (pfx ? pfx->m_num : 0) + reserve; | ||||||
230 | else if (!pfx) | ||||||
231 | return MAX (4, reserve)((4) > (reserve) ? (4) : (reserve)); | ||||||
232 | return calculate_allocation_1 (pfx->m_alloc, pfx->m_num + reserve); | ||||||
233 | } | ||||||
234 | |||||||
235 | template<typename, typename, typename> struct vec; | ||||||
236 | |||||||
237 | /* Valid vector layouts | ||||||
238 | |||||||
239 | vl_embed - Embeddable vector that uses the trailing array idiom. | ||||||
240 | vl_ptr - Space efficient vector that uses a pointer to an | ||||||
241 | embeddable vector. */ | ||||||
242 | struct vl_embed { }; | ||||||
243 | struct vl_ptr { }; | ||||||
244 | |||||||
245 | |||||||
246 | /* Types of supported allocations | ||||||
247 | |||||||
248 | va_heap - Allocation uses malloc/free. | ||||||
249 | va_gc - Allocation uses ggc_alloc. | ||||||
250 | va_gc_atomic - Same as GC, but individual elements of the array | ||||||
251 | do not need to be marked during collection. */ | ||||||
252 | |||||||
253 | /* Allocator type for heap vectors. */ | ||||||
254 | struct va_heap | ||||||
255 | { | ||||||
256 | /* Heap vectors are frequently regular instances, so use the vl_ptr | ||||||
257 | layout for them. */ | ||||||
258 | typedef vl_ptr default_layout; | ||||||
259 | |||||||
260 | template<typename T> | ||||||
261 | static void reserve (vec<T, va_heap, vl_embed> *&, unsigned, bool | ||||||
262 | CXX_MEM_STAT_INFO); | ||||||
263 | |||||||
264 | template<typename T> | ||||||
265 | static void release (vec<T, va_heap, vl_embed> *&); | ||||||
266 | }; | ||||||
267 | |||||||
268 | |||||||
269 | /* Allocator for heap memory. Ensure there are at least RESERVE free | ||||||
270 | slots in V. If EXACT is true, grow exactly, else grow | ||||||
271 | exponentially. As a special case, if the vector had not been | ||||||
272 | allocated and RESERVE is 0, no vector will be created. */ | ||||||
273 | |||||||
274 | template<typename T> | ||||||
275 | inline void | ||||||
276 | va_heap::reserve (vec<T, va_heap, vl_embed> *&v, unsigned reserve, bool exact | ||||||
277 | MEM_STAT_DECL) | ||||||
278 | { | ||||||
279 | size_t elt_size = sizeof (T); | ||||||
280 | unsigned alloc | ||||||
281 | = vec_prefix::calculate_allocation (v ? &v->m_vecpfx : 0, reserve, exact); | ||||||
282 | gcc_checking_assert (alloc)((void)(!(alloc) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 282, __FUNCTION__), 0 : 0)); | ||||||
283 | |||||||
284 | if (GATHER_STATISTICS0 && v) | ||||||
285 | v->m_vecpfx.release_overhead (v, elt_size * v->allocated (), | ||||||
286 | v->allocated (), false); | ||||||
287 | |||||||
288 | size_t size = vec<T, va_heap, vl_embed>::embedded_size (alloc); | ||||||
289 | unsigned nelem = v ? v->length () : 0; | ||||||
290 | v = static_cast <vec<T, va_heap, vl_embed> *> (xrealloc (v, size)); | ||||||
291 | v->embedded_init (alloc, nelem); | ||||||
292 | |||||||
293 | if (GATHER_STATISTICS0) | ||||||
294 | v->m_vecpfx.register_overhead (v, alloc, elt_size PASS_MEM_STAT); | ||||||
295 | } | ||||||
296 | |||||||
297 | |||||||
298 | #if GCC_VERSION(4 * 1000 + 2) >= 4007 | ||||||
299 | #pragma GCC diagnostic push | ||||||
300 | #pragma GCC diagnostic ignored "-Wfree-nonheap-object" | ||||||
301 | #endif | ||||||
302 | |||||||
303 | /* Free the heap space allocated for vector V. */ | ||||||
304 | |||||||
305 | template<typename T> | ||||||
306 | void | ||||||
307 | va_heap::release (vec<T, va_heap, vl_embed> *&v) | ||||||
308 | { | ||||||
309 | size_t elt_size = sizeof (T); | ||||||
310 | if (v == NULLnullptr) | ||||||
311 | return; | ||||||
312 | |||||||
313 | if (GATHER_STATISTICS0) | ||||||
314 | v->m_vecpfx.release_overhead (v, elt_size * v->allocated (), | ||||||
315 | v->allocated (), true); | ||||||
316 | ::free (v); | ||||||
317 | v = NULLnullptr; | ||||||
318 | } | ||||||
319 | |||||||
320 | #if GCC_VERSION(4 * 1000 + 2) >= 4007 | ||||||
321 | #pragma GCC diagnostic pop | ||||||
322 | #endif | ||||||
323 | |||||||
324 | /* Allocator type for GC vectors. Notice that we need the structure | ||||||
325 | declaration even if GC is not enabled. */ | ||||||
326 | |||||||
327 | struct va_gc | ||||||
328 | { | ||||||
329 | /* Use vl_embed as the default layout for GC vectors. Due to GTY | ||||||
330 | limitations, GC vectors must always be pointers, so it is more | ||||||
331 | efficient to use a pointer to the vl_embed layout, rather than | ||||||
332 | using a pointer to a pointer as would be the case with vl_ptr. */ | ||||||
333 | typedef vl_embed default_layout; | ||||||
334 | |||||||
335 | template<typename T, typename A> | ||||||
336 | static void reserve (vec<T, A, vl_embed> *&, unsigned, bool | ||||||
337 | CXX_MEM_STAT_INFO); | ||||||
338 | |||||||
339 | template<typename T, typename A> | ||||||
340 | static void release (vec<T, A, vl_embed> *&v); | ||||||
341 | }; | ||||||
342 | |||||||
343 | |||||||
344 | /* Free GC memory used by V and reset V to NULL. */ | ||||||
345 | |||||||
346 | template<typename T, typename A> | ||||||
347 | inline void | ||||||
348 | va_gc::release (vec<T, A, vl_embed> *&v) | ||||||
349 | { | ||||||
350 | if (v) | ||||||
351 | ::ggc_free (v); | ||||||
352 | v = NULLnullptr; | ||||||
353 | } | ||||||
354 | |||||||
355 | |||||||
356 | /* Allocator for GC memory. Ensure there are at least RESERVE free | ||||||
357 | slots in V. If EXACT is true, grow exactly, else grow | ||||||
358 | exponentially. As a special case, if the vector had not been | ||||||
359 | allocated and RESERVE is 0, no vector will be created. */ | ||||||
360 | |||||||
361 | template<typename T, typename A> | ||||||
362 | void | ||||||
363 | va_gc::reserve (vec<T, A, vl_embed> *&v, unsigned reserve, bool exact | ||||||
364 | MEM_STAT_DECL) | ||||||
365 | { | ||||||
366 | unsigned alloc | ||||||
367 | = vec_prefix::calculate_allocation (v
| ||||||
368 | if (!alloc) | ||||||
369 | { | ||||||
370 | ::ggc_free (v); | ||||||
371 | v = NULLnullptr; | ||||||
372 | return; | ||||||
373 | } | ||||||
374 | |||||||
375 | /* Calculate the amount of space we want. */ | ||||||
376 | size_t size = vec<T, A, vl_embed>::embedded_size (alloc); | ||||||
377 | |||||||
378 | /* Ask the allocator how much space it will really give us. */ | ||||||
379 | size = ::ggc_round_alloc_size (size); | ||||||
380 | |||||||
381 | /* Adjust the number of slots accordingly. */ | ||||||
382 | size_t vec_offset = sizeof (vec_prefix); | ||||||
383 | size_t elt_size = sizeof (T); | ||||||
384 | alloc = (size - vec_offset) / elt_size; | ||||||
385 | |||||||
386 | /* And finally, recalculate the amount of space we ask for. */ | ||||||
387 | size = vec_offset + alloc * elt_size; | ||||||
388 | |||||||
389 | unsigned nelem = v ? v->length () : 0; | ||||||
390 | v = static_cast <vec<T, A, vl_embed> *> (::ggc_realloc (v, size | ||||||
391 | PASS_MEM_STAT)); | ||||||
392 | v->embedded_init (alloc, nelem); | ||||||
393 | } | ||||||
394 | |||||||
395 | |||||||
396 | /* Allocator type for GC vectors. This is for vectors of types | ||||||
397 | atomics w.r.t. collection, so allocation and deallocation is | ||||||
398 | completely inherited from va_gc. */ | ||||||
399 | struct va_gc_atomic : va_gc | ||||||
400 | { | ||||||
401 | }; | ||||||
402 | |||||||
403 | |||||||
404 | /* Generic vector template. Default values for A and L indicate the | ||||||
405 | most commonly used strategies. | ||||||
406 | |||||||
407 | FIXME - Ideally, they would all be vl_ptr to encourage using regular | ||||||
408 | instances for vectors, but the existing GTY machinery is limited | ||||||
409 | in that it can only deal with GC objects that are pointers | ||||||
410 | themselves. | ||||||
411 | |||||||
412 | This means that vector operations that need to deal with | ||||||
413 | potentially NULL pointers, must be provided as free | ||||||
414 | functions (see the vec_safe_* functions above). */ | ||||||
415 | template<typename T, | ||||||
416 | typename A = va_heap, | ||||||
417 | typename L = typename A::default_layout> | ||||||
418 | struct GTY((user)) vec | ||||||
419 | { | ||||||
420 | }; | ||||||
421 | |||||||
422 | /* Allow C++11 range-based 'for' to work directly on vec<T>*. */ | ||||||
423 | template<typename T, typename A, typename L> | ||||||
424 | T* begin (vec<T,A,L> *v) { return v ? v->begin () : nullptr; } | ||||||
425 | template<typename T, typename A, typename L> | ||||||
426 | T* end (vec<T,A,L> *v) { return v ? v->end () : nullptr; } | ||||||
427 | template<typename T, typename A, typename L> | ||||||
428 | const T* begin (const vec<T,A,L> *v) { return v ? v->begin () : nullptr; } | ||||||
429 | template<typename T, typename A, typename L> | ||||||
430 | const T* end (const vec<T,A,L> *v) { return v ? v->end () : nullptr; } | ||||||
431 | |||||||
432 | /* Generic vec<> debug helpers. | ||||||
433 | |||||||
434 | These need to be instantiated for each vec<TYPE> used throughout | ||||||
435 | the compiler like this: | ||||||
436 | |||||||
437 | DEFINE_DEBUG_VEC (TYPE) | ||||||
438 | |||||||
439 | The reason we have a debug_helper() is because GDB can't | ||||||
440 | disambiguate a plain call to debug(some_vec), and it must be called | ||||||
441 | like debug<TYPE>(some_vec). */ | ||||||
442 | |||||||
443 | template<typename T> | ||||||
444 | void | ||||||
445 | debug_helper (vec<T> &ref) | ||||||
446 | { | ||||||
447 | unsigned i; | ||||||
448 | for (i = 0; i < ref.length (); ++i) | ||||||
449 | { | ||||||
450 | fprintf (stderrstderr, "[%d] = ", i); | ||||||
451 | debug_slim (ref[i]); | ||||||
452 | fputc ('\n', stderrstderr); | ||||||
453 | } | ||||||
454 | } | ||||||
455 | |||||||
456 | /* We need a separate va_gc variant here because default template | ||||||
457 | argument for functions cannot be used in c++-98. Once this | ||||||
458 | restriction is removed, those variant should be folded with the | ||||||
459 | above debug_helper. */ | ||||||
460 | |||||||
461 | template<typename T> | ||||||
462 | void | ||||||
463 | debug_helper (vec<T, va_gc> &ref) | ||||||
464 | { | ||||||
465 | unsigned i; | ||||||
466 | for (i = 0; i < ref.length (); ++i) | ||||||
467 | { | ||||||
468 | fprintf (stderrstderr, "[%d] = ", i); | ||||||
469 | debug_slim (ref[i]); | ||||||
470 | fputc ('\n', stderrstderr); | ||||||
471 | } | ||||||
472 | } | ||||||
473 | |||||||
474 | /* Macro to define debug(vec<T>) and debug(vec<T, va_gc>) helper | ||||||
475 | functions for a type T. */ | ||||||
476 | |||||||
477 | #define DEFINE_DEBUG_VEC(T)template void debug_helper (vec<T> &); template void debug_helper (vec<T, va_gc> &); __attribute__ ((__used__ )) void debug (vec<T> &ref) { debug_helper <T> (ref); } __attribute__ ((__used__)) void debug (vec<T> *ptr) { if (ptr) debug (*ptr); else fprintf (stderr, "<nil>\n" ); } __attribute__ ((__used__)) void debug (vec<T, va_gc> &ref) { debug_helper <T> (ref); } __attribute__ (( __used__)) void debug (vec<T, va_gc> *ptr) { if (ptr) debug (*ptr); else fprintf (stderr, "<nil>\n"); } \ | ||||||
478 | template void debug_helper (vec<T> &); \ | ||||||
479 | template void debug_helper (vec<T, va_gc> &); \ | ||||||
480 | /* Define the vec<T> debug functions. */ \ | ||||||
481 | DEBUG_FUNCTION__attribute__ ((__used__)) void \ | ||||||
482 | debug (vec<T> &ref) \ | ||||||
483 | { \ | ||||||
484 | debug_helper <T> (ref); \ | ||||||
485 | } \ | ||||||
486 | DEBUG_FUNCTION__attribute__ ((__used__)) void \ | ||||||
487 | debug (vec<T> *ptr) \ | ||||||
488 | { \ | ||||||
489 | if (ptr) \ | ||||||
490 | debug (*ptr); \ | ||||||
491 | else \ | ||||||
492 | fprintf (stderrstderr, "<nil>\n"); \ | ||||||
493 | } \ | ||||||
494 | /* Define the vec<T, va_gc> debug functions. */ \ | ||||||
495 | DEBUG_FUNCTION__attribute__ ((__used__)) void \ | ||||||
496 | debug (vec<T, va_gc> &ref) \ | ||||||
497 | { \ | ||||||
498 | debug_helper <T> (ref); \ | ||||||
499 | } \ | ||||||
500 | DEBUG_FUNCTION__attribute__ ((__used__)) void \ | ||||||
501 | debug (vec<T, va_gc> *ptr) \ | ||||||
502 | { \ | ||||||
503 | if (ptr) \ | ||||||
504 | debug (*ptr); \ | ||||||
505 | else \ | ||||||
506 | fprintf (stderrstderr, "<nil>\n"); \ | ||||||
507 | } | ||||||
508 | |||||||
509 | /* Default-construct N elements in DST. */ | ||||||
510 | |||||||
511 | template <typename T> | ||||||
512 | inline void | ||||||
513 | vec_default_construct (T *dst, unsigned n) | ||||||
514 | { | ||||||
515 | #ifdef BROKEN_VALUE_INITIALIZATION | ||||||
516 | /* Versions of GCC before 4.4 sometimes leave certain objects | ||||||
517 | uninitialized when value initialized, though if the type has | ||||||
518 | user defined default ctor, that ctor is invoked. As a workaround | ||||||
519 | perform clearing first and then the value initialization, which | ||||||
520 | fixes the case when value initialization doesn't initialize due to | ||||||
521 | the bugs and should initialize to all zeros, but still allows | ||||||
522 | vectors for types with user defined default ctor that initializes | ||||||
523 | some or all elements to non-zero. If T has no user defined | ||||||
524 | default ctor and some non-static data members have user defined | ||||||
525 | default ctors that initialize to non-zero the workaround will | ||||||
526 | still not work properly; in that case we just need to provide | ||||||
527 | user defined default ctor. */ | ||||||
528 | memset (dst, '\0', sizeof (T) * n); | ||||||
529 | #endif | ||||||
530 | for ( ; n; ++dst, --n) | ||||||
531 | ::new (static_cast<void*>(dst)) T (); | ||||||
532 | } | ||||||
533 | |||||||
534 | /* Copy-construct N elements in DST from *SRC. */ | ||||||
535 | |||||||
536 | template <typename T> | ||||||
537 | inline void | ||||||
538 | vec_copy_construct (T *dst, const T *src, unsigned n) | ||||||
539 | { | ||||||
540 | for ( ; n; ++dst, ++src, --n) | ||||||
541 | ::new (static_cast<void*>(dst)) T (*src); | ||||||
542 | } | ||||||
543 | |||||||
544 | /* Type to provide NULL values for vec<T, A, L>. This is used to | ||||||
545 | provide nil initializers for vec instances. Since vec must be | ||||||
546 | a POD, we cannot have proper ctor/dtor for it. To initialize | ||||||
547 | a vec instance, you can assign it the value vNULL. This isn't | ||||||
548 | needed for file-scope and function-local static vectors, which | ||||||
549 | are zero-initialized by default. */ | ||||||
550 | struct vnull | ||||||
551 | { | ||||||
552 | template <typename T, typename A, typename L> | ||||||
553 | CONSTEXPRconstexpr operator vec<T, A, L> () const { return vec<T, A, L>(); } | ||||||
554 | }; | ||||||
555 | extern vnull vNULL; | ||||||
556 | |||||||
557 | |||||||
558 | /* Embeddable vector. These vectors are suitable to be embedded | ||||||
559 | in other data structures so that they can be pre-allocated in a | ||||||
560 | contiguous memory block. | ||||||
561 | |||||||
562 | Embeddable vectors are implemented using the trailing array idiom, | ||||||
563 | thus they are not resizeable without changing the address of the | ||||||
564 | vector object itself. This means you cannot have variables or | ||||||
565 | fields of embeddable vector type -- always use a pointer to a | ||||||
566 | vector. The one exception is the final field of a structure, which | ||||||
567 | could be a vector type. | ||||||
568 | |||||||
569 | You will have to use the embedded_size & embedded_init calls to | ||||||
570 | create such objects, and they will not be resizeable (so the 'safe' | ||||||
571 | allocation variants are not available). | ||||||
572 | |||||||
573 | Properties: | ||||||
574 | |||||||
575 | - The whole vector and control data are allocated in a single | ||||||
576 | contiguous block. It uses the trailing-vector idiom, so | ||||||
577 | allocation must reserve enough space for all the elements | ||||||
578 | in the vector plus its control data. | ||||||
579 | - The vector cannot be re-allocated. | ||||||
580 | - The vector cannot grow nor shrink. | ||||||
581 | - No indirections needed for access/manipulation. | ||||||
582 | - It requires 2 words of storage (prior to vector allocation). */ | ||||||
583 | |||||||
584 | template<typename T, typename A> | ||||||
585 | struct GTY((user)) vec<T, A, vl_embed> | ||||||
586 | { | ||||||
587 | public: | ||||||
588 | unsigned allocated (void) const { return m_vecpfx.m_alloc; } | ||||||
589 | unsigned length (void) const { return m_vecpfx.m_num; } | ||||||
590 | bool is_empty (void) const { return m_vecpfx.m_num == 0; } | ||||||
591 | T *address (void) { return m_vecdata; } | ||||||
592 | const T *address (void) const { return m_vecdata; } | ||||||
593 | T *begin () { return address (); } | ||||||
594 | const T *begin () const { return address (); } | ||||||
595 | T *end () { return address () + length (); } | ||||||
596 | const T *end () const { return address () + length (); } | ||||||
597 | const T &operator[] (unsigned) const; | ||||||
598 | T &operator[] (unsigned); | ||||||
599 | T &last (void); | ||||||
600 | bool space (unsigned) const; | ||||||
601 | bool iterate (unsigned, T *) const; | ||||||
602 | bool iterate (unsigned, T **) const; | ||||||
603 | vec *copy (ALONE_CXX_MEM_STAT_INFO) const; | ||||||
604 | void splice (const vec &); | ||||||
605 | void splice (const vec *src); | ||||||
606 | T *quick_push (const T &); | ||||||
607 | T &pop (void); | ||||||
608 | void truncate (unsigned); | ||||||
609 | void quick_insert (unsigned, const T &); | ||||||
610 | void ordered_remove (unsigned); | ||||||
611 | void unordered_remove (unsigned); | ||||||
612 | void block_remove (unsigned, unsigned); | ||||||
613 | void qsort (int (*) (const void *, const void *))qsort (int (*) (const void *, const void *)); | ||||||
614 | void sort (int (*) (const void *, const void *, void *), void *); | ||||||
615 | T *bsearch (const void *key, int (*compar)(const void *, const void *)); | ||||||
616 | T *bsearch (const void *key, | ||||||
617 | int (*compar)(const void *, const void *, void *), void *); | ||||||
618 | unsigned lower_bound (T, bool (*)(const T &, const T &)) const; | ||||||
619 | bool contains (const T &search) const; | ||||||
620 | static size_t embedded_size (unsigned); | ||||||
621 | void embedded_init (unsigned, unsigned = 0, unsigned = 0); | ||||||
622 | void quick_grow (unsigned len); | ||||||
623 | void quick_grow_cleared (unsigned len); | ||||||
624 | |||||||
625 | /* vec class can access our internal data and functions. */ | ||||||
626 | template <typename, typename, typename> friend struct vec; | ||||||
627 | |||||||
628 | /* The allocator types also need access to our internals. */ | ||||||
629 | friend struct va_gc; | ||||||
630 | friend struct va_gc_atomic; | ||||||
631 | friend struct va_heap; | ||||||
632 | |||||||
633 | /* FIXME - These fields should be private, but we need to cater to | ||||||
634 | compilers that have stricter notions of PODness for types. */ | ||||||
635 | vec_prefix m_vecpfx; | ||||||
636 | T m_vecdata[1]; | ||||||
637 | }; | ||||||
638 | |||||||
639 | |||||||
640 | /* Convenience wrapper functions to use when dealing with pointers to | ||||||
641 | embedded vectors. Some functionality for these vectors must be | ||||||
642 | provided via free functions for these reasons: | ||||||
643 | |||||||
644 | 1- The pointer may be NULL (e.g., before initial allocation). | ||||||
645 | |||||||
646 | 2- When the vector needs to grow, it must be reallocated, so | ||||||
647 | the pointer will change its value. | ||||||
648 | |||||||
649 | Because of limitations with the current GC machinery, all vectors | ||||||
650 | in GC memory *must* be pointers. */ | ||||||
651 | |||||||
652 | |||||||
653 | /* If V contains no room for NELEMS elements, return false. Otherwise, | ||||||
654 | return true. */ | ||||||
655 | template<typename T, typename A> | ||||||
656 | inline bool | ||||||
657 | vec_safe_space (const vec<T, A, vl_embed> *v, unsigned nelems) | ||||||
658 | { | ||||||
659 | return v ? v->space (nelems) : nelems == 0; | ||||||
660 | } | ||||||
661 | |||||||
662 | |||||||
663 | /* If V is NULL, return 0. Otherwise, return V->length(). */ | ||||||
664 | template<typename T, typename A> | ||||||
665 | inline unsigned | ||||||
666 | vec_safe_length (const vec<T, A, vl_embed> *v) | ||||||
667 | { | ||||||
668 | return v ? v->length () : 0; | ||||||
669 | } | ||||||
670 | |||||||
671 | |||||||
672 | /* If V is NULL, return NULL. Otherwise, return V->address(). */ | ||||||
673 | template<typename T, typename A> | ||||||
674 | inline T * | ||||||
675 | vec_safe_address (vec<T, A, vl_embed> *v) | ||||||
676 | { | ||||||
677 | return v ? v->address () : NULLnullptr; | ||||||
678 | } | ||||||
679 | |||||||
680 | |||||||
681 | /* If V is NULL, return true. Otherwise, return V->is_empty(). */ | ||||||
682 | template<typename T, typename A> | ||||||
683 | inline bool | ||||||
684 | vec_safe_is_empty (vec<T, A, vl_embed> *v) | ||||||
685 | { | ||||||
686 | return v ? v->is_empty () : true; | ||||||
687 | } | ||||||
688 | |||||||
689 | /* If V does not have space for NELEMS elements, call | ||||||
690 | V->reserve(NELEMS, EXACT). */ | ||||||
691 | template<typename T, typename A> | ||||||
692 | inline bool | ||||||
693 | vec_safe_reserve (vec<T, A, vl_embed> *&v, unsigned nelems, bool exact = false | ||||||
694 | CXX_MEM_STAT_INFO) | ||||||
695 | { | ||||||
696 | bool extend = nelems
| ||||||
697 | if (extend
| ||||||
698 | A::reserve (v, nelems, exact PASS_MEM_STAT); | ||||||
699 | return extend; | ||||||
700 | } | ||||||
701 | |||||||
702 | template<typename T, typename A> | ||||||
703 | inline bool | ||||||
704 | vec_safe_reserve_exact (vec<T, A, vl_embed> *&v, unsigned nelems | ||||||
705 | CXX_MEM_STAT_INFO) | ||||||
706 | { | ||||||
707 | return vec_safe_reserve (v, nelems, true PASS_MEM_STAT); | ||||||
708 | } | ||||||
709 | |||||||
710 | |||||||
711 | /* Allocate GC memory for V with space for NELEMS slots. If NELEMS | ||||||
712 | is 0, V is initialized to NULL. */ | ||||||
713 | |||||||
714 | template<typename T, typename A> | ||||||
715 | inline void | ||||||
716 | vec_alloc (vec<T, A, vl_embed> *&v, unsigned nelems CXX_MEM_STAT_INFO) | ||||||
717 | { | ||||||
718 | v = NULLnullptr; | ||||||
719 | vec_safe_reserve (v, nelems, false PASS_MEM_STAT); | ||||||
720 | } | ||||||
721 | |||||||
722 | |||||||
723 | /* Free the GC memory allocated by vector V and set it to NULL. */ | ||||||
724 | |||||||
725 | template<typename T, typename A> | ||||||
726 | inline void | ||||||
727 | vec_free (vec<T, A, vl_embed> *&v) | ||||||
728 | { | ||||||
729 | A::release (v); | ||||||
730 | } | ||||||
731 | |||||||
732 | |||||||
733 | /* Grow V to length LEN. Allocate it, if necessary. */ | ||||||
734 | template<typename T, typename A> | ||||||
735 | inline void | ||||||
736 | vec_safe_grow (vec<T, A, vl_embed> *&v, unsigned len, | ||||||
737 | bool exact = false CXX_MEM_STAT_INFO) | ||||||
738 | { | ||||||
739 | unsigned oldlen = vec_safe_length (v); | ||||||
740 | gcc_checking_assert (len >= oldlen)((void)(!(len >= oldlen) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 740, __FUNCTION__), 0 : 0)); | ||||||
741 | vec_safe_reserve (v, len - oldlen, exact PASS_MEM_STAT); | ||||||
742 | v->quick_grow (len); | ||||||
743 | } | ||||||
744 | |||||||
745 | |||||||
746 | /* If V is NULL, allocate it. Call V->safe_grow_cleared(LEN). */ | ||||||
747 | template<typename T, typename A> | ||||||
748 | inline void | ||||||
749 | vec_safe_grow_cleared (vec<T, A, vl_embed> *&v, unsigned len, | ||||||
750 | bool exact = false CXX_MEM_STAT_INFO) | ||||||
751 | { | ||||||
752 | unsigned oldlen = vec_safe_length (v); | ||||||
753 | vec_safe_grow (v, len, exact PASS_MEM_STAT); | ||||||
754 | vec_default_construct (v->address () + oldlen, len - oldlen); | ||||||
755 | } | ||||||
756 | |||||||
757 | |||||||
758 | /* Assume V is not NULL. */ | ||||||
759 | |||||||
760 | template<typename T> | ||||||
761 | inline void | ||||||
762 | vec_safe_grow_cleared (vec<T, va_heap, vl_ptr> *&v, | ||||||
763 | unsigned len, bool exact = false CXX_MEM_STAT_INFO) | ||||||
764 | { | ||||||
765 | v->safe_grow_cleared (len, exact PASS_MEM_STAT); | ||||||
766 | } | ||||||
767 | |||||||
768 | /* If V does not have space for NELEMS elements, call | ||||||
769 | V->reserve(NELEMS, EXACT). */ | ||||||
770 | |||||||
771 | template<typename T> | ||||||
772 | inline bool | ||||||
773 | vec_safe_reserve (vec<T, va_heap, vl_ptr> *&v, unsigned nelems, bool exact = false | ||||||
774 | CXX_MEM_STAT_INFO) | ||||||
775 | { | ||||||
776 | return v->reserve (nelems, exact); | ||||||
777 | } | ||||||
778 | |||||||
779 | |||||||
780 | /* If V is NULL return false, otherwise return V->iterate(IX, PTR). */ | ||||||
781 | template<typename T, typename A> | ||||||
782 | inline bool | ||||||
783 | vec_safe_iterate (const vec<T, A, vl_embed> *v, unsigned ix, T **ptr) | ||||||
784 | { | ||||||
785 | if (v) | ||||||
786 | return v->iterate (ix, ptr); | ||||||
787 | else | ||||||
788 | { | ||||||
789 | *ptr = 0; | ||||||
790 | return false; | ||||||
791 | } | ||||||
792 | } | ||||||
793 | |||||||
794 | template<typename T, typename A> | ||||||
795 | inline bool | ||||||
796 | vec_safe_iterate (const vec<T, A, vl_embed> *v, unsigned ix, T *ptr) | ||||||
797 | { | ||||||
798 | if (v
| ||||||
799 | return v->iterate (ix, ptr); | ||||||
800 | else | ||||||
801 | { | ||||||
802 | *ptr = 0; | ||||||
803 | return false; | ||||||
804 | } | ||||||
805 | } | ||||||
806 | |||||||
807 | |||||||
808 | /* If V has no room for one more element, reallocate it. Then call | ||||||
809 | V->quick_push(OBJ). */ | ||||||
810 | template<typename T, typename A> | ||||||
811 | inline T * | ||||||
812 | vec_safe_push (vec<T, A, vl_embed> *&v, const T &obj CXX_MEM_STAT_INFO) | ||||||
813 | { | ||||||
814 | vec_safe_reserve (v, 1, false PASS_MEM_STAT); | ||||||
815 | return v->quick_push (obj); | ||||||
| |||||||
816 | } | ||||||
817 | |||||||
818 | |||||||
819 | /* if V has no room for one more element, reallocate it. Then call | ||||||
820 | V->quick_insert(IX, OBJ). */ | ||||||
821 | template<typename T, typename A> | ||||||
822 | inline void | ||||||
823 | vec_safe_insert (vec<T, A, vl_embed> *&v, unsigned ix, const T &obj | ||||||
824 | CXX_MEM_STAT_INFO) | ||||||
825 | { | ||||||
826 | vec_safe_reserve (v, 1, false PASS_MEM_STAT); | ||||||
827 | v->quick_insert (ix, obj); | ||||||
828 | } | ||||||
829 | |||||||
830 | |||||||
831 | /* If V is NULL, do nothing. Otherwise, call V->truncate(SIZE). */ | ||||||
832 | template<typename T, typename A> | ||||||
833 | inline void | ||||||
834 | vec_safe_truncate (vec<T, A, vl_embed> *v, unsigned size) | ||||||
835 | { | ||||||
836 | if (v) | ||||||
837 | v->truncate (size); | ||||||
838 | } | ||||||
839 | |||||||
840 | |||||||
841 | /* If SRC is not NULL, return a pointer to a copy of it. */ | ||||||
842 | template<typename T, typename A> | ||||||
843 | inline vec<T, A, vl_embed> * | ||||||
844 | vec_safe_copy (vec<T, A, vl_embed> *src CXX_MEM_STAT_INFO) | ||||||
845 | { | ||||||
846 | return src ? src->copy (ALONE_PASS_MEM_STAT) : NULLnullptr; | ||||||
847 | } | ||||||
848 | |||||||
849 | /* Copy the elements from SRC to the end of DST as if by memcpy. | ||||||
850 | Reallocate DST, if necessary. */ | ||||||
851 | template<typename T, typename A> | ||||||
852 | inline void | ||||||
853 | vec_safe_splice (vec<T, A, vl_embed> *&dst, const vec<T, A, vl_embed> *src | ||||||
854 | CXX_MEM_STAT_INFO) | ||||||
855 | { | ||||||
856 | unsigned src_len = vec_safe_length (src); | ||||||
857 | if (src_len) | ||||||
858 | { | ||||||
859 | vec_safe_reserve_exact (dst, vec_safe_length (dst) + src_len | ||||||
860 | PASS_MEM_STAT); | ||||||
861 | dst->splice (*src); | ||||||
862 | } | ||||||
863 | } | ||||||
864 | |||||||
865 | /* Return true if SEARCH is an element of V. Note that this is O(N) in the | ||||||
866 | size of the vector and so should be used with care. */ | ||||||
867 | |||||||
868 | template<typename T, typename A> | ||||||
869 | inline bool | ||||||
870 | vec_safe_contains (vec<T, A, vl_embed> *v, const T &search) | ||||||
871 | { | ||||||
872 | return v ? v->contains (search) : false; | ||||||
873 | } | ||||||
874 | |||||||
875 | /* Index into vector. Return the IX'th element. IX must be in the | ||||||
876 | domain of the vector. */ | ||||||
877 | |||||||
878 | template<typename T, typename A> | ||||||
879 | inline const T & | ||||||
880 | vec<T, A, vl_embed>::operator[] (unsigned ix) const | ||||||
881 | { | ||||||
882 | gcc_checking_assert (ix < m_vecpfx.m_num)((void)(!(ix < m_vecpfx.m_num) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 882, __FUNCTION__), 0 : 0)); | ||||||
883 | return m_vecdata[ix]; | ||||||
884 | } | ||||||
885 | |||||||
886 | template<typename T, typename A> | ||||||
887 | inline T & | ||||||
888 | vec<T, A, vl_embed>::operator[] (unsigned ix) | ||||||
889 | { | ||||||
890 | gcc_checking_assert (ix < m_vecpfx.m_num)((void)(!(ix < m_vecpfx.m_num) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 890, __FUNCTION__), 0 : 0)); | ||||||
891 | return m_vecdata[ix]; | ||||||
892 | } | ||||||
893 | |||||||
894 | |||||||
895 | /* Get the final element of the vector, which must not be empty. */ | ||||||
896 | |||||||
897 | template<typename T, typename A> | ||||||
898 | inline T & | ||||||
899 | vec<T, A, vl_embed>::last (void) | ||||||
900 | { | ||||||
901 | gcc_checking_assert (m_vecpfx.m_num > 0)((void)(!(m_vecpfx.m_num > 0) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 901, __FUNCTION__), 0 : 0)); | ||||||
902 | return (*this)[m_vecpfx.m_num - 1]; | ||||||
903 | } | ||||||
904 | |||||||
905 | |||||||
906 | /* If this vector has space for NELEMS additional entries, return | ||||||
907 | true. You usually only need to use this if you are doing your | ||||||
908 | own vector reallocation, for instance on an embedded vector. This | ||||||
909 | returns true in exactly the same circumstances that vec::reserve | ||||||
910 | will. */ | ||||||
911 | |||||||
912 | template<typename T, typename A> | ||||||
913 | inline bool | ||||||
914 | vec<T, A, vl_embed>::space (unsigned nelems) const | ||||||
915 | { | ||||||
916 | return m_vecpfx.m_alloc - m_vecpfx.m_num >= nelems; | ||||||
917 | } | ||||||
918 | |||||||
919 | |||||||
920 | /* Return iteration condition and update PTR to point to the IX'th | ||||||
921 | element of this vector. Use this to iterate over the elements of a | ||||||
922 | vector as follows, | ||||||
923 | |||||||
924 | for (ix = 0; vec<T, A>::iterate (v, ix, &ptr); ix++) | ||||||
925 | continue; */ | ||||||
926 | |||||||
927 | template<typename T, typename A> | ||||||
928 | inline bool | ||||||
929 | vec<T, A, vl_embed>::iterate (unsigned ix, T *ptr) const | ||||||
930 | { | ||||||
931 | if (ix < m_vecpfx.m_num) | ||||||
932 | { | ||||||
933 | *ptr = m_vecdata[ix]; | ||||||
934 | return true; | ||||||
935 | } | ||||||
936 | else | ||||||
937 | { | ||||||
938 | *ptr = 0; | ||||||
939 | return false; | ||||||
940 | } | ||||||
941 | } | ||||||
942 | |||||||
943 | |||||||
944 | /* Return iteration condition and update *PTR to point to the | ||||||
945 | IX'th element of this vector. Use this to iterate over the | ||||||
946 | elements of a vector as follows, | ||||||
947 | |||||||
948 | for (ix = 0; v->iterate (ix, &ptr); ix++) | ||||||
949 | continue; | ||||||
950 | |||||||
951 | This variant is for vectors of objects. */ | ||||||
952 | |||||||
953 | template<typename T, typename A> | ||||||
954 | inline bool | ||||||
955 | vec<T, A, vl_embed>::iterate (unsigned ix, T **ptr) const | ||||||
956 | { | ||||||
957 | if (ix < m_vecpfx.m_num) | ||||||
958 | { | ||||||
959 | *ptr = CONST_CAST (T *, &m_vecdata[ix])(const_cast<T *> ((&m_vecdata[ix]))); | ||||||
960 | return true; | ||||||
961 | } | ||||||
962 | else | ||||||
963 | { | ||||||
964 | *ptr = 0; | ||||||
965 | return false; | ||||||
966 | } | ||||||
967 | } | ||||||
968 | |||||||
969 | |||||||
970 | /* Return a pointer to a copy of this vector. */ | ||||||
971 | |||||||
972 | template<typename T, typename A> | ||||||
973 | inline vec<T, A, vl_embed> * | ||||||
974 | vec<T, A, vl_embed>::copy (ALONE_MEM_STAT_DECLvoid) const | ||||||
975 | { | ||||||
976 | vec<T, A, vl_embed> *new_vec = NULLnullptr; | ||||||
977 | unsigned len = length (); | ||||||
978 | if (len) | ||||||
979 | { | ||||||
980 | vec_alloc (new_vec, len PASS_MEM_STAT); | ||||||
981 | new_vec->embedded_init (len, len); | ||||||
982 | vec_copy_construct (new_vec->address (), m_vecdata, len); | ||||||
983 | } | ||||||
984 | return new_vec; | ||||||
985 | } | ||||||
986 | |||||||
987 | |||||||
988 | /* Copy the elements from SRC to the end of this vector as if by memcpy. | ||||||
989 | The vector must have sufficient headroom available. */ | ||||||
990 | |||||||
991 | template<typename T, typename A> | ||||||
992 | inline void | ||||||
993 | vec<T, A, vl_embed>::splice (const vec<T, A, vl_embed> &src) | ||||||
994 | { | ||||||
995 | unsigned len = src.length (); | ||||||
996 | if (len) | ||||||
997 | { | ||||||
998 | gcc_checking_assert (space (len))((void)(!(space (len)) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 998, __FUNCTION__), 0 : 0)); | ||||||
999 | vec_copy_construct (end (), src.address (), len); | ||||||
1000 | m_vecpfx.m_num += len; | ||||||
1001 | } | ||||||
1002 | } | ||||||
1003 | |||||||
1004 | template<typename T, typename A> | ||||||
1005 | inline void | ||||||
1006 | vec<T, A, vl_embed>::splice (const vec<T, A, vl_embed> *src) | ||||||
1007 | { | ||||||
1008 | if (src) | ||||||
1009 | splice (*src); | ||||||
1010 | } | ||||||
1011 | |||||||
1012 | |||||||
1013 | /* Push OBJ (a new element) onto the end of the vector. There must be | ||||||
1014 | sufficient space in the vector. Return a pointer to the slot | ||||||
1015 | where OBJ was inserted. */ | ||||||
1016 | |||||||
1017 | template<typename T, typename A> | ||||||
1018 | inline T * | ||||||
1019 | vec<T, A, vl_embed>::quick_push (const T &obj) | ||||||
1020 | { | ||||||
1021 | gcc_checking_assert (space (1))((void)(!(space (1)) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1021, __FUNCTION__), 0 : 0)); | ||||||
1022 | T *slot = &m_vecdata[m_vecpfx.m_num++]; | ||||||
1023 | *slot = obj; | ||||||
1024 | return slot; | ||||||
1025 | } | ||||||
1026 | |||||||
1027 | |||||||
1028 | /* Pop and return the last element off the end of the vector. */ | ||||||
1029 | |||||||
1030 | template<typename T, typename A> | ||||||
1031 | inline T & | ||||||
1032 | vec<T, A, vl_embed>::pop (void) | ||||||
1033 | { | ||||||
1034 | gcc_checking_assert (length () > 0)((void)(!(length () > 0) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1034, __FUNCTION__), 0 : 0)); | ||||||
1035 | return m_vecdata[--m_vecpfx.m_num]; | ||||||
1036 | } | ||||||
1037 | |||||||
1038 | |||||||
1039 | /* Set the length of the vector to SIZE. The new length must be less | ||||||
1040 | than or equal to the current length. This is an O(1) operation. */ | ||||||
1041 | |||||||
1042 | template<typename T, typename A> | ||||||
1043 | inline void | ||||||
1044 | vec<T, A, vl_embed>::truncate (unsigned size) | ||||||
1045 | { | ||||||
1046 | gcc_checking_assert (length () >= size)((void)(!(length () >= size) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1046, __FUNCTION__), 0 : 0)); | ||||||
1047 | m_vecpfx.m_num = size; | ||||||
1048 | } | ||||||
1049 | |||||||
1050 | |||||||
1051 | /* Insert an element, OBJ, at the IXth position of this vector. There | ||||||
1052 | must be sufficient space. */ | ||||||
1053 | |||||||
1054 | template<typename T, typename A> | ||||||
1055 | inline void | ||||||
1056 | vec<T, A, vl_embed>::quick_insert (unsigned ix, const T &obj) | ||||||
1057 | { | ||||||
1058 | gcc_checking_assert (length () < allocated ())((void)(!(length () < allocated ()) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1058, __FUNCTION__), 0 : 0)); | ||||||
1059 | gcc_checking_assert (ix <= length ())((void)(!(ix <= length ()) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1059, __FUNCTION__), 0 : 0)); | ||||||
1060 | T *slot = &m_vecdata[ix]; | ||||||
1061 | memmove (slot + 1, slot, (m_vecpfx.m_num++ - ix) * sizeof (T)); | ||||||
1062 | *slot = obj; | ||||||
1063 | } | ||||||
1064 | |||||||
1065 | |||||||
1066 | /* Remove an element from the IXth position of this vector. Ordering of | ||||||
1067 | remaining elements is preserved. This is an O(N) operation due to | ||||||
1068 | memmove. */ | ||||||
1069 | |||||||
1070 | template<typename T, typename A> | ||||||
1071 | inline void | ||||||
1072 | vec<T, A, vl_embed>::ordered_remove (unsigned ix) | ||||||
1073 | { | ||||||
1074 | gcc_checking_assert (ix < length ())((void)(!(ix < length ()) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1074, __FUNCTION__), 0 : 0)); | ||||||
1075 | T *slot = &m_vecdata[ix]; | ||||||
1076 | memmove (slot, slot + 1, (--m_vecpfx.m_num - ix) * sizeof (T)); | ||||||
1077 | } | ||||||
1078 | |||||||
1079 | |||||||
1080 | /* Remove elements in [START, END) from VEC for which COND holds. Ordering of | ||||||
1081 | remaining elements is preserved. This is an O(N) operation. */ | ||||||
1082 | |||||||
1083 | #define VEC_ORDERED_REMOVE_IF_FROM_TO(vec, read_index, write_index, \{ ((void)(!((end) <= (vec).length ()) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1084, __FUNCTION__), 0 : 0)); for (read_index = write_index = (start); read_index < (end); ++read_index) { elem_ptr = &(vec)[read_index]; bool remove_p = (cond); if (remove_p ) continue; if (read_index != write_index) (vec)[write_index] = (vec)[read_index]; write_index++; } if (read_index - write_index > 0) (vec).block_remove (write_index, read_index - write_index ); } | ||||||
1084 | elem_ptr, start, end, cond){ ((void)(!((end) <= (vec).length ()) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1084, __FUNCTION__), 0 : 0)); for (read_index = write_index = (start); read_index < (end); ++read_index) { elem_ptr = &(vec)[read_index]; bool remove_p = (cond); if (remove_p ) continue; if (read_index != write_index) (vec)[write_index] = (vec)[read_index]; write_index++; } if (read_index - write_index > 0) (vec).block_remove (write_index, read_index - write_index ); } \ | ||||||
1085 | { \ | ||||||
1086 | gcc_assert ((end) <= (vec).length ())((void)(!((end) <= (vec).length ()) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1086, __FUNCTION__), 0 : 0)); \ | ||||||
1087 | for (read_index = write_index = (start); read_index < (end); \ | ||||||
1088 | ++read_index) \ | ||||||
1089 | { \ | ||||||
1090 | elem_ptr = &(vec)[read_index]; \ | ||||||
1091 | bool remove_p = (cond); \ | ||||||
1092 | if (remove_p) \ | ||||||
1093 | continue; \ | ||||||
1094 | \ | ||||||
1095 | if (read_index != write_index) \ | ||||||
1096 | (vec)[write_index] = (vec)[read_index]; \ | ||||||
1097 | \ | ||||||
1098 | write_index++; \ | ||||||
1099 | } \ | ||||||
1100 | \ | ||||||
1101 | if (read_index - write_index > 0) \ | ||||||
1102 | (vec).block_remove (write_index, read_index - write_index); \ | ||||||
1103 | } | ||||||
1104 | |||||||
1105 | |||||||
1106 | /* Remove elements from VEC for which COND holds. Ordering of remaining | ||||||
1107 | elements is preserved. This is an O(N) operation. */ | ||||||
1108 | |||||||
1109 | #define VEC_ORDERED_REMOVE_IF(vec, read_index, write_index, elem_ptr, \{ ((void)(!(((vec).length ()) <= ((vec)).length ()) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1110, __FUNCTION__), 0 : 0)); for (read_index = write_index = (0); read_index < ((vec).length ()); ++read_index) { elem_ptr = &((vec))[read_index]; bool remove_p = ((cond)); if (remove_p ) continue; if (read_index != write_index) ((vec))[write_index ] = ((vec))[read_index]; write_index++; } if (read_index - write_index > 0) ((vec)).block_remove (write_index, read_index - write_index ); } | ||||||
1110 | cond){ ((void)(!(((vec).length ()) <= ((vec)).length ()) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1110, __FUNCTION__), 0 : 0)); for (read_index = write_index = (0); read_index < ((vec).length ()); ++read_index) { elem_ptr = &((vec))[read_index]; bool remove_p = ((cond)); if (remove_p ) continue; if (read_index != write_index) ((vec))[write_index ] = ((vec))[read_index]; write_index++; } if (read_index - write_index > 0) ((vec)).block_remove (write_index, read_index - write_index ); } \ | ||||||
1111 | VEC_ORDERED_REMOVE_IF_FROM_TO ((vec), read_index, write_index, \{ ((void)(!(((vec).length ()) <= ((vec)).length ()) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1112, __FUNCTION__), 0 : 0)); for (read_index = write_index = (0); read_index < ((vec).length ()); ++read_index) { elem_ptr = &((vec))[read_index]; bool remove_p = ((cond)); if (remove_p ) continue; if (read_index != write_index) ((vec))[write_index ] = ((vec))[read_index]; write_index++; } if (read_index - write_index > 0) ((vec)).block_remove (write_index, read_index - write_index ); } | ||||||
1112 | elem_ptr, 0, (vec).length (), (cond)){ ((void)(!(((vec).length ()) <= ((vec)).length ()) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1112, __FUNCTION__), 0 : 0)); for (read_index = write_index = (0); read_index < ((vec).length ()); ++read_index) { elem_ptr = &((vec))[read_index]; bool remove_p = ((cond)); if (remove_p ) continue; if (read_index != write_index) ((vec))[write_index ] = ((vec))[read_index]; write_index++; } if (read_index - write_index > 0) ((vec)).block_remove (write_index, read_index - write_index ); } | ||||||
1113 | |||||||
1114 | /* Remove an element from the IXth position of this vector. Ordering of | ||||||
1115 | remaining elements is destroyed. This is an O(1) operation. */ | ||||||
1116 | |||||||
1117 | template<typename T, typename A> | ||||||
1118 | inline void | ||||||
1119 | vec<T, A, vl_embed>::unordered_remove (unsigned ix) | ||||||
1120 | { | ||||||
1121 | gcc_checking_assert (ix < length ())((void)(!(ix < length ()) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1121, __FUNCTION__), 0 : 0)); | ||||||
1122 | m_vecdata[ix] = m_vecdata[--m_vecpfx.m_num]; | ||||||
1123 | } | ||||||
1124 | |||||||
1125 | |||||||
1126 | /* Remove LEN elements starting at the IXth. Ordering is retained. | ||||||
1127 | This is an O(N) operation due to memmove. */ | ||||||
1128 | |||||||
1129 | template<typename T, typename A> | ||||||
1130 | inline void | ||||||
1131 | vec<T, A, vl_embed>::block_remove (unsigned ix, unsigned len) | ||||||
1132 | { | ||||||
1133 | gcc_checking_assert (ix + len <= length ())((void)(!(ix + len <= length ()) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1133, __FUNCTION__), 0 : 0)); | ||||||
1134 | T *slot = &m_vecdata[ix]; | ||||||
1135 | m_vecpfx.m_num -= len; | ||||||
1136 | memmove (slot, slot + len, (m_vecpfx.m_num - ix) * sizeof (T)); | ||||||
1137 | } | ||||||
1138 | |||||||
1139 | |||||||
1140 | /* Sort the contents of this vector with qsort. CMP is the comparison | ||||||
1141 | function to pass to qsort. */ | ||||||
1142 | |||||||
1143 | template<typename T, typename A> | ||||||
1144 | inline void | ||||||
1145 | vec<T, A, vl_embed>::qsort (int (*cmp) (const void *, const void *))qsort (int (*cmp) (const void *, const void *)) | ||||||
1146 | { | ||||||
1147 | if (length () > 1) | ||||||
1148 | gcc_qsort (address (), length (), sizeof (T), cmp); | ||||||
1149 | } | ||||||
1150 | |||||||
1151 | /* Sort the contents of this vector with qsort. CMP is the comparison | ||||||
1152 | function to pass to qsort. */ | ||||||
1153 | |||||||
1154 | template<typename T, typename A> | ||||||
1155 | inline void | ||||||
1156 | vec<T, A, vl_embed>::sort (int (*cmp) (const void *, const void *, void *), | ||||||
1157 | void *data) | ||||||
1158 | { | ||||||
1159 | if (length () > 1) | ||||||
1160 | gcc_sort_r (address (), length (), sizeof (T), cmp, data); | ||||||
1161 | } | ||||||
1162 | |||||||
1163 | |||||||
1164 | /* Search the contents of the sorted vector with a binary search. | ||||||
1165 | CMP is the comparison function to pass to bsearch. */ | ||||||
1166 | |||||||
1167 | template<typename T, typename A> | ||||||
1168 | inline T * | ||||||
1169 | vec<T, A, vl_embed>::bsearch (const void *key, | ||||||
1170 | int (*compar) (const void *, const void *)) | ||||||
1171 | { | ||||||
1172 | const void *base = this->address (); | ||||||
1173 | size_t nmemb = this->length (); | ||||||
1174 | size_t size = sizeof (T); | ||||||
1175 | /* The following is a copy of glibc stdlib-bsearch.h. */ | ||||||
1176 | size_t l, u, idx; | ||||||
1177 | const void *p; | ||||||
1178 | int comparison; | ||||||
1179 | |||||||
1180 | l = 0; | ||||||
1181 | u = nmemb; | ||||||
1182 | while (l < u) | ||||||
1183 | { | ||||||
1184 | idx = (l + u) / 2; | ||||||
1185 | p = (const void *) (((const char *) base) + (idx * size)); | ||||||
1186 | comparison = (*compar) (key, p); | ||||||
1187 | if (comparison < 0) | ||||||
1188 | u = idx; | ||||||
1189 | else if (comparison > 0) | ||||||
1190 | l = idx + 1; | ||||||
1191 | else | ||||||
1192 | return (T *)const_cast<void *>(p); | ||||||
1193 | } | ||||||
1194 | |||||||
1195 | return NULLnullptr; | ||||||
1196 | } | ||||||
1197 | |||||||
1198 | /* Search the contents of the sorted vector with a binary search. | ||||||
1199 | CMP is the comparison function to pass to bsearch. */ | ||||||
1200 | |||||||
1201 | template<typename T, typename A> | ||||||
1202 | inline T * | ||||||
1203 | vec<T, A, vl_embed>::bsearch (const void *key, | ||||||
1204 | int (*compar) (const void *, const void *, | ||||||
1205 | void *), void *data) | ||||||
1206 | { | ||||||
1207 | const void *base = this->address (); | ||||||
1208 | size_t nmemb = this->length (); | ||||||
1209 | size_t size = sizeof (T); | ||||||
1210 | /* The following is a copy of glibc stdlib-bsearch.h. */ | ||||||
1211 | size_t l, u, idx; | ||||||
1212 | const void *p; | ||||||
1213 | int comparison; | ||||||
1214 | |||||||
1215 | l = 0; | ||||||
1216 | u = nmemb; | ||||||
1217 | while (l < u) | ||||||
1218 | { | ||||||
1219 | idx = (l + u) / 2; | ||||||
1220 | p = (const void *) (((const char *) base) + (idx * size)); | ||||||
1221 | comparison = (*compar) (key, p, data); | ||||||
1222 | if (comparison < 0) | ||||||
1223 | u = idx; | ||||||
1224 | else if (comparison > 0) | ||||||
1225 | l = idx + 1; | ||||||
1226 | else | ||||||
1227 | return (T *)const_cast<void *>(p); | ||||||
1228 | } | ||||||
1229 | |||||||
1230 | return NULLnullptr; | ||||||
1231 | } | ||||||
1232 | |||||||
1233 | /* Return true if SEARCH is an element of V. Note that this is O(N) in the | ||||||
1234 | size of the vector and so should be used with care. */ | ||||||
1235 | |||||||
1236 | template<typename T, typename A> | ||||||
1237 | inline bool | ||||||
1238 | vec<T, A, vl_embed>::contains (const T &search) const | ||||||
1239 | { | ||||||
1240 | unsigned int len = length (); | ||||||
1241 | for (unsigned int i = 0; i < len; i++) | ||||||
1242 | if ((*this)[i] == search) | ||||||
1243 | return true; | ||||||
1244 | |||||||
1245 | return false; | ||||||
1246 | } | ||||||
1247 | |||||||
1248 | /* Find and return the first position in which OBJ could be inserted | ||||||
1249 | without changing the ordering of this vector. LESSTHAN is a | ||||||
1250 | function that returns true if the first argument is strictly less | ||||||
1251 | than the second. */ | ||||||
1252 | |||||||
1253 | template<typename T, typename A> | ||||||
1254 | unsigned | ||||||
1255 | vec<T, A, vl_embed>::lower_bound (T obj, bool (*lessthan)(const T &, const T &)) | ||||||
1256 | const | ||||||
1257 | { | ||||||
1258 | unsigned int len = length (); | ||||||
1259 | unsigned int half, middle; | ||||||
1260 | unsigned int first = 0; | ||||||
1261 | while (len > 0) | ||||||
1262 | { | ||||||
1263 | half = len / 2; | ||||||
1264 | middle = first; | ||||||
1265 | middle += half; | ||||||
1266 | T middle_elem = (*this)[middle]; | ||||||
1267 | if (lessthan (middle_elem, obj)) | ||||||
1268 | { | ||||||
1269 | first = middle; | ||||||
1270 | ++first; | ||||||
1271 | len = len - half - 1; | ||||||
1272 | } | ||||||
1273 | else | ||||||
1274 | len = half; | ||||||
1275 | } | ||||||
1276 | return first; | ||||||
1277 | } | ||||||
1278 | |||||||
1279 | |||||||
1280 | /* Return the number of bytes needed to embed an instance of an | ||||||
1281 | embeddable vec inside another data structure. | ||||||
1282 | |||||||
1283 | Use these methods to determine the required size and initialization | ||||||
1284 | of a vector V of type T embedded within another structure (as the | ||||||
1285 | final member): | ||||||
1286 | |||||||
1287 | size_t vec<T, A, vl_embed>::embedded_size (unsigned alloc); | ||||||
1288 | void v->embedded_init (unsigned alloc, unsigned num); | ||||||
1289 | |||||||
1290 | These allow the caller to perform the memory allocation. */ | ||||||
1291 | |||||||
1292 | template<typename T, typename A> | ||||||
1293 | inline size_t | ||||||
1294 | vec<T, A, vl_embed>::embedded_size (unsigned alloc) | ||||||
1295 | { | ||||||
1296 | struct alignas (T) U { char data[sizeof (T)]; }; | ||||||
1297 | typedef vec<U, A, vl_embed> vec_embedded; | ||||||
1298 | typedef typename std::conditional<std::is_standard_layout<T>::value, | ||||||
1299 | vec, vec_embedded>::type vec_stdlayout; | ||||||
1300 | static_assert (sizeof (vec_stdlayout) == sizeof (vec), ""); | ||||||
1301 | static_assert (alignof (vec_stdlayout) == alignof (vec), ""); | ||||||
1302 | return offsetof (vec_stdlayout, m_vecdata)__builtin_offsetof(vec_stdlayout, m_vecdata) + alloc * sizeof (T); | ||||||
1303 | } | ||||||
1304 | |||||||
1305 | |||||||
1306 | /* Initialize the vector to contain room for ALLOC elements and | ||||||
1307 | NUM active elements. */ | ||||||
1308 | |||||||
1309 | template<typename T, typename A> | ||||||
1310 | inline void | ||||||
1311 | vec<T, A, vl_embed>::embedded_init (unsigned alloc, unsigned num, unsigned aut) | ||||||
1312 | { | ||||||
1313 | m_vecpfx.m_alloc = alloc; | ||||||
1314 | m_vecpfx.m_using_auto_storage = aut; | ||||||
1315 | m_vecpfx.m_num = num; | ||||||
1316 | } | ||||||
1317 | |||||||
1318 | |||||||
1319 | /* Grow the vector to a specific length. LEN must be as long or longer than | ||||||
1320 | the current length. The new elements are uninitialized. */ | ||||||
1321 | |||||||
1322 | template<typename T, typename A> | ||||||
1323 | inline void | ||||||
1324 | vec<T, A, vl_embed>::quick_grow (unsigned len) | ||||||
1325 | { | ||||||
1326 | gcc_checking_assert (length () <= len && len <= m_vecpfx.m_alloc)((void)(!(length () <= len && len <= m_vecpfx.m_alloc ) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1326, __FUNCTION__), 0 : 0)); | ||||||
1327 | m_vecpfx.m_num = len; | ||||||
1328 | } | ||||||
1329 | |||||||
1330 | |||||||
1331 | /* Grow the vector to a specific length. LEN must be as long or longer than | ||||||
1332 | the current length. The new elements are initialized to zero. */ | ||||||
1333 | |||||||
1334 | template<typename T, typename A> | ||||||
1335 | inline void | ||||||
1336 | vec<T, A, vl_embed>::quick_grow_cleared (unsigned len) | ||||||
1337 | { | ||||||
1338 | unsigned oldlen = length (); | ||||||
1339 | size_t growby = len - oldlen; | ||||||
1340 | quick_grow (len); | ||||||
1341 | if (growby != 0) | ||||||
1342 | vec_default_construct (address () + oldlen, growby); | ||||||
1343 | } | ||||||
1344 | |||||||
1345 | /* Garbage collection support for vec<T, A, vl_embed>. */ | ||||||
1346 | |||||||
1347 | template<typename T> | ||||||
1348 | void | ||||||
1349 | gt_ggc_mx (vec<T, va_gc> *v) | ||||||
1350 | { | ||||||
1351 | extern void gt_ggc_mx (T &); | ||||||
1352 | for (unsigned i = 0; i < v->length (); i++) | ||||||
1353 | gt_ggc_mx ((*v)[i]); | ||||||
1354 | } | ||||||
1355 | |||||||
1356 | template<typename T> | ||||||
1357 | void | ||||||
1358 | gt_ggc_mx (vec<T, va_gc_atomic, vl_embed> *v ATTRIBUTE_UNUSED__attribute__ ((__unused__))) | ||||||
1359 | { | ||||||
1360 | /* Nothing to do. Vectors of atomic types wrt GC do not need to | ||||||
1361 | be traversed. */ | ||||||
1362 | } | ||||||
1363 | |||||||
1364 | |||||||
1365 | /* PCH support for vec<T, A, vl_embed>. */ | ||||||
1366 | |||||||
1367 | template<typename T, typename A> | ||||||
1368 | void | ||||||
1369 | gt_pch_nx (vec<T, A, vl_embed> *v) | ||||||
1370 | { | ||||||
1371 | extern void gt_pch_nx (T &); | ||||||
1372 | for (unsigned i = 0; i < v->length (); i++) | ||||||
1373 | gt_pch_nx ((*v)[i]); | ||||||
1374 | } | ||||||
1375 | |||||||
1376 | template<typename T, typename A> | ||||||
1377 | void | ||||||
1378 | gt_pch_nx (vec<T *, A, vl_embed> *v, gt_pointer_operator op, void *cookie) | ||||||
1379 | { | ||||||
1380 | for (unsigned i = 0; i < v->length (); i++) | ||||||
1381 | op (&((*v)[i]), cookie); | ||||||
1382 | } | ||||||
1383 | |||||||
1384 | template<typename T, typename A> | ||||||
1385 | void | ||||||
1386 | gt_pch_nx (vec<T, A, vl_embed> *v, gt_pointer_operator op, void *cookie) | ||||||
1387 | { | ||||||
1388 | extern void gt_pch_nx (T *, gt_pointer_operator, void *); | ||||||
1389 | for (unsigned i = 0; i < v->length (); i++) | ||||||
1390 | gt_pch_nx (&((*v)[i]), op, cookie); | ||||||
1391 | } | ||||||
1392 | |||||||
1393 | |||||||
1394 | /* Space efficient vector. These vectors can grow dynamically and are | ||||||
1395 | allocated together with their control data. They are suited to be | ||||||
1396 | included in data structures. Prior to initial allocation, they | ||||||
1397 | only take a single word of storage. | ||||||
1398 | |||||||
1399 | These vectors are implemented as a pointer to an embeddable vector. | ||||||
1400 | The semantics allow for this pointer to be NULL to represent empty | ||||||
1401 | vectors. This way, empty vectors occupy minimal space in the | ||||||
1402 | structure containing them. | ||||||
1403 | |||||||
1404 | Properties: | ||||||
1405 | |||||||
1406 | - The whole vector and control data are allocated in a single | ||||||
1407 | contiguous block. | ||||||
1408 | - The whole vector may be re-allocated. | ||||||
1409 | - Vector data may grow and shrink. | ||||||
1410 | - Access and manipulation requires a pointer test and | ||||||
1411 | indirection. | ||||||
1412 | - It requires 1 word of storage (prior to vector allocation). | ||||||
1413 | |||||||
1414 | |||||||
1415 | Limitations: | ||||||
1416 | |||||||
1417 | These vectors must be PODs because they are stored in unions. | ||||||
1418 | (http://en.wikipedia.org/wiki/Plain_old_data_structures). | ||||||
1419 | As long as we use C++03, we cannot have constructors nor | ||||||
1420 | destructors in classes that are stored in unions. */ | ||||||
1421 | |||||||
1422 | template<typename T> | ||||||
1423 | struct vec<T, va_heap, vl_ptr> | ||||||
1424 | { | ||||||
1425 | public: | ||||||
1426 | /* Memory allocation and deallocation for the embedded vector. | ||||||
1427 | Needed because we cannot have proper ctors/dtors defined. */ | ||||||
1428 | void create (unsigned nelems CXX_MEM_STAT_INFO); | ||||||
1429 | void release (void); | ||||||
1430 | |||||||
1431 | /* Vector operations. */ | ||||||
1432 | bool exists (void) const | ||||||
1433 | { return m_vec != NULLnullptr; } | ||||||
1434 | |||||||
1435 | bool is_empty (void) const | ||||||
1436 | { return m_vec ? m_vec->is_empty () : true; } | ||||||
1437 | |||||||
1438 | unsigned length (void) const | ||||||
1439 | { return m_vec ? m_vec->length () : 0; } | ||||||
1440 | |||||||
1441 | T *address (void) | ||||||
1442 | { return m_vec ? m_vec->m_vecdata : NULLnullptr; } | ||||||
1443 | |||||||
1444 | const T *address (void) const | ||||||
1445 | { return m_vec ? m_vec->m_vecdata : NULLnullptr; } | ||||||
1446 | |||||||
1447 | T *begin () { return address (); } | ||||||
1448 | const T *begin () const { return address (); } | ||||||
1449 | T *end () { return begin () + length (); } | ||||||
1450 | const T *end () const { return begin () + length (); } | ||||||
1451 | const T &operator[] (unsigned ix) const | ||||||
1452 | { return (*m_vec)[ix]; } | ||||||
1453 | |||||||
1454 | bool operator!=(const vec &other) const | ||||||
1455 | { return !(*this == other); } | ||||||
1456 | |||||||
1457 | bool operator==(const vec &other) const | ||||||
1458 | { return address () == other.address (); } | ||||||
1459 | |||||||
1460 | T &operator[] (unsigned ix) | ||||||
1461 | { return (*m_vec)[ix]; } | ||||||
1462 | |||||||
1463 | T &last (void) | ||||||
1464 | { return m_vec->last (); } | ||||||
1465 | |||||||
1466 | bool space (int nelems) const | ||||||
1467 | { return m_vec ? m_vec->space (nelems) : nelems == 0; } | ||||||
1468 | |||||||
1469 | bool iterate (unsigned ix, T *p) const; | ||||||
1470 | bool iterate (unsigned ix, T **p) const; | ||||||
1471 | vec copy (ALONE_CXX_MEM_STAT_INFO) const; | ||||||
1472 | bool reserve (unsigned, bool = false CXX_MEM_STAT_INFO); | ||||||
1473 | bool reserve_exact (unsigned CXX_MEM_STAT_INFO); | ||||||
1474 | void splice (const vec &); | ||||||
1475 | void safe_splice (const vec & CXX_MEM_STAT_INFO); | ||||||
1476 | T *quick_push (const T &); | ||||||
1477 | T *safe_push (const T &CXX_MEM_STAT_INFO); | ||||||
1478 | T &pop (void); | ||||||
1479 | void truncate (unsigned); | ||||||
1480 | void safe_grow (unsigned, bool = false CXX_MEM_STAT_INFO); | ||||||
1481 | void safe_grow_cleared (unsigned, bool = false CXX_MEM_STAT_INFO); | ||||||
1482 | void quick_grow (unsigned); | ||||||
1483 | void quick_grow_cleared (unsigned); | ||||||
1484 | void quick_insert (unsigned, const T &); | ||||||
1485 | void safe_insert (unsigned, const T & CXX_MEM_STAT_INFO); | ||||||
1486 | void ordered_remove (unsigned); | ||||||
1487 | void unordered_remove (unsigned); | ||||||
1488 | void block_remove (unsigned, unsigned); | ||||||
1489 | void qsort (int (*) (const void *, const void *))qsort (int (*) (const void *, const void *)); | ||||||
1490 | void sort (int (*) (const void *, const void *, void *), void *); | ||||||
1491 | T *bsearch (const void *key, int (*compar)(const void *, const void *)); | ||||||
1492 | T *bsearch (const void *key, | ||||||
1493 | int (*compar)(const void *, const void *, void *), void *); | ||||||
1494 | unsigned lower_bound (T, bool (*)(const T &, const T &)) const; | ||||||
1495 | bool contains (const T &search) const; | ||||||
1496 | void reverse (void); | ||||||
1497 | |||||||
1498 | bool using_auto_storage () const; | ||||||
1499 | |||||||
1500 | /* FIXME - This field should be private, but we need to cater to | ||||||
1501 | compilers that have stricter notions of PODness for types. */ | ||||||
1502 | vec<T, va_heap, vl_embed> *m_vec; | ||||||
1503 | }; | ||||||
1504 | |||||||
1505 | |||||||
1506 | /* auto_vec is a subclass of vec that automatically manages creating and | ||||||
1507 | releasing the internal vector. If N is non zero then it has N elements of | ||||||
1508 | internal storage. The default is no internal storage, and you probably only | ||||||
1509 | want to ask for internal storage for vectors on the stack because if the | ||||||
1510 | size of the vector is larger than the internal storage that space is wasted. | ||||||
1511 | */ | ||||||
1512 | template<typename T, size_t N = 0> | ||||||
1513 | class auto_vec : public vec<T, va_heap> | ||||||
1514 | { | ||||||
1515 | public: | ||||||
1516 | auto_vec () | ||||||
1517 | { | ||||||
1518 | m_auto.embedded_init (MAX (N, 2)((N) > (2) ? (N) : (2)), 0, 1); | ||||||
1519 | this->m_vec = &m_auto; | ||||||
1520 | } | ||||||
1521 | |||||||
1522 | auto_vec (size_t s) | ||||||
1523 | { | ||||||
1524 | if (s > N) | ||||||
1525 | { | ||||||
1526 | this->create (s); | ||||||
1527 | return; | ||||||
1528 | } | ||||||
1529 | |||||||
1530 | m_auto.embedded_init (MAX (N, 2)((N) > (2) ? (N) : (2)), 0, 1); | ||||||
1531 | this->m_vec = &m_auto; | ||||||
1532 | } | ||||||
1533 | |||||||
1534 | ~auto_vec () | ||||||
1535 | { | ||||||
1536 | this->release (); | ||||||
1537 | } | ||||||
1538 | |||||||
1539 | private: | ||||||
1540 | vec<T, va_heap, vl_embed> m_auto; | ||||||
1541 | T m_data[MAX (N - 1, 1)((N - 1) > (1) ? (N - 1) : (1))]; | ||||||
1542 | }; | ||||||
1543 | |||||||
1544 | /* auto_vec is a sub class of vec whose storage is released when it is | ||||||
1545 | destroyed. */ | ||||||
1546 | template<typename T> | ||||||
1547 | class auto_vec<T, 0> : public vec<T, va_heap> | ||||||
1548 | { | ||||||
1549 | public: | ||||||
1550 | auto_vec () { this->m_vec = NULLnullptr; } | ||||||
1551 | auto_vec (size_t n) { this->create (n); } | ||||||
1552 | ~auto_vec () { this->release (); } | ||||||
1553 | |||||||
1554 | auto_vec (vec<T, va_heap>&& r) | ||||||
1555 | { | ||||||
1556 | gcc_assert (!r.using_auto_storage ())((void)(!(!r.using_auto_storage ()) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1556, __FUNCTION__), 0 : 0)); | ||||||
1557 | this->m_vec = r.m_vec; | ||||||
1558 | r.m_vec = NULLnullptr; | ||||||
1559 | } | ||||||
1560 | auto_vec& operator= (vec<T, va_heap>&& r) | ||||||
1561 | { | ||||||
1562 | gcc_assert (!r.using_auto_storage ())((void)(!(!r.using_auto_storage ()) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1562, __FUNCTION__), 0 : 0)); | ||||||
1563 | this->release (); | ||||||
1564 | this->m_vec = r.m_vec; | ||||||
1565 | r.m_vec = NULLnullptr; | ||||||
1566 | return *this; | ||||||
1567 | } | ||||||
1568 | }; | ||||||
1569 | |||||||
1570 | |||||||
1571 | /* Allocate heap memory for pointer V and create the internal vector | ||||||
1572 | with space for NELEMS elements. If NELEMS is 0, the internal | ||||||
1573 | vector is initialized to empty. */ | ||||||
1574 | |||||||
1575 | template<typename T> | ||||||
1576 | inline void | ||||||
1577 | vec_alloc (vec<T> *&v, unsigned nelems CXX_MEM_STAT_INFO) | ||||||
1578 | { | ||||||
1579 | v = new vec<T>; | ||||||
1580 | v->create (nelems PASS_MEM_STAT); | ||||||
1581 | } | ||||||
1582 | |||||||
1583 | |||||||
1584 | /* A subclass of auto_vec <char *> that frees all of its elements on | ||||||
1585 | deletion. */ | ||||||
1586 | |||||||
1587 | class auto_string_vec : public auto_vec <char *> | ||||||
1588 | { | ||||||
1589 | public: | ||||||
1590 | ~auto_string_vec (); | ||||||
1591 | }; | ||||||
1592 | |||||||
1593 | /* A subclass of auto_vec <T *> that deletes all of its elements on | ||||||
1594 | destruction. | ||||||
1595 | |||||||
1596 | This is a crude way for a vec to "own" the objects it points to | ||||||
1597 | and clean up automatically. | ||||||
1598 | |||||||
1599 | For example, no attempt is made to delete elements when an item | ||||||
1600 | within the vec is overwritten. | ||||||
1601 | |||||||
1602 | We can't rely on gnu::unique_ptr within a container, | ||||||
1603 | since we can't rely on move semantics in C++98. */ | ||||||
1604 | |||||||
1605 | template <typename T> | ||||||
1606 | class auto_delete_vec : public auto_vec <T *> | ||||||
1607 | { | ||||||
1608 | public: | ||||||
1609 | auto_delete_vec () {} | ||||||
1610 | auto_delete_vec (size_t s) : auto_vec <T *> (s) {} | ||||||
1611 | |||||||
1612 | ~auto_delete_vec (); | ||||||
1613 | |||||||
1614 | private: | ||||||
1615 | DISABLE_COPY_AND_ASSIGN(auto_delete_vec)auto_delete_vec (const auto_delete_vec&) = delete; void operator = (const auto_delete_vec &) = delete; | ||||||
1616 | }; | ||||||
1617 | |||||||
1618 | /* Conditionally allocate heap memory for VEC and its internal vector. */ | ||||||
1619 | |||||||
1620 | template<typename T> | ||||||
1621 | inline void | ||||||
1622 | vec_check_alloc (vec<T, va_heap> *&vec, unsigned nelems CXX_MEM_STAT_INFO) | ||||||
1623 | { | ||||||
1624 | if (!vec) | ||||||
1625 | vec_alloc (vec, nelems PASS_MEM_STAT); | ||||||
1626 | } | ||||||
1627 | |||||||
1628 | |||||||
1629 | /* Free the heap memory allocated by vector V and set it to NULL. */ | ||||||
1630 | |||||||
1631 | template<typename T> | ||||||
1632 | inline void | ||||||
1633 | vec_free (vec<T> *&v) | ||||||
1634 | { | ||||||
1635 | if (v == NULLnullptr) | ||||||
1636 | return; | ||||||
1637 | |||||||
1638 | v->release (); | ||||||
1639 | delete v; | ||||||
1640 | v = NULLnullptr; | ||||||
1641 | } | ||||||
1642 | |||||||
1643 | |||||||
1644 | /* Return iteration condition and update PTR to point to the IX'th | ||||||
1645 | element of this vector. Use this to iterate over the elements of a | ||||||
1646 | vector as follows, | ||||||
1647 | |||||||
1648 | for (ix = 0; v.iterate (ix, &ptr); ix++) | ||||||
1649 | continue; */ | ||||||
1650 | |||||||
1651 | template<typename T> | ||||||
1652 | inline bool | ||||||
1653 | vec<T, va_heap, vl_ptr>::iterate (unsigned ix, T *ptr) const | ||||||
1654 | { | ||||||
1655 | if (m_vec) | ||||||
1656 | return m_vec->iterate (ix, ptr); | ||||||
1657 | else | ||||||
1658 | { | ||||||
1659 | *ptr = 0; | ||||||
1660 | return false; | ||||||
1661 | } | ||||||
1662 | } | ||||||
1663 | |||||||
1664 | |||||||
1665 | /* Return iteration condition and update *PTR to point to the | ||||||
1666 | IX'th element of this vector. Use this to iterate over the | ||||||
1667 | elements of a vector as follows, | ||||||
1668 | |||||||
1669 | for (ix = 0; v->iterate (ix, &ptr); ix++) | ||||||
1670 | continue; | ||||||
1671 | |||||||
1672 | This variant is for vectors of objects. */ | ||||||
1673 | |||||||
1674 | template<typename T> | ||||||
1675 | inline bool | ||||||
1676 | vec<T, va_heap, vl_ptr>::iterate (unsigned ix, T **ptr) const | ||||||
1677 | { | ||||||
1678 | if (m_vec) | ||||||
1679 | return m_vec->iterate (ix, ptr); | ||||||
1680 | else | ||||||
1681 | { | ||||||
1682 | *ptr = 0; | ||||||
1683 | return false; | ||||||
1684 | } | ||||||
1685 | } | ||||||
1686 | |||||||
1687 | |||||||
1688 | /* Convenience macro for forward iteration. */ | ||||||
1689 | #define FOR_EACH_VEC_ELT(V, I, P)for (I = 0; (V).iterate ((I), &(P)); ++(I)) \ | ||||||
1690 | for (I = 0; (V).iterate ((I), &(P)); ++(I)) | ||||||
1691 | |||||||
1692 | #define FOR_EACH_VEC_SAFE_ELT(V, I, P)for (I = 0; vec_safe_iterate ((V), (I), &(P)); ++(I)) \ | ||||||
1693 | for (I = 0; vec_safe_iterate ((V), (I), &(P)); ++(I)) | ||||||
1694 | |||||||
1695 | /* Likewise, but start from FROM rather than 0. */ | ||||||
1696 | #define FOR_EACH_VEC_ELT_FROM(V, I, P, FROM)for (I = (FROM); (V).iterate ((I), &(P)); ++(I)) \ | ||||||
1697 | for (I = (FROM); (V).iterate ((I), &(P)); ++(I)) | ||||||
1698 | |||||||
1699 | /* Convenience macro for reverse iteration. */ | ||||||
1700 | #define FOR_EACH_VEC_ELT_REVERSE(V, I, P)for (I = (V).length () - 1; (V).iterate ((I), &(P)); (I)-- ) \ | ||||||
1701 | for (I = (V).length () - 1; \ | ||||||
1702 | (V).iterate ((I), &(P)); \ | ||||||
1703 | (I)--) | ||||||
1704 | |||||||
1705 | #define FOR_EACH_VEC_SAFE_ELT_REVERSE(V, I, P)for (I = vec_safe_length (V) - 1; vec_safe_iterate ((V), (I), &(P)); (I)--) \ | ||||||
1706 | for (I = vec_safe_length (V) - 1; \ | ||||||
1707 | vec_safe_iterate ((V), (I), &(P)); \ | ||||||
1708 | (I)--) | ||||||
1709 | |||||||
1710 | /* auto_string_vec's dtor, freeing all contained strings, automatically | ||||||
1711 | chaining up to ~auto_vec <char *>, which frees the internal buffer. */ | ||||||
1712 | |||||||
1713 | inline | ||||||
1714 | auto_string_vec::~auto_string_vec () | ||||||
1715 | { | ||||||
1716 | int i; | ||||||
1717 | char *str; | ||||||
1718 | FOR_EACH_VEC_ELT (*this, i, str)for (i = 0; (*this).iterate ((i), &(str)); ++(i)) | ||||||
1719 | free (str); | ||||||
1720 | } | ||||||
1721 | |||||||
1722 | /* auto_delete_vec's dtor, deleting all contained items, automatically | ||||||
1723 | chaining up to ~auto_vec <T*>, which frees the internal buffer. */ | ||||||
1724 | |||||||
1725 | template <typename T> | ||||||
1726 | inline | ||||||
1727 | auto_delete_vec<T>::~auto_delete_vec () | ||||||
1728 | { | ||||||
1729 | int i; | ||||||
1730 | T *item; | ||||||
1731 | FOR_EACH_VEC_ELT (*this, i, item)for (i = 0; (*this).iterate ((i), &(item)); ++(i)) | ||||||
1732 | delete item; | ||||||
1733 | } | ||||||
1734 | |||||||
1735 | |||||||
1736 | /* Return a copy of this vector. */ | ||||||
1737 | |||||||
1738 | template<typename T> | ||||||
1739 | inline vec<T, va_heap, vl_ptr> | ||||||
1740 | vec<T, va_heap, vl_ptr>::copy (ALONE_MEM_STAT_DECLvoid) const | ||||||
1741 | { | ||||||
1742 | vec<T, va_heap, vl_ptr> new_vec = vNULL; | ||||||
1743 | if (length ()) | ||||||
1744 | new_vec.m_vec = m_vec->copy (ALONE_PASS_MEM_STAT); | ||||||
1745 | return new_vec; | ||||||
1746 | } | ||||||
1747 | |||||||
1748 | |||||||
1749 | /* Ensure that the vector has at least RESERVE slots available (if | ||||||
1750 | EXACT is false), or exactly RESERVE slots available (if EXACT is | ||||||
1751 | true). | ||||||
1752 | |||||||
1753 | This may create additional headroom if EXACT is false. | ||||||
1754 | |||||||
1755 | Note that this can cause the embedded vector to be reallocated. | ||||||
1756 | Returns true iff reallocation actually occurred. */ | ||||||
1757 | |||||||
1758 | template<typename T> | ||||||
1759 | inline bool | ||||||
1760 | vec<T, va_heap, vl_ptr>::reserve (unsigned nelems, bool exact MEM_STAT_DECL) | ||||||
1761 | { | ||||||
1762 | if (space (nelems)) | ||||||
1763 | return false; | ||||||
1764 | |||||||
1765 | /* For now play a game with va_heap::reserve to hide our auto storage if any, | ||||||
1766 | this is necessary because it doesn't have enough information to know the | ||||||
1767 | embedded vector is in auto storage, and so should not be freed. */ | ||||||
1768 | vec<T, va_heap, vl_embed> *oldvec = m_vec; | ||||||
1769 | unsigned int oldsize = 0; | ||||||
1770 | bool handle_auto_vec = m_vec && using_auto_storage (); | ||||||
1771 | if (handle_auto_vec) | ||||||
1772 | { | ||||||
1773 | m_vec = NULLnullptr; | ||||||
1774 | oldsize = oldvec->length (); | ||||||
1775 | nelems += oldsize; | ||||||
1776 | } | ||||||
1777 | |||||||
1778 | va_heap::reserve (m_vec, nelems, exact PASS_MEM_STAT); | ||||||
1779 | if (handle_auto_vec) | ||||||
1780 | { | ||||||
1781 | vec_copy_construct (m_vec->address (), oldvec->address (), oldsize); | ||||||
1782 | m_vec->m_vecpfx.m_num = oldsize; | ||||||
1783 | } | ||||||
1784 | |||||||
1785 | return true; | ||||||
1786 | } | ||||||
1787 | |||||||
1788 | |||||||
1789 | /* Ensure that this vector has exactly NELEMS slots available. This | ||||||
1790 | will not create additional headroom. Note this can cause the | ||||||
1791 | embedded vector to be reallocated. Returns true iff reallocation | ||||||
1792 | actually occurred. */ | ||||||
1793 | |||||||
1794 | template<typename T> | ||||||
1795 | inline bool | ||||||
1796 | vec<T, va_heap, vl_ptr>::reserve_exact (unsigned nelems MEM_STAT_DECL) | ||||||
1797 | { | ||||||
1798 | return reserve (nelems, true PASS_MEM_STAT); | ||||||
1799 | } | ||||||
1800 | |||||||
1801 | |||||||
1802 | /* Create the internal vector and reserve NELEMS for it. This is | ||||||
1803 | exactly like vec::reserve, but the internal vector is | ||||||
1804 | unconditionally allocated from scratch. The old one, if it | ||||||
1805 | existed, is lost. */ | ||||||
1806 | |||||||
1807 | template<typename T> | ||||||
1808 | inline void | ||||||
1809 | vec<T, va_heap, vl_ptr>::create (unsigned nelems MEM_STAT_DECL) | ||||||
1810 | { | ||||||
1811 | m_vec = NULLnullptr; | ||||||
1812 | if (nelems > 0) | ||||||
1813 | reserve_exact (nelems PASS_MEM_STAT); | ||||||
1814 | } | ||||||
1815 | |||||||
1816 | |||||||
1817 | /* Free the memory occupied by the embedded vector. */ | ||||||
1818 | |||||||
1819 | template<typename T> | ||||||
1820 | inline void | ||||||
1821 | vec<T, va_heap, vl_ptr>::release (void) | ||||||
1822 | { | ||||||
1823 | if (!m_vec) | ||||||
1824 | return; | ||||||
1825 | |||||||
1826 | if (using_auto_storage ()) | ||||||
1827 | { | ||||||
1828 | m_vec->m_vecpfx.m_num = 0; | ||||||
1829 | return; | ||||||
1830 | } | ||||||
1831 | |||||||
1832 | va_heap::release (m_vec); | ||||||
1833 | } | ||||||
1834 | |||||||
1835 | /* Copy the elements from SRC to the end of this vector as if by memcpy. | ||||||
1836 | SRC and this vector must be allocated with the same memory | ||||||
1837 | allocation mechanism. This vector is assumed to have sufficient | ||||||
1838 | headroom available. */ | ||||||
1839 | |||||||
1840 | template<typename T> | ||||||
1841 | inline void | ||||||
1842 | vec<T, va_heap, vl_ptr>::splice (const vec<T, va_heap, vl_ptr> &src) | ||||||
1843 | { | ||||||
1844 | if (src.length ()) | ||||||
1845 | m_vec->splice (*(src.m_vec)); | ||||||
1846 | } | ||||||
1847 | |||||||
1848 | |||||||
1849 | /* Copy the elements in SRC to the end of this vector as if by memcpy. | ||||||
1850 | SRC and this vector must be allocated with the same mechanism. | ||||||
1851 | If there is not enough headroom in this vector, it will be reallocated | ||||||
1852 | as needed. */ | ||||||
1853 | |||||||
1854 | template<typename T> | ||||||
1855 | inline void | ||||||
1856 | vec<T, va_heap, vl_ptr>::safe_splice (const vec<T, va_heap, vl_ptr> &src | ||||||
1857 | MEM_STAT_DECL) | ||||||
1858 | { | ||||||
1859 | if (src.length ()) | ||||||
1860 | { | ||||||
1861 | reserve_exact (src.length ()); | ||||||
1862 | splice (src); | ||||||
1863 | } | ||||||
1864 | } | ||||||
1865 | |||||||
1866 | |||||||
1867 | /* Push OBJ (a new element) onto the end of the vector. There must be | ||||||
1868 | sufficient space in the vector. Return a pointer to the slot | ||||||
1869 | where OBJ was inserted. */ | ||||||
1870 | |||||||
1871 | template<typename T> | ||||||
1872 | inline T * | ||||||
1873 | vec<T, va_heap, vl_ptr>::quick_push (const T &obj) | ||||||
1874 | { | ||||||
1875 | return m_vec->quick_push (obj); | ||||||
1876 | } | ||||||
1877 | |||||||
1878 | |||||||
1879 | /* Push a new element OBJ onto the end of this vector. Reallocates | ||||||
1880 | the embedded vector, if needed. Return a pointer to the slot where | ||||||
1881 | OBJ was inserted. */ | ||||||
1882 | |||||||
1883 | template<typename T> | ||||||
1884 | inline T * | ||||||
1885 | vec<T, va_heap, vl_ptr>::safe_push (const T &obj MEM_STAT_DECL) | ||||||
1886 | { | ||||||
1887 | reserve (1, false PASS_MEM_STAT); | ||||||
1888 | return quick_push (obj); | ||||||
1889 | } | ||||||
1890 | |||||||
1891 | |||||||
1892 | /* Pop and return the last element off the end of the vector. */ | ||||||
1893 | |||||||
1894 | template<typename T> | ||||||
1895 | inline T & | ||||||
1896 | vec<T, va_heap, vl_ptr>::pop (void) | ||||||
1897 | { | ||||||
1898 | return m_vec->pop (); | ||||||
1899 | } | ||||||
1900 | |||||||
1901 | |||||||
1902 | /* Set the length of the vector to LEN. The new length must be less | ||||||
1903 | than or equal to the current length. This is an O(1) operation. */ | ||||||
1904 | |||||||
1905 | template<typename T> | ||||||
1906 | inline void | ||||||
1907 | vec<T, va_heap, vl_ptr>::truncate (unsigned size) | ||||||
1908 | { | ||||||
1909 | if (m_vec) | ||||||
1910 | m_vec->truncate (size); | ||||||
1911 | else | ||||||
1912 | gcc_checking_assert (size == 0)((void)(!(size == 0) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1912, __FUNCTION__), 0 : 0)); | ||||||
1913 | } | ||||||
1914 | |||||||
1915 | |||||||
1916 | /* Grow the vector to a specific length. LEN must be as long or | ||||||
1917 | longer than the current length. The new elements are | ||||||
1918 | uninitialized. Reallocate the internal vector, if needed. */ | ||||||
1919 | |||||||
1920 | template<typename T> | ||||||
1921 | inline void | ||||||
1922 | vec<T, va_heap, vl_ptr>::safe_grow (unsigned len, bool exact MEM_STAT_DECL) | ||||||
1923 | { | ||||||
1924 | unsigned oldlen = length (); | ||||||
1925 | gcc_checking_assert (oldlen <= len)((void)(!(oldlen <= len) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1925, __FUNCTION__), 0 : 0)); | ||||||
1926 | reserve (len - oldlen, exact PASS_MEM_STAT); | ||||||
1927 | if (m_vec) | ||||||
1928 | m_vec->quick_grow (len); | ||||||
1929 | else | ||||||
1930 | gcc_checking_assert (len == 0)((void)(!(len == 0) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1930, __FUNCTION__), 0 : 0)); | ||||||
1931 | } | ||||||
1932 | |||||||
1933 | |||||||
1934 | /* Grow the embedded vector to a specific length. LEN must be as | ||||||
1935 | long or longer than the current length. The new elements are | ||||||
1936 | initialized to zero. Reallocate the internal vector, if needed. */ | ||||||
1937 | |||||||
1938 | template<typename T> | ||||||
1939 | inline void | ||||||
1940 | vec<T, va_heap, vl_ptr>::safe_grow_cleared (unsigned len, bool exact | ||||||
1941 | MEM_STAT_DECL) | ||||||
1942 | { | ||||||
1943 | unsigned oldlen = length (); | ||||||
1944 | size_t growby = len - oldlen; | ||||||
1945 | safe_grow (len, exact PASS_MEM_STAT); | ||||||
1946 | if (growby != 0) | ||||||
1947 | vec_default_construct (address () + oldlen, growby); | ||||||
1948 | } | ||||||
1949 | |||||||
1950 | |||||||
1951 | /* Same as vec::safe_grow but without reallocation of the internal vector. | ||||||
1952 | If the vector cannot be extended, a runtime assertion will be triggered. */ | ||||||
1953 | |||||||
1954 | template<typename T> | ||||||
1955 | inline void | ||||||
1956 | vec<T, va_heap, vl_ptr>::quick_grow (unsigned len) | ||||||
1957 | { | ||||||
1958 | gcc_checking_assert (m_vec)((void)(!(m_vec) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1958, __FUNCTION__), 0 : 0)); | ||||||
1959 | m_vec->quick_grow (len); | ||||||
1960 | } | ||||||
1961 | |||||||
1962 | |||||||
1963 | /* Same as vec::quick_grow_cleared but without reallocation of the | ||||||
1964 | internal vector. If the vector cannot be extended, a runtime | ||||||
1965 | assertion will be triggered. */ | ||||||
1966 | |||||||
1967 | template<typename T> | ||||||
1968 | inline void | ||||||
1969 | vec<T, va_heap, vl_ptr>::quick_grow_cleared (unsigned len) | ||||||
1970 | { | ||||||
1971 | gcc_checking_assert (m_vec)((void)(!(m_vec) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1971, __FUNCTION__), 0 : 0)); | ||||||
1972 | m_vec->quick_grow_cleared (len); | ||||||
1973 | } | ||||||
1974 | |||||||
1975 | |||||||
1976 | /* Insert an element, OBJ, at the IXth position of this vector. There | ||||||
1977 | must be sufficient space. */ | ||||||
1978 | |||||||
1979 | template<typename T> | ||||||
1980 | inline void | ||||||
1981 | vec<T, va_heap, vl_ptr>::quick_insert (unsigned ix, const T &obj) | ||||||
1982 | { | ||||||
1983 | m_vec->quick_insert (ix, obj); | ||||||
1984 | } | ||||||
1985 | |||||||
1986 | |||||||
1987 | /* Insert an element, OBJ, at the IXth position of the vector. | ||||||
1988 | Reallocate the embedded vector, if necessary. */ | ||||||
1989 | |||||||
1990 | template<typename T> | ||||||
1991 | inline void | ||||||
1992 | vec<T, va_heap, vl_ptr>::safe_insert (unsigned ix, const T &obj MEM_STAT_DECL) | ||||||
1993 | { | ||||||
1994 | reserve (1, false PASS_MEM_STAT); | ||||||
1995 | quick_insert (ix, obj); | ||||||
1996 | } | ||||||
1997 | |||||||
1998 | |||||||
1999 | /* Remove an element from the IXth position of this vector. Ordering of | ||||||
2000 | remaining elements is preserved. This is an O(N) operation due to | ||||||
2001 | a memmove. */ | ||||||
2002 | |||||||
2003 | template<typename T> | ||||||
2004 | inline void | ||||||
2005 | vec<T, va_heap, vl_ptr>::ordered_remove (unsigned ix) | ||||||
2006 | { | ||||||
2007 | m_vec->ordered_remove (ix); | ||||||
2008 | } | ||||||
2009 | |||||||
2010 | |||||||
2011 | /* Remove an element from the IXth position of this vector. Ordering | ||||||
2012 | of remaining elements is destroyed. This is an O(1) operation. */ | ||||||
2013 | |||||||
2014 | template<typename T> | ||||||
2015 | inline void | ||||||
2016 | vec<T, va_heap, vl_ptr>::unordered_remove (unsigned ix) | ||||||
2017 | { | ||||||
2018 | m_vec->unordered_remove (ix); | ||||||
2019 | } | ||||||
2020 | |||||||
2021 | |||||||
2022 | /* Remove LEN elements starting at the IXth. Ordering is retained. | ||||||
2023 | This is an O(N) operation due to memmove. */ | ||||||
2024 | |||||||
2025 | template<typename T> | ||||||
2026 | inline void | ||||||
2027 | vec<T, va_heap, vl_ptr>::block_remove (unsigned ix, unsigned len) | ||||||
2028 | { | ||||||
2029 | m_vec->block_remove (ix, len); | ||||||
2030 | } | ||||||
2031 | |||||||
2032 | |||||||
2033 | /* Sort the contents of this vector with qsort. CMP is the comparison | ||||||
2034 | function to pass to qsort. */ | ||||||
2035 | |||||||
2036 | template<typename T> | ||||||
2037 | inline void | ||||||
2038 | vec<T, va_heap, vl_ptr>::qsort (int (*cmp) (const void *, const void *))qsort (int (*cmp) (const void *, const void *)) | ||||||
2039 | { | ||||||
2040 | if (m_vec) | ||||||
2041 | m_vec->qsort (cmp)qsort (cmp); | ||||||
2042 | } | ||||||
2043 | |||||||
2044 | /* Sort the contents of this vector with qsort. CMP is the comparison | ||||||
2045 | function to pass to qsort. */ | ||||||
2046 | |||||||
2047 | template<typename T> | ||||||
2048 | inline void | ||||||
2049 | vec<T, va_heap, vl_ptr>::sort (int (*cmp) (const void *, const void *, | ||||||
2050 | void *), void *data) | ||||||
2051 | { | ||||||
2052 | if (m_vec) | ||||||
2053 | m_vec->sort (cmp, data); | ||||||
2054 | } | ||||||
2055 | |||||||
2056 | |||||||
2057 | /* Search the contents of the sorted vector with a binary search. | ||||||
2058 | CMP is the comparison function to pass to bsearch. */ | ||||||
2059 | |||||||
2060 | template<typename T> | ||||||
2061 | inline T * | ||||||
2062 | vec<T, va_heap, vl_ptr>::bsearch (const void *key, | ||||||
2063 | int (*cmp) (const void *, const void *)) | ||||||
2064 | { | ||||||
2065 | if (m_vec) | ||||||
2066 | return m_vec->bsearch (key, cmp); | ||||||
2067 | return NULLnullptr; | ||||||
2068 | } | ||||||
2069 | |||||||
2070 | /* Search the contents of the sorted vector with a binary search. | ||||||
2071 | CMP is the comparison function to pass to bsearch. */ | ||||||
2072 | |||||||
2073 | template<typename T> | ||||||
2074 | inline T * | ||||||
2075 | vec<T, va_heap, vl_ptr>::bsearch (const void *key, | ||||||
2076 | int (*cmp) (const void *, const void *, | ||||||
2077 | void *), void *data) | ||||||
2078 | { | ||||||
2079 | if (m_vec) | ||||||
2080 | return m_vec->bsearch (key, cmp, data); | ||||||
2081 | return NULLnullptr; | ||||||
2082 | } | ||||||
2083 | |||||||
2084 | |||||||
2085 | /* Find and return the first position in which OBJ could be inserted | ||||||
2086 | without changing the ordering of this vector. LESSTHAN is a | ||||||
2087 | function that returns true if the first argument is strictly less | ||||||
2088 | than the second. */ | ||||||
2089 | |||||||
2090 | template<typename T> | ||||||
2091 | inline unsigned | ||||||
2092 | vec<T, va_heap, vl_ptr>::lower_bound (T obj, | ||||||
2093 | bool (*lessthan)(const T &, const T &)) | ||||||
2094 | const | ||||||
2095 | { | ||||||
2096 | return m_vec ? m_vec->lower_bound (obj, lessthan) : 0; | ||||||
2097 | } | ||||||
2098 | |||||||
2099 | /* Return true if SEARCH is an element of V. Note that this is O(N) in the | ||||||
2100 | size of the vector and so should be used with care. */ | ||||||
2101 | |||||||
2102 | template<typename T> | ||||||
2103 | inline bool | ||||||
2104 | vec<T, va_heap, vl_ptr>::contains (const T &search) const | ||||||
2105 | { | ||||||
2106 | return m_vec ? m_vec->contains (search) : false; | ||||||
2107 | } | ||||||
2108 | |||||||
2109 | /* Reverse content of the vector. */ | ||||||
2110 | |||||||
2111 | template<typename T> | ||||||
2112 | inline void | ||||||
2113 | vec<T, va_heap, vl_ptr>::reverse (void) | ||||||
2114 | { | ||||||
2115 | unsigned l = length (); | ||||||
2116 | T *ptr = address (); | ||||||
2117 | |||||||
2118 | for (unsigned i = 0; i < l / 2; i++) | ||||||
2119 | std::swap (ptr[i], ptr[l - i - 1]); | ||||||
2120 | } | ||||||
2121 | |||||||
2122 | template<typename T> | ||||||
2123 | inline bool | ||||||
2124 | vec<T, va_heap, vl_ptr>::using_auto_storage () const | ||||||
2125 | { | ||||||
2126 | return m_vec->m_vecpfx.m_using_auto_storage; | ||||||
2127 | } | ||||||
2128 | |||||||
2129 | /* Release VEC and call release of all element vectors. */ | ||||||
2130 | |||||||
2131 | template<typename T> | ||||||
2132 | inline void | ||||||
2133 | release_vec_vec (vec<vec<T> > &vec) | ||||||
2134 | { | ||||||
2135 | for (unsigned i = 0; i < vec.length (); i++) | ||||||
2136 | vec[i].release (); | ||||||
2137 | |||||||
2138 | vec.release (); | ||||||
2139 | } | ||||||
2140 | |||||||
2141 | // Provide a subset of the std::span functionality. (We can't use std::span | ||||||
2142 | // itself because it's a C++20 feature.) | ||||||
2143 | // | ||||||
2144 | // In addition, provide an invalid value that is distinct from all valid | ||||||
2145 | // sequences (including the empty sequence). This can be used to return | ||||||
2146 | // failure without having to use std::optional. | ||||||
2147 | // | ||||||
2148 | // There is no operator bool because it would be ambiguous whether it is | ||||||
2149 | // testing for a valid value or an empty sequence. | ||||||
2150 | template<typename T> | ||||||
2151 | class array_slice | ||||||
2152 | { | ||||||
2153 | template<typename OtherT> friend class array_slice; | ||||||
2154 | |||||||
2155 | public: | ||||||
2156 | using value_type = T; | ||||||
2157 | using iterator = T *; | ||||||
2158 | using const_iterator = const T *; | ||||||
2159 | |||||||
2160 | array_slice () : m_base (nullptr), m_size (0) {} | ||||||
2161 | |||||||
2162 | template<typename OtherT> | ||||||
2163 | array_slice (array_slice<OtherT> other) | ||||||
2164 | : m_base (other.m_base), m_size (other.m_size) {} | ||||||
2165 | |||||||
2166 | array_slice (iterator base, unsigned int size) | ||||||
2167 | : m_base (base), m_size (size) {} | ||||||
2168 | |||||||
2169 | template<size_t N> | ||||||
2170 | array_slice (T (&array)[N]) : m_base (array), m_size (N) {} | ||||||
2171 | |||||||
2172 | template<typename OtherT> | ||||||
2173 | array_slice (const vec<OtherT> &v) | ||||||
2174 | : m_base (v.address ()), m_size (v.length ()) {} | ||||||
2175 | |||||||
2176 | iterator begin () { return m_base; } | ||||||
2177 | iterator end () { return m_base + m_size; } | ||||||
2178 | |||||||
2179 | const_iterator begin () const { return m_base; } | ||||||
2180 | const_iterator end () const { return m_base + m_size; } | ||||||
2181 | |||||||
2182 | value_type &front (); | ||||||
2183 | value_type &back (); | ||||||
2184 | value_type &operator[] (unsigned int i); | ||||||
2185 | |||||||
2186 | const value_type &front () const; | ||||||
2187 | const value_type &back () const; | ||||||
2188 | const value_type &operator[] (unsigned int i) const; | ||||||
2189 | |||||||
2190 | size_t size () const { return m_size; } | ||||||
2191 | size_t size_bytes () const { return m_size * sizeof (T); } | ||||||
2192 | bool empty () const { return m_size == 0; } | ||||||
2193 | |||||||
2194 | // An invalid array_slice that represents a failed operation. This is | ||||||
2195 | // distinct from an empty slice, which is a valid result in some contexts. | ||||||
2196 | static array_slice invalid () { return { nullptr, ~0U }; } | ||||||
2197 | |||||||
2198 | // True if the array is valid, false if it is an array like INVALID. | ||||||
2199 | bool is_valid () const { return m_base || m_size == 0; } | ||||||
2200 | |||||||
2201 | private: | ||||||
2202 | iterator m_base; | ||||||
2203 | unsigned int m_size; | ||||||
2204 | }; | ||||||
2205 | |||||||
2206 | template<typename T> | ||||||
2207 | inline typename array_slice<T>::value_type & | ||||||
2208 | array_slice<T>::front () | ||||||
2209 | { | ||||||
2210 | gcc_checking_assert (m_size)((void)(!(m_size) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 2210, __FUNCTION__), 0 : 0)); | ||||||
2211 | return m_base[0]; | ||||||
2212 | } | ||||||
2213 | |||||||
2214 | template<typename T> | ||||||
2215 | inline const typename array_slice<T>::value_type & | ||||||
2216 | array_slice<T>::front () const | ||||||
2217 | { | ||||||
2218 | gcc_checking_assert (m_size)((void)(!(m_size) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 2218, __FUNCTION__), 0 : 0)); | ||||||
2219 | return m_base[0]; | ||||||
2220 | } | ||||||
2221 | |||||||
2222 | template<typename T> | ||||||
2223 | inline typename array_slice<T>::value_type & | ||||||
2224 | array_slice<T>::back () | ||||||
2225 | { | ||||||
2226 | gcc_checking_assert (m_size)((void)(!(m_size) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 2226, __FUNCTION__), 0 : 0)); | ||||||
2227 | return m_base[m_size - 1]; | ||||||
2228 | } | ||||||
2229 | |||||||
2230 | template<typename T> | ||||||
2231 | inline const typename array_slice<T>::value_type & | ||||||
2232 | array_slice<T>::back () const | ||||||
2233 | { | ||||||
2234 | gcc_checking_assert (m_size)((void)(!(m_size) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 2234, __FUNCTION__), 0 : 0)); | ||||||
2235 | return m_base[m_size - 1]; | ||||||
2236 | } | ||||||
2237 | |||||||
2238 | template<typename T> | ||||||
2239 | inline typename array_slice<T>::value_type & | ||||||
2240 | array_slice<T>::operator[] (unsigned int i) | ||||||
2241 | { | ||||||
2242 | gcc_checking_assert (i < m_size)((void)(!(i < m_size) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 2242, __FUNCTION__), 0 : 0)); | ||||||
2243 | return m_base[i]; | ||||||
2244 | } | ||||||
2245 | |||||||
2246 | template<typename T> | ||||||
2247 | inline const typename array_slice<T>::value_type & | ||||||
2248 | array_slice<T>::operator[] (unsigned int i) const | ||||||
2249 | { | ||||||
2250 | gcc_checking_assert (i < m_size)((void)(!(i < m_size) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 2250, __FUNCTION__), 0 : 0)); | ||||||
2251 | return m_base[i]; | ||||||
2252 | } | ||||||
2253 | |||||||
2254 | template<typename T> | ||||||
2255 | array_slice<T> | ||||||
2256 | make_array_slice (T *base, unsigned int size) | ||||||
2257 | { | ||||||
2258 | return array_slice<T> (base, size); | ||||||
2259 | } | ||||||
2260 | |||||||
2261 | #if (GCC_VERSION(4 * 1000 + 2) >= 3000) | ||||||
2262 | # pragma GCC poison m_vec m_vecpfx m_vecdata | ||||||
2263 | #endif | ||||||
2264 | |||||||
2265 | #endif // GCC_VEC_H |