Myles Watson | 41aecb9 | 2019-02-06 14:02:36 -0800 | [diff] [blame] | 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" |
Myles Watson | 5e69313 | 2019-09-18 16:19:06 -0700 | [diff] [blame] | 18 | |
Myles Watson | 945f4c3 | 2019-09-25 15:33:39 -0700 | [diff] [blame] | 19 | #include "fields/custom_field.h" |
| 20 | #include "fields/scalar_field.h" |
Myles Watson | 41aecb9 | 2019-02-06 14:02:36 -0800 | [diff] [blame] | 21 | #include "util.h" |
| 22 | |
Myles Watson | 6f55d38 | 2019-07-15 15:02:48 -0700 | [diff] [blame] | 23 | const std::string ArrayField::kFieldType = "ArrayField"; |
| 24 | |
Myles Watson | 5e69313 | 2019-09-18 16:19:06 -0700 | [diff] [blame] | 25 | ArrayField::ArrayField(std::string name, int element_size, int array_size, ParseLocation loc) |
| 26 | : PacketField(name, loc), element_field_(new ScalarField("val", element_size, loc)), element_size_(element_size), |
| 27 | array_size_(array_size) { |
| 28 | if (element_size > 64 || element_size < 0) |
| 29 | ERROR(this) << __func__ << ": Not implemented for element size = " << element_size; |
Myles Watson | de15b64 | 2019-07-02 12:02:47 -0700 | [diff] [blame] | 30 | if (element_size % 8 != 0) { |
| 31 | ERROR(this) << "Can only have arrays with elements that are byte aligned (" << element_size << ")"; |
| 32 | } |
Myles Watson | 41aecb9 | 2019-02-06 14:02:36 -0800 | [diff] [blame] | 33 | } |
| 34 | |
Myles Watson | 5e69313 | 2019-09-18 16:19:06 -0700 | [diff] [blame] | 35 | ArrayField::ArrayField(std::string name, TypeDef* type_def, int array_size, ParseLocation loc) |
| 36 | : PacketField(name, loc), element_field_(type_def->GetNewField("val", loc)), |
| 37 | element_size_(element_field_->GetSize()), array_size_(array_size) { |
| 38 | if (!element_size_.empty() && element_size_.bits() % 8 != 0) { |
| 39 | ERROR(this) << "Can only have arrays with elements that are byte aligned (" << element_size_ << ")"; |
Myles Watson | de15b64 | 2019-07-02 12:02:47 -0700 | [diff] [blame] | 40 | } |
Myles Watson | 41aecb9 | 2019-02-06 14:02:36 -0800 | [diff] [blame] | 41 | } |
| 42 | |
Myles Watson | 6f55d38 | 2019-07-15 15:02:48 -0700 | [diff] [blame] | 43 | const std::string& ArrayField::GetFieldType() const { |
| 44 | return ArrayField::kFieldType; |
Myles Watson | 41aecb9 | 2019-02-06 14:02:36 -0800 | [diff] [blame] | 45 | } |
| 46 | |
| 47 | Size ArrayField::GetSize() const { |
Myles Watson | 5e69313 | 2019-09-18 16:19:06 -0700 | [diff] [blame] | 48 | if (!element_size_.empty() && !element_size_.has_dynamic()) { |
| 49 | return Size(array_size_ * element_size_.bits()); |
Myles Watson | 41aecb9 | 2019-02-06 14:02:36 -0800 | [diff] [blame] | 50 | } |
Jakub Pawlowski | de83e2c | 2019-07-19 14:51:50 +0200 | [diff] [blame] | 51 | return Size(); |
Myles Watson | 41aecb9 | 2019-02-06 14:02:36 -0800 | [diff] [blame] | 52 | } |
| 53 | |
Myles Watson | de15b64 | 2019-07-02 12:02:47 -0700 | [diff] [blame] | 54 | Size ArrayField::GetBuilderSize() const { |
Myles Watson | 5e69313 | 2019-09-18 16:19:06 -0700 | [diff] [blame] | 55 | if (!element_size_.empty() && !element_size_.has_dynamic()) { |
| 56 | return GetSize(); |
Myles Watson | 945f4c3 | 2019-09-25 15:33:39 -0700 | [diff] [blame] | 57 | } else if (element_field_->BuilderParameterMustBeMoved()) { |
| 58 | std::string ret = "[this](){ size_t length = 0; for (const auto& elem : " + GetName() + |
| 59 | "_) { length += elem->size() * 8; } return length; }()"; |
| 60 | return ret; |
Myles Watson | de15b64 | 2019-07-02 12:02:47 -0700 | [diff] [blame] | 61 | } else { |
| 62 | std::string ret = "[this](){ size_t length = 0; for (const auto& elem : " + GetName() + |
| 63 | "_) { length += elem.size() * 8; } return length; }()"; |
| 64 | return ret; |
| 65 | } |
| 66 | } |
| 67 | |
Myles Watson | 4b8c0ed | 2019-10-03 09:08:34 -0700 | [diff] [blame] | 68 | Size ArrayField::GetStructSize() const { |
| 69 | if (!element_size_.empty() && !element_size_.has_dynamic()) { |
| 70 | return GetSize(); |
| 71 | } else if (element_field_->BuilderParameterMustBeMoved()) { |
| 72 | std::string ret = "[this](){ size_t length = 0; for (const auto& elem : to_fill->" + GetName() + |
| 73 | "_) { length += elem->size() * 8; } return length; }()"; |
| 74 | return ret; |
| 75 | } else { |
| 76 | std::string ret = "[this](){ size_t length = 0; for (const auto& elem : to_fill->" + GetName() + |
| 77 | "_) { length += elem.size() * 8; } return length; }()"; |
| 78 | return ret; |
| 79 | } |
| 80 | } |
| 81 | |
Myles Watson | 6f55d38 | 2019-07-15 15:02:48 -0700 | [diff] [blame] | 82 | std::string ArrayField::GetDataType() const { |
Myles Watson | 5e69313 | 2019-09-18 16:19:06 -0700 | [diff] [blame] | 83 | return "std::array<" + element_field_->GetDataType() + "," + std::to_string(array_size_) + ">"; |
Myles Watson | 41aecb9 | 2019-02-06 14:02:36 -0800 | [diff] [blame] | 84 | } |
| 85 | |
Myles Watson | 5e43ed7 | 2019-10-02 15:01:15 -0700 | [diff] [blame] | 86 | void ArrayField::GenExtractor(std::ostream& s, int num_leading_bits, bool for_struct) const { |
Myles Watson | 5e69313 | 2019-09-18 16:19:06 -0700 | [diff] [blame] | 87 | s << GetDataType() << "::iterator ret_it = " << GetName() << "_ptr->begin();"; |
| 88 | s << "auto " << element_field_->GetName() << "_it = " << GetName() << "_it;"; |
Myles Watson | d66ec50 | 2019-10-04 16:02:38 -0700 | [diff] [blame] | 89 | if (!element_size_.empty()) { |
Myles Watson | 5e69313 | 2019-09-18 16:19:06 -0700 | [diff] [blame] | 90 | s << "while (" << element_field_->GetName() << "_it.NumBytesRemaining() >= " << element_size_.bytes(); |
| 91 | s << " && ret_it < " << GetName() << "_ptr->end()) {"; |
Myles Watson | cbfe6cf | 2019-07-16 09:50:23 -0700 | [diff] [blame] | 92 | } else { |
Myles Watson | 5e69313 | 2019-09-18 16:19:06 -0700 | [diff] [blame] | 93 | s << "while (" << element_field_->GetName() << "_it.NumBytesRemaining() > 0 "; |
| 94 | s << " && ret_it < " << GetName() << "_ptr->end()) {"; |
Myles Watson | cbfe6cf | 2019-07-16 09:50:23 -0700 | [diff] [blame] | 95 | } |
Myles Watson | 945f4c3 | 2019-09-25 15:33:39 -0700 | [diff] [blame] | 96 | if (element_field_->BuilderParameterMustBeMoved()) { |
| 97 | s << element_field_->GetDataType() << " " << element_field_->GetName() << "_ptr;"; |
| 98 | } else { |
| 99 | s << element_field_->GetDataType() << "* " << element_field_->GetName() << "_ptr = ret_it;"; |
| 100 | } |
Myles Watson | 5e43ed7 | 2019-10-02 15:01:15 -0700 | [diff] [blame] | 101 | element_field_->GenExtractor(s, num_leading_bits, for_struct); |
Myles Watson | 945f4c3 | 2019-09-25 15:33:39 -0700 | [diff] [blame] | 102 | if (element_field_->BuilderParameterMustBeMoved()) { |
| 103 | s << "*ret_it = std::move(" << element_field_->GetName() << "_ptr);"; |
| 104 | } |
Myles Watson | 4b10f63 | 2019-08-22 14:11:00 -0700 | [diff] [blame] | 105 | s << "ret_it++;"; |
| 106 | s << "}"; |
Myles Watson | cbfe6cf | 2019-07-16 09:50:23 -0700 | [diff] [blame] | 107 | } |
| 108 | |
Jack He | c61124e | 2019-11-18 15:35:04 -0800 | [diff] [blame^] | 109 | std::string ArrayField::GetGetterFunctionName() const { |
| 110 | std::stringstream ss; |
| 111 | ss << "Get" << util::UnderscoreToCamelCase(GetName()); |
| 112 | return ss.str(); |
| 113 | } |
| 114 | |
Myles Watson | 41aecb9 | 2019-02-06 14:02:36 -0800 | [diff] [blame] | 115 | void ArrayField::GenGetter(std::ostream& s, Size start_offset, Size end_offset) const { |
Jack He | c61124e | 2019-11-18 15:35:04 -0800 | [diff] [blame^] | 116 | s << GetDataType() << " " << GetGetterFunctionName() << "() {"; |
Myles Watson | 8def62f | 2019-07-24 15:52:33 -0700 | [diff] [blame] | 117 | s << "ASSERT(was_validated_);"; |
Myles Watson | 6de8691 | 2019-08-06 23:07:52 -0700 | [diff] [blame] | 118 | s << "size_t end_index = size();"; |
Myles Watson | 5e69313 | 2019-09-18 16:19:06 -0700 | [diff] [blame] | 119 | s << "auto to_bound = begin();"; |
Myles Watson | 41aecb9 | 2019-02-06 14:02:36 -0800 | [diff] [blame] | 120 | |
Myles Watson | b6ec5e1 | 2019-10-02 15:07:05 -0700 | [diff] [blame] | 121 | int num_leading_bits = GenBounds(s, start_offset, end_offset, GetSize()); |
Myles Watson | 5e69313 | 2019-09-18 16:19:06 -0700 | [diff] [blame] | 122 | s << GetDataType() << " " << GetName() << "_value;"; |
| 123 | s << GetDataType() << "* " << GetName() << "_ptr = &" << GetName() << "_value;"; |
Myles Watson | 5e43ed7 | 2019-10-02 15:01:15 -0700 | [diff] [blame] | 124 | GenExtractor(s, num_leading_bits, false); |
Myles Watson | 41aecb9 | 2019-02-06 14:02:36 -0800 | [diff] [blame] | 125 | |
Myles Watson | 5e69313 | 2019-09-18 16:19:06 -0700 | [diff] [blame] | 126 | s << "return " << GetName() << "_value;"; |
Myles Watson | 41aecb9 | 2019-02-06 14:02:36 -0800 | [diff] [blame] | 127 | s << "}\n"; |
| 128 | } |
| 129 | |
Jack He | c61124e | 2019-11-18 15:35:04 -0800 | [diff] [blame^] | 130 | std::string ArrayField::GetBuilderParameterType() const { |
| 131 | std::stringstream ss; |
Myles Watson | 945f4c3 | 2019-09-25 15:33:39 -0700 | [diff] [blame] | 132 | if (element_field_->BuilderParameterMustBeMoved()) { |
Jack He | c61124e | 2019-11-18 15:35:04 -0800 | [diff] [blame^] | 133 | ss << "std::array<" << element_field_->GetDataType() << "," << array_size_ << ">"; |
Myles Watson | 945f4c3 | 2019-09-25 15:33:39 -0700 | [diff] [blame] | 134 | } else { |
Jack He | c61124e | 2019-11-18 15:35:04 -0800 | [diff] [blame^] | 135 | ss << "const std::array<" << element_field_->GetDataType() << "," << array_size_ << ">&"; |
Myles Watson | 945f4c3 | 2019-09-25 15:33:39 -0700 | [diff] [blame] | 136 | } |
Jack He | c61124e | 2019-11-18 15:35:04 -0800 | [diff] [blame^] | 137 | return ss.str(); |
Myles Watson | 835bf7b | 2019-07-17 13:17:24 -0700 | [diff] [blame] | 138 | } |
Myles Watson | 41aecb9 | 2019-02-06 14:02:36 -0800 | [diff] [blame] | 139 | |
Myles Watson | 945f4c3 | 2019-09-25 15:33:39 -0700 | [diff] [blame] | 140 | bool ArrayField::BuilderParameterMustBeMoved() const { |
| 141 | return element_field_->BuilderParameterMustBeMoved(); |
| 142 | } |
| 143 | |
Myles Watson | 835bf7b | 2019-07-17 13:17:24 -0700 | [diff] [blame] | 144 | bool ArrayField::GenBuilderMember(std::ostream& s) const { |
Myles Watson | 5e69313 | 2019-09-18 16:19:06 -0700 | [diff] [blame] | 145 | s << "std::array<" << element_field_->GetDataType() << "," << array_size_ << "> " << GetName(); |
Myles Watson | 41aecb9 | 2019-02-06 14:02:36 -0800 | [diff] [blame] | 146 | return true; |
| 147 | } |
| 148 | |
| 149 | bool ArrayField::HasParameterValidator() const { |
Jakub Pawlowski | de83e2c | 2019-07-19 14:51:50 +0200 | [diff] [blame] | 150 | return false; |
Myles Watson | 41aecb9 | 2019-02-06 14:02:36 -0800 | [diff] [blame] | 151 | } |
| 152 | |
Jakub Pawlowski | de83e2c | 2019-07-19 14:51:50 +0200 | [diff] [blame] | 153 | void ArrayField::GenParameterValidator(std::ostream&) const { |
| 154 | // Array length is validated by the compiler |
Myles Watson | 41aecb9 | 2019-02-06 14:02:36 -0800 | [diff] [blame] | 155 | } |
| 156 | |
| 157 | void ArrayField::GenInserter(std::ostream& s) const { |
Myles Watson | 5e69313 | 2019-09-18 16:19:06 -0700 | [diff] [blame] | 158 | s << "for (const auto& val_ : " << GetName() << "_) {"; |
| 159 | element_field_->GenInserter(s); |
Myles Watson | 41aecb9 | 2019-02-06 14:02:36 -0800 | [diff] [blame] | 160 | s << "}\n"; |
| 161 | } |
| 162 | |
| 163 | void ArrayField::GenValidator(std::ostream&) const { |
| 164 | // NOTE: We could check if the element size divides cleanly into the array size, but we decided to forgo that |
| 165 | // in favor of just returning as many elements as possible in a best effort style. |
| 166 | // |
| 167 | // Other than that there is nothing that arrays need to be validated on other than length so nothing needs to |
| 168 | // be done here. |
| 169 | } |
Jack He | c61124e | 2019-11-18 15:35:04 -0800 | [diff] [blame^] | 170 | |
| 171 | bool ArrayField::IsContainerField() const { |
| 172 | return true; |
| 173 | } |
| 174 | |
| 175 | const PacketField* ArrayField::GetElementField() const { |
| 176 | return element_field_; |
| 177 | } |