1/*
2 * Copyright (c) 2011-2015, Intel Corporation
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation and/or
13 * other materials provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors
16 * may be used to endorse or promote products derived from this software without
17 * specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30#include "ArrayParameter.h"
31#include <sstream> // for istringstream
32#include "Tokenizer.h"
33#include "ParameterType.h"
34#include "ParameterAccessContext.h"
35#include "ConfigurationAccessContext.h"
36#include "ParameterBlackboard.h"
37#include "Utility.h"
38#include <assert.h>
39
40#define base CParameter
41
42using std::string;
43
44CArrayParameter::CArrayParameter(const string &strName, const CTypeElement *pTypeElement)
45    : base(strName, pTypeElement)
46{
47}
48
49size_t CArrayParameter::getFootPrint() const
50{
51    return getSize() * getArrayLength();
52}
53
54// Array length
55size_t CArrayParameter::getArrayLength() const
56{
57    return getTypeElement()->getArrayLength();
58}
59
60// Element properties
61void CArrayParameter::showProperties(string &strResult) const
62{
63    base::showProperties(strResult);
64
65    // Array length
66    strResult += "Array length: ";
67    strResult += std::to_string(getArrayLength());
68    strResult += "\n";
69}
70
71// User set/get
72bool CArrayParameter::accessValue(CPathNavigator &pathNavigator, string &strValue, bool bSet,
73                                  CParameterAccessContext &parameterAccessContext) const
74{
75    size_t index;
76
77    if (!getIndex(pathNavigator, index, parameterAccessContext)) {
78
79        return false;
80    }
81
82    if (bSet) {
83        // Set
84        if (index == (size_t)-1) {
85
86            // No index provided, start with 0
87            index = 0;
88        }
89
90        // Actually set values
91        if (!setValues(index, getOffset() - parameterAccessContext.getBaseOffset(), strValue,
92                       parameterAccessContext)) {
93            return false;
94        }
95
96        // Synchronize
97        if (!sync(parameterAccessContext)) {
98
99            appendParameterPathToError(parameterAccessContext);
100            return false;
101        }
102    } else {
103        // Get
104        if (index == (size_t)-1) {
105
106            // Whole array requested
107            strValue = getValues(getOffset() - parameterAccessContext.getBaseOffset(),
108                                 parameterAccessContext);
109
110        } else {
111            // Scalar requested
112            CParameter::doGetValue(strValue, getOffset() + index * getSize(),
113                                   parameterAccessContext);
114        }
115    }
116
117    return true;
118}
119
120/// Actual parameter access
121// String access
122bool CArrayParameter::doSetValue(const string &value, size_t offset,
123                                 CParameterAccessContext &parameterAccessContext) const
124{
125    return setValues(0, offset, value, parameterAccessContext);
126}
127
128void CArrayParameter::doGetValue(string &value, size_t offset,
129                                 CParameterAccessContext &parameterAccessContext) const
130{
131    // Whole array requested
132    value = getValues(offset, parameterAccessContext);
133}
134
135// Boolean
136bool CArrayParameter::access(std::vector<bool> &abValues, bool bSet,
137                             CParameterAccessContext &parameterAccessContext) const
138{
139    return accessValues(abValues, bSet, parameterAccessContext);
140}
141
142// Integer
143bool CArrayParameter::access(std::vector<uint32_t> &auiValues, bool bSet,
144                             CParameterAccessContext &parameterAccessContext) const
145{
146    return accessValues(auiValues, bSet, parameterAccessContext);
147}
148
149// Signed Integer Access
150bool CArrayParameter::access(std::vector<int32_t> &aiValues, bool bSet,
151                             CParameterAccessContext &parameterAccessContext) const
152{
153    return accessValues(aiValues, bSet, parameterAccessContext);
154}
155
156// Double Access
157bool CArrayParameter::access(std::vector<double> &adValues, bool bSet,
158                             CParameterAccessContext &parameterAccessContext) const
159{
160    return accessValues(adValues, bSet, parameterAccessContext);
161}
162
163// String Access
164bool CArrayParameter::access(std::vector<string> &astrValues, bool bSet,
165                             CParameterAccessContext &parameterAccessContext) const
166{
167    return accessValues(astrValues, bSet, parameterAccessContext);
168}
169
170// Dump
171string CArrayParameter::logValue(CParameterAccessContext &context) const
172{
173    // Dump values
174    return getValues(0, context);
175}
176
177// Used for simulation and virtual subsystems
178void CArrayParameter::setDefaultValues(CParameterAccessContext &parameterAccessContext) const
179{
180    // Get default value from type
181    uint32_t uiDefaultValue =
182        static_cast<const CParameterType *>(getTypeElement())->getDefaultValue();
183
184    // Write blackboard
185    CParameterBlackboard *pBlackboard = parameterAccessContext.getParameterBlackboard();
186
187    // Process
188    size_t valueIndex;
189    size_t size = getSize();
190    size_t offset = getOffset();
191    size_t arrayLength = getArrayLength();
192
193    for (valueIndex = 0; valueIndex < arrayLength; valueIndex++) {
194
195        // Beware this code works on little endian architectures only!
196        pBlackboard->writeInteger(&uiDefaultValue, size, offset);
197
198        offset += size;
199    }
200}
201
202// Index from path
203bool CArrayParameter::getIndex(CPathNavigator &pathNavigator, size_t &index,
204                               CParameterAccessContext &parameterAccessContext) const
205{
206    index = (size_t)-1;
207
208    string *pStrChildName = pathNavigator.next();
209
210    if (pStrChildName) {
211
212        // Check index is numeric
213        std::istringstream iss(*pStrChildName);
214
215        iss >> index;
216
217        if (!iss) {
218
219            parameterAccessContext.setError("Expected numerical expression as last item in " +
220                                            pathNavigator.getCurrentPath());
221
222            return false;
223        }
224
225        if (index >= getArrayLength()) {
226            std::ostringstream oss;
227
228            oss << "Provided index out of range (max is " << getArrayLength() - 1 << ")";
229
230            parameterAccessContext.setError(oss.str());
231
232            return false;
233        }
234
235        // Check no other item provided in path
236        pStrChildName = pathNavigator.next();
237
238        if (pStrChildName) {
239
240            // Should be leaf element
241            parameterAccessContext.setError("Path not found: " + pathNavigator.getCurrentPath());
242
243            return false;
244        }
245    }
246
247    return true;
248}
249
250// Common set value processing
251bool CArrayParameter::setValues(size_t uiStartIndex, size_t offset, const string &strValue,
252                                CParameterAccessContext &parameterAccessContext) const
253{
254    // Deal with value(s)
255    Tokenizer tok(strValue, Tokenizer::defaultDelimiters + ",");
256
257    std::vector<string> astrValues = tok.split();
258    size_t nbValues = astrValues.size();
259
260    // Check number of provided values
261    if (nbValues + uiStartIndex > getArrayLength()) {
262
263        // Out of bounds
264        parameterAccessContext.setError("Too many values provided");
265
266        return false;
267    }
268
269    // Process
270    size_t valueIndex;
271    size_t size = getSize();
272    offset += uiStartIndex * size;
273
274    for (valueIndex = 0; valueIndex < nbValues; valueIndex++) {
275
276        if (!doSet(astrValues[valueIndex], offset, parameterAccessContext)) {
277
278            // Append parameter path to error
279            parameterAccessContext.appendToError(" " + getPath() + "/" +
280                                                 std::to_string(valueIndex + uiStartIndex));
281
282            return false;
283        }
284
285        offset += size;
286    }
287    return true;
288}
289
290// Common get value processing
291string CArrayParameter::getValues(size_t offset,
292                                  CParameterAccessContext &parameterAccessContext) const
293{
294    size_t size = getSize();
295    size_t arrayLength = getArrayLength();
296
297    string output;
298
299    bool bFirst = true;
300
301    for (size_t valueIndex = 0; valueIndex < arrayLength; valueIndex++) {
302        string strReadValue;
303
304        doGet(strReadValue, offset, parameterAccessContext);
305
306        if (!bFirst) {
307
308            output += " ";
309        } else {
310
311            bFirst = false;
312        }
313
314        output += strReadValue;
315
316        offset += size;
317    }
318
319    return output;
320}
321
322// Generic Access
323template <typename type>
324bool CArrayParameter::accessValues(std::vector<type> &values, bool bSet,
325                                   CParameterAccessContext &parameterAccessContext) const
326{
327    if (bSet) {
328
329        // Set Value
330        if (!setValues(values, parameterAccessContext)) {
331
332            appendParameterPathToError(parameterAccessContext);
333            return false;
334        }
335        if (!sync(parameterAccessContext)) {
336
337            appendParameterPathToError(parameterAccessContext);
338            return false;
339        }
340    } else {
341        // Get Value
342        if (!getValues(values, parameterAccessContext)) {
343
344            appendParameterPathToError(parameterAccessContext);
345            return false;
346        }
347    }
348    return true;
349}
350
351template <typename type>
352bool CArrayParameter::setValues(const std::vector<type> &values,
353                                CParameterAccessContext &parameterAccessContext) const
354{
355    size_t nbValues = getArrayLength();
356    size_t size = getSize();
357    size_t offset = getOffset();
358
359    assert(values.size() == nbValues);
360
361    // Process
362    for (size_t valueIndex = 0; valueIndex < nbValues; valueIndex++) {
363
364        if (!doSet(values[valueIndex], offset, parameterAccessContext)) {
365
366            return false;
367        }
368
369        offset += size;
370    }
371
372    return true;
373}
374
375template <typename type>
376bool CArrayParameter::getValues(std::vector<type> &values,
377                                CParameterAccessContext &parameterAccessContext) const
378{
379    size_t nbValues = getArrayLength();
380    size_t size = getSize();
381    size_t offset = getOffset();
382
383    values.clear();
384
385    for (size_t valueIndex = 0; valueIndex < nbValues; valueIndex++) {
386        type readValue;
387
388        if (!doGet(readValue, offset, parameterAccessContext)) {
389
390            return false;
391        }
392
393        values.push_back(readValue);
394
395        offset += size;
396    }
397    return true;
398}
399
400template <typename type>
401bool CArrayParameter::doSet(type value, size_t offset,
402                            CParameterAccessContext &parameterAccessContext) const
403{
404    uint32_t uiData;
405
406    if (!static_cast<const CParameterType *>(getTypeElement())
407             ->toBlackboard(value, uiData, parameterAccessContext)) {
408
409        return false;
410    }
411    // Write blackboard
412    CParameterBlackboard *pBlackboard = parameterAccessContext.getParameterBlackboard();
413
414    // Beware this code works on little endian architectures only!
415    pBlackboard->writeInteger(&uiData, getSize(), offset);
416
417    return true;
418}
419
420template <typename type>
421bool CArrayParameter::doGet(type &value, size_t offset,
422                            CParameterAccessContext &parameterAccessContext) const
423{
424    uint32_t uiData = 0;
425
426    // Read blackboard
427    const CParameterBlackboard *pBlackboard = parameterAccessContext.getParameterBlackboard();
428
429    // Beware this code works on little endian architectures only!
430    pBlackboard->readInteger(&uiData, getSize(), offset);
431
432    return static_cast<const CParameterType *>(getTypeElement())
433        ->fromBlackboard(value, uiData, parameterAccessContext);
434}
435