1 /*
2 * Copyright 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "fields/array_field.h"
18
19 #include "fields/custom_field.h"
20 #include "fields/scalar_field.h"
21 #include "util.h"
22
23 const std::string ArrayField::kFieldType = "ArrayField";
24
ArrayField(std::string name,int element_size,int array_size,ParseLocation loc)25 ArrayField::ArrayField(std::string name, int element_size, int array_size, ParseLocation loc)
26 : PacketField(name, loc),
27 element_field_(new ScalarField("val", element_size, loc)),
28 element_size_(element_size),
29 array_size_(array_size) {
30 if (element_size > 64 || element_size < 0) {
31 ERROR(this) << __func__ << ": Not implemented for element size = " << element_size;
32 }
33 if (element_size % 8 != 0) {
34 ERROR(this) << "Can only have arrays with elements that are byte aligned (" << element_size
35 << ")";
36 }
37 }
38
ArrayField(std::string name,TypeDef * type_def,int array_size,ParseLocation loc)39 ArrayField::ArrayField(std::string name, TypeDef* type_def, int array_size, ParseLocation loc)
40 : PacketField(name, loc),
41 element_field_(type_def->GetNewField("val", loc)),
42 element_size_(element_field_->GetSize()),
43 array_size_(array_size) {
44 if (!element_size_.empty() && element_size_.bits() % 8 != 0) {
45 ERROR(this) << "Can only have arrays with elements that are byte aligned (" << element_size_
46 << ")";
47 }
48 }
49
GetFieldType() const50 const std::string& ArrayField::GetFieldType() const { return ArrayField::kFieldType; }
51
GetSize() const52 Size ArrayField::GetSize() const {
53 if (!element_size_.empty() && !element_size_.has_dynamic()) {
54 return Size(array_size_ * element_size_.bits());
55 }
56 return Size();
57 }
58
GetBuilderSize() const59 Size ArrayField::GetBuilderSize() const {
60 if (!element_size_.empty() && !element_size_.has_dynamic()) {
61 return GetSize();
62 } else if (element_field_->BuilderParameterMustBeMoved()) {
63 std::string ret = "[this](){ size_t length = 0; for (const auto& elem : " + GetName() +
64 "_) { length += elem->size() * 8; } return length; }()";
65 return ret;
66 } else {
67 std::string ret = "[this](){ size_t length = 0; for (const auto& elem : " + GetName() +
68 "_) { length += elem.size() * 8; } return length; }()";
69 return ret;
70 }
71 }
72
GetStructSize() const73 Size ArrayField::GetStructSize() const {
74 if (!element_size_.empty() && !element_size_.has_dynamic()) {
75 return GetSize();
76 } else if (element_field_->BuilderParameterMustBeMoved()) {
77 std::string ret = "[this](){ size_t length = 0; for (const auto& elem : to_fill->" + GetName() +
78 "_) { length += elem->size() * 8; } return length; }()";
79 return ret;
80 } else {
81 std::string ret = "[this](){ size_t length = 0; for (const auto& elem : to_fill->" + GetName() +
82 "_) { length += elem.size() * 8; } return length; }()";
83 return ret;
84 }
85 }
86
GetDataType() const87 std::string ArrayField::GetDataType() const {
88 return "std::array<" + element_field_->GetDataType() + "," + std::to_string(array_size_) + ">";
89 }
90
GenExtractor(std::ostream & s,int num_leading_bits,bool for_struct) const91 void ArrayField::GenExtractor(std::ostream& s, int num_leading_bits, bool for_struct) const {
92 s << GetDataType() << "::iterator ret_it = " << GetName() << "_ptr->begin();";
93 s << "auto " << element_field_->GetName() << "_it = " << GetName() << "_it;";
94 if (!element_size_.empty()) {
95 s << "while (" << element_field_->GetName()
96 << "_it.NumBytesRemaining() >= " << element_size_.bytes();
97 s << " && ret_it < " << GetName() << "_ptr->end()) {";
98 } else {
99 s << "while (" << element_field_->GetName() << "_it.NumBytesRemaining() > 0 ";
100 s << " && ret_it < " << GetName() << "_ptr->end()) {";
101 }
102 if (element_field_->BuilderParameterMustBeMoved()) {
103 s << element_field_->GetDataType() << " " << element_field_->GetName() << "_ptr;";
104 } else {
105 s << "auto " << element_field_->GetName() << "_ptr = ret_it;";
106 }
107 element_field_->GenExtractor(s, num_leading_bits, for_struct);
108 if (element_field_->BuilderParameterMustBeMoved()) {
109 s << "*ret_it = std::move(" << element_field_->GetName() << "_ptr);";
110 }
111 s << "ret_it++;";
112 s << "}";
113 }
114
GetGetterFunctionName() const115 std::string ArrayField::GetGetterFunctionName() const {
116 std::stringstream ss;
117 ss << "Get" << util::UnderscoreToCamelCase(GetName());
118 return ss.str();
119 }
120
GenGetter(std::ostream & s,Size start_offset,Size end_offset) const121 void ArrayField::GenGetter(std::ostream& s, Size start_offset, Size end_offset) const {
122 s << GetDataType() << " " << GetGetterFunctionName() << "() const {";
123 s << "ASSERT(was_validated_);";
124 s << "size_t end_index = size();";
125 s << "auto to_bound = begin();";
126
127 int num_leading_bits = GenBounds(s, start_offset, end_offset, GetSize());
128 s << GetDataType() << " " << GetName() << "_value{};";
129 s << GetDataType() << "* " << GetName() << "_ptr = &" << GetName() << "_value;";
130 GenExtractor(s, num_leading_bits, false);
131
132 s << "return " << GetName() << "_value;";
133 s << "}\n";
134 }
135
GetBuilderParameterType() const136 std::string ArrayField::GetBuilderParameterType() const {
137 std::stringstream ss;
138 if (element_field_->BuilderParameterMustBeMoved()) {
139 ss << "std::array<" << element_field_->GetDataType() << "," << array_size_ << ">";
140 } else {
141 ss << "const std::array<" << element_field_->GetDataType() << "," << array_size_ << ">&";
142 }
143 return ss.str();
144 }
145
BuilderParameterMustBeMoved() const146 bool ArrayField::BuilderParameterMustBeMoved() const {
147 return element_field_->BuilderParameterMustBeMoved();
148 }
149
GenBuilderMember(std::ostream & s) const150 bool ArrayField::GenBuilderMember(std::ostream& s) const {
151 s << "std::array<" << element_field_->GetDataType() << "," << array_size_ << "> " << GetName();
152 return true;
153 }
154
HasParameterValidator() const155 bool ArrayField::HasParameterValidator() const { return false; }
156
GenParameterValidator(std::ostream &) const157 void ArrayField::GenParameterValidator(std::ostream&) const {
158 // Array length is validated by the compiler
159 }
160
GenInserter(std::ostream & s) const161 void ArrayField::GenInserter(std::ostream& s) const {
162 s << "for (const auto& val_ : " << GetName() << "_) {";
163 element_field_->GenInserter(s);
164 s << "}\n";
165 }
166
GenValidator(std::ostream &) const167 void ArrayField::GenValidator(std::ostream&) const {
168 // NOTE: We could check if the element size divides cleanly into the array size, but we decided to
169 // forgo that in favor of just returning as many elements as possible in a best effort style.
170 //
171 // Other than that there is nothing that arrays need to be validated on other than length so
172 // nothing needs to be done here.
173 }
174
IsContainerField() const175 bool ArrayField::IsContainerField() const { return true; }
176
GetElementField() const177 const PacketField* ArrayField::GetElementField() const { return element_field_; }
178
GenStringRepresentation(std::ostream & s,std::string accessor) const179 void ArrayField::GenStringRepresentation(std::ostream& s, std::string accessor) const {
180 s << "\"ARRAY[\";";
181 s << "/* " << element_field_->GetDataType() << " " << element_field_->GetFieldType() << " */";
182
183 std::string arr_idx = "arridx_" + accessor;
184 std::string arr_size = std::to_string(array_size_);
185 s << "for (size_t index = 0; index < " << arr_size << "; index++) {";
186 std::string element_accessor = "(" + accessor + "[index])";
187 s << "ss << ((index == 0) ? \"\" : \", \") << ";
188
189 if (element_field_->GetFieldType() == CustomField::kFieldType) {
190 s << element_accessor << ".ToString()";
191 } else {
192 element_field_->GenStringRepresentation(s, element_accessor);
193 }
194
195 s << ";}";
196 s << "ss << \"]\"";
197 }
198