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