1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "type_converter.h"
17 
18 #include <algorithm>
19 #include <memory>
20 #include <numeric>
21 #include <vector>
22 
23 #include "aie_log.h"
24 #include "aie_macros.h"
25 #include "aie_retcode_inner.h"
26 
27 using namespace OHOS::AI::Feature;
28 
29 namespace {
30 #define TYPE_CONVERT_ITEMS(input, output, indices)                                \
31     do {                                                                          \
32         std::for_each(indices.begin(), indices.end(), [input, output](size_t i) { \
33             output[i] = input[i];                                                 \
34         });                                                                       \
35     } while (0)
36 }
37 
38 template<typename InType>
DoCast(const InType * inputAddr,size_t inputSize,FeatureData & buffer)39 static int32_t DoCast(const InType *inputAddr, size_t inputSize, FeatureData &buffer)
40 {
41     std::vector<size_t> indices(inputSize);
42     std::iota(indices.begin(), indices.end(), 0);
43     switch (buffer.dataType) {
44         case UINT8: {
45             auto outputAddr = static_cast<uint8_t *>(buffer.data);
46             TYPE_CONVERT_ITEMS(inputAddr, outputAddr, indices);
47             break;
48         }
49         case INT8: {
50             auto outputAddr = static_cast<int8_t *>(buffer.data);
51             TYPE_CONVERT_ITEMS(inputAddr, outputAddr, indices);
52             break;
53         }
54         case UINT16: {
55             auto outputAddr = static_cast<uint16_t *>(buffer.data);
56             TYPE_CONVERT_ITEMS(inputAddr, outputAddr, indices);
57             break;
58         }
59         case INT16: {
60             auto outputAddr = static_cast<int16_t *>(buffer.data);
61             TYPE_CONVERT_ITEMS(inputAddr, outputAddr, indices);
62             break;
63         }
64         case UINT32: {
65             auto outputAddr = static_cast<uint32_t *>(buffer.data);
66             TYPE_CONVERT_ITEMS(inputAddr, outputAddr, indices);
67             break;
68         }
69         case INT32: {
70             auto outputAddr = static_cast<int32_t *>(buffer.data);
71             TYPE_CONVERT_ITEMS(inputAddr, outputAddr, indices);
72             break;
73         }
74         case FLOAT: {
75             auto outputAddr = static_cast<float *>(buffer.data);
76             TYPE_CONVERT_ITEMS(inputAddr, outputAddr, indices);
77             break;
78         }
79         default:
80             return RETCODE_FAILURE;
81     }
82     return RETCODE_SUCCESS;
83 }
84 
TypeConverter()85 TypeConverter::TypeConverter(): isInitialized_(false)
86 {
87     workBuffer_ = {
88         .dataType = UNKNOWN,
89         .data = nullptr,
90         .size = 0,
91     };
92 }
93 
~TypeConverter()94 TypeConverter::~TypeConverter()
95 {
96     Release();
97 }
98 
Init(const FeatureProcessorConfig * config)99 int32_t TypeConverter::Init(const FeatureProcessorConfig *config)
100 {
101     if (isInitialized_) {
102         HILOGE("[TypeConverter]Fail to initialize more than once. Release it, then try again");
103         return RETCODE_FAILURE;
104     }
105     if (config == nullptr) {
106         HILOGE("[TypeConverter]Fail with null config pointer");
107         return RETCODE_FAILURE;
108     }
109     auto localConfig = *(static_cast<const TypeConverterConfig *>(config));
110     if (localConfig.dataType == UNKNOWN) {
111         HILOGE("[TypeConverter]The configured dataType[UNKNOWN] is unsupported");
112         return RETCODE_FAILURE;
113     }
114     workBuffer_.dataType = localConfig.dataType;
115     workBuffer_.size = localConfig.size;
116     uint8_t typeSize = CONVERT_DATATYPE_TO_SIZE(workBuffer_.dataType);
117     size_t bufferSize = workBuffer_.size * typeSize;
118     if (bufferSize > MAX_SAMPLE_SIZE) {
119         HILOGE("[TypeConverter]The required memory size is larger than MAX_SAMPLE_SIZE[%zu]",
120             MAX_SAMPLE_SIZE);
121         return RETCODE_FAILURE;
122     }
123     AIE_NEW(workBuffer_.data, uint8_t[bufferSize]);
124     if (workBuffer_.data == nullptr) {
125         HILOGE("[TypeConverter]Fail to allocate memory for workBuffer");
126         return RETCODE_FAILURE;
127     }
128     isInitialized_ = true;
129     return RETCODE_SUCCESS;
130 }
131 
Release()132 void TypeConverter::Release()
133 {
134     if (isInitialized_) {
135         auto bufferAddr = static_cast<uint8_t *>(workBuffer_.data);
136         AIE_DELETE_ARRAY(bufferAddr);
137         isInitialized_ = false;
138     }
139 }
140 
Process(const FeatureData & input,FeatureData & output)141 int32_t TypeConverter::Process(const FeatureData &input, FeatureData &output)
142 {
143     if (output.data != nullptr || output.size != 0) {
144         HILOGE("[TypeConverter]Fail with non-empty output");
145         return RETCODE_FAILURE;
146     }
147     if (input.data == nullptr || input.size == 0) {
148         HILOGE("[TypeConverter]Fail to process with nullptr input");
149         return RETCODE_FAILURE;
150     }
151     if (input.size != workBuffer_.size) {
152         HILOGE("[TypeConverter]The input size[%zu] is not equal to the output size[%zu]",
153             input.size, workBuffer_.size);
154         return RETCODE_FAILURE;
155     }
156     if (InnerProcess(input) != RETCODE_SUCCESS) {
157         HILOGE("[TypeConverter]Fail to convert dataType from input to output");
158         return RETCODE_FAILURE;
159     }
160     output.dataType = workBuffer_.dataType;
161     output.data = workBuffer_.data;
162     output.size = workBuffer_.size;
163     return RETCODE_SUCCESS;
164 }
165 
InnerProcess(const FeatureData & input)166 int32_t TypeConverter::InnerProcess(const FeatureData &input)
167 {
168     switch (input.dataType) {
169         case UINT8:
170             return DoCast<uint8_t>(static_cast<uint8_t *>(input.data), input.size, workBuffer_);
171         case INT8:
172             return DoCast<int8_t>(static_cast<int8_t *>(input.data), input.size, workBuffer_);
173         case UINT16:
174             return DoCast<uint16_t>(static_cast<uint16_t *>(input.data), input.size, workBuffer_);
175         case INT16:
176             return DoCast<int16_t>(static_cast<int16_t *>(input.data), input.size, workBuffer_);
177         case UINT32:
178             return DoCast<uint32_t>(static_cast<uint32_t *>(input.data), input.size, workBuffer_);
179         case INT32:
180             return DoCast<int32_t>(static_cast<int32_t *>(input.data), input.size, workBuffer_);
181         case FLOAT:
182             return DoCast<float>(static_cast<float *>(input.data), input.size, workBuffer_);
183         default:
184             HILOGE("[TypeConverter]Fail with unknown input type");
185             return RETCODE_FAILURE;
186     }
187     return RETCODE_SUCCESS;
188 }