]>
Commit | Line | Data |
---|---|---|
f67539c2 TL |
1 | /* |
2 | * Licensed to the Apache Software Foundation (ASF) under one | |
3 | * or more contributor license agreements. See the NOTICE file | |
4 | * distributed with this work for additional information | |
5 | * regarding copyright ownership. The ASF licenses this file | |
6 | * to you under the Apache License, Version 2.0 (the | |
7 | * "License"); you may not use this file except in compliance | |
8 | * with the License. You may obtain a copy of the License at | |
9 | * | |
10 | * http://www.apache.org/licenses/LICENSE-2.0 | |
11 | * | |
12 | * Unless required by applicable law or agreed to in writing, | |
13 | * software distributed under the License is distributed on an | |
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
15 | * KIND, either express or implied. See the License for the | |
16 | * specific language governing permissions and limitations | |
17 | * under the License. | |
18 | */ | |
19 | ||
20 | #ifndef T_STRUCT_H | |
21 | #define T_STRUCT_H | |
22 | ||
23 | #include <algorithm> | |
24 | #include <vector> | |
25 | #include <utility> | |
26 | #include <string> | |
27 | ||
28 | #include "thrift/parse/t_type.h" | |
29 | #include "thrift/parse/t_field.h" | |
30 | ||
31 | // Forward declare that puppy | |
32 | class t_program; | |
33 | ||
34 | /** | |
35 | * A struct is a container for a set of member fields that has a name. Structs | |
36 | * are also used to implement exception types. | |
37 | * | |
38 | */ | |
39 | class t_struct : public t_type { | |
40 | public: | |
41 | typedef std::vector<t_field*> members_type; | |
42 | ||
43 | t_struct(t_program* program) | |
44 | : t_type(program), | |
45 | is_xception_(false), | |
46 | is_union_(false), | |
47 | members_validated(false), | |
48 | members_with_value(0), | |
49 | xsd_all_(false) {} | |
50 | ||
51 | t_struct(t_program* program, const std::string& name) | |
52 | : t_type(program, name), | |
53 | is_xception_(false), | |
54 | is_union_(false), | |
55 | members_validated(false), | |
56 | members_with_value(0), | |
57 | xsd_all_(false) {} | |
58 | ||
59 | void set_name(const std::string& name) override { | |
60 | name_ = name; | |
61 | validate_union_members(); | |
62 | } | |
63 | ||
64 | void set_xception(bool is_xception) { is_xception_ = is_xception; } | |
65 | ||
66 | void validate_union_member(t_field* field) { | |
67 | if (is_union_ && (!name_.empty())) { | |
68 | ||
69 | // 1) unions can't have required fields | |
70 | // 2) union members are implicitly optional, otherwise bugs like THRIFT-3650 wait to happen | |
71 | if (field->get_req() != t_field::T_OPTIONAL) { | |
72 | // no warning on default requiredness, but do warn on anything else that is explicitly asked for | |
73 | if(field->get_req() != t_field::T_OPT_IN_REQ_OUT) { | |
74 | pwarning(1, | |
75 | "Union %s field %s: union members must be optional, ignoring specified requiredness.\n", | |
76 | name_.c_str(), | |
77 | field->get_name().c_str()); | |
78 | } | |
79 | field->set_req(t_field::T_OPTIONAL); | |
80 | } | |
81 | ||
82 | // unions may have up to one member defaulted, but not more | |
83 | if (field->get_value() != nullptr) { | |
84 | if (1 < ++members_with_value) { | |
85 | throw "Error: Field " + field->get_name() + " provides another default value for union " | |
86 | + name_; | |
87 | } | |
88 | } | |
89 | } | |
90 | } | |
91 | ||
92 | void validate_union_members() { | |
93 | if (is_union_ && (!name_.empty()) && (!members_validated)) { | |
94 | members_type::const_iterator m_iter; | |
95 | for (m_iter = members_in_id_order_.begin(); m_iter != members_in_id_order_.end(); ++m_iter) { | |
96 | validate_union_member(*m_iter); | |
97 | } | |
98 | members_validated = true; | |
99 | } | |
100 | } | |
101 | ||
102 | void set_union(bool is_union) { | |
103 | is_union_ = is_union; | |
104 | validate_union_members(); | |
105 | } | |
106 | ||
107 | void set_xsd_all(bool xsd_all) { xsd_all_ = xsd_all; } | |
108 | ||
109 | bool get_xsd_all() const { return xsd_all_; } | |
110 | ||
111 | bool append(t_field* elem) { | |
112 | typedef members_type::iterator iter_type; | |
113 | std::pair<iter_type, iter_type> bounds = std::equal_range(members_in_id_order_.begin(), | |
114 | members_in_id_order_.end(), | |
115 | elem, | |
116 | t_field::key_compare()); | |
117 | if (bounds.first != bounds.second) { | |
118 | return false; | |
119 | } | |
120 | // returns false when there is a conflict of field names | |
121 | if (get_field_by_name(elem->get_name()) != nullptr) { | |
122 | return false; | |
123 | } | |
124 | members_.push_back(elem); | |
125 | members_in_id_order_.insert(bounds.second, elem); | |
126 | validate_union_member(elem); | |
127 | return true; | |
128 | } | |
129 | ||
130 | const members_type& get_members() const { return members_; } | |
131 | ||
132 | const members_type& get_sorted_members() const { return members_in_id_order_; } | |
133 | ||
134 | bool is_struct() const override { return !is_xception_; } | |
135 | ||
136 | bool is_xception() const override { return is_xception_; } | |
137 | ||
138 | bool is_union() const { return is_union_; } | |
139 | ||
140 | t_field* get_field_by_name(std::string field_name) { | |
141 | return const_cast<t_field*>(const_cast<const t_struct&>(*this).get_field_by_name(field_name)); | |
142 | } | |
143 | ||
144 | const t_field* get_field_by_name(std::string field_name) const { | |
145 | members_type::const_iterator m_iter; | |
146 | for (m_iter = members_in_id_order_.begin(); m_iter != members_in_id_order_.end(); ++m_iter) { | |
147 | if ((*m_iter)->get_name() == field_name) { | |
148 | return *m_iter; | |
149 | } | |
150 | } | |
151 | return nullptr; | |
152 | } | |
153 | ||
154 | private: | |
155 | members_type members_; | |
156 | members_type members_in_id_order_; | |
157 | bool is_xception_; | |
158 | bool is_union_; | |
159 | bool members_validated; | |
160 | int members_with_value; | |
161 | ||
162 | bool xsd_all_; | |
163 | }; | |
164 | ||
165 | #endif |