File: decimalfield.h

package info (click to toggle)
amqp-cpp 4.3.27-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 1,384 kB
  • sloc: cpp: 10,021; ansic: 191; makefile: 95
file content (242 lines) | stat: -rw-r--r-- 5,492 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
/**
 *  Decimal field type for AMQP
 *
 *  @copyright 2014 - 2020 Copernica BV
 */

/**
 *  Include guard
 */
#pragma once

/**
 *  Dependencies
 */
#include <cmath>
#include <ostream>
#include "field.h"
#include "outbuffer.h"
#include "inbuffer.h"

/**
 *  Set up namespace
 */
namespace AMQP {

/**
 *  Class implementation
 */
class DecimalField : public Field
{
/**
 *  To preserve precision the decision is made to work with the places and number.
 *  These values are sent in the framedata, so no precision will be lost.
 *  Other options, such as floats, doubles, Decimal32 etc result in loss of precision
 *  and this is something which is not acceptable.
 *
 *  Only (in)equality and assignment operators are implemented since the decimalfield
 *  is not supposed to be altered.
 *  e.q. ==, != and =
 *
 *  When requesting the value of this object there are 3 choices;
 *  float, double or DecimalField
 *  e.g. valueFloat(), valueDouble() and value()
 */
private:
    /**
     *  The number of places, which means the number of decimals
     *  e.g. number = 1234, places = 2, true value is 12.34
     */
    uint8_t _places;

    /**
     *  The number without the decimals
     */
    uint32_t _number;

protected:
    /**
     *  Write encoded payload to the given buffer.
     */
    virtual void fill(OutBuffer& buffer) const override
    {
        // encode fields
        buffer.add(_places);
        buffer.add(_number);
    }

public:
    /**
     *  Construct decimal field
     *
     *  @param  places  the number of places
     *  @param  number  the integer number
     */
    DecimalField(uint8_t places = 0, uint32_t number = 0) :
        _places(places),
        _number(number)
    {}

    /**
     *  Construct based on incoming data
     *  @param  frame
     */
    DecimalField(InBuffer &frame)
    {
        _places = frame.nextUint8();
        _number = frame.nextUint32();
    }

    /**
     *  Destructor
     */
    virtual ~DecimalField() {}

    /**
     *  Create a new identical instance of this object
     *  @return unique_ptr
     */
    virtual std::unique_ptr<Field> clone() const override
    {
        return std::unique_ptr<Field>(new DecimalField(_places, _number));
    }

    /**
     *  Output the object to a stream
     *  @param std::ostream
     */
    virtual void output(std::ostream &stream) const override
    {
        // output floating point value
        stream << "decimal(" << _number / pow(10.0f, _places) << ")";
    }

    /**
     *  Assign a new value
     *
     *  @param  value   new value for field
     *  @return DecimalField
     */
    DecimalField& operator=(const DecimalField& value)
    {
        // if it's the same object, skip assignment and just return *this
        if (this == &value) return *this;

        // not the same object, copy values to this object.
        _places = value._places;
        _number = value._number;

        // allow chaining
        return *this;
    }

    /**
     *  Casts decimalfield to double
     *  e.g. "double x = decimalfield" will work
     *
     *  @return  double     value of decimalfield in double format
     */
    virtual operator double() const override
    {
        return _number / pow(10.0f, _places);
    }

    /**
     *  Casts decimalfield to float
     *  e.g. "float x = decimalfield" will work
     *
     *  @return  float     value of decimalfield in float format
     */
    virtual operator float() const override
    {
        return static_cast<float>(_number / pow(10.0f, _places));
    }

    /**
     *  Check for equality between this and another DecimalField
     *
     *  @param  value   value to be checked for equality
     *  @return boolean whether values are equal
     */
    bool operator==(const DecimalField& value) const
    {
        // check if everything is the same
        // precision is taken into account, e.q. 1.0 != 1.00
        // meaning number:10, places:1 is not equal to number:100, places:2
        return _number == value.number() && _places == value.places();
    }

    /**
     *  Check for inequality between this and another DecimalField
     *
     *  @param  value    value to be checked for inequality
     *  @return boolean  whether values are inequal
     */
    bool operator!=(const DecimalField& value) const
    {
        return !(*this == value);
    }

    /**
     *  Get the size this field will take when
     *  encoded in the AMQP wire-frame format
     */
    virtual size_t size() const override
    {
        // the sum of all fields
        return 5;
    }

    /**
     *  Get the number of places
     *  @return uint8_t
     */
    uint8_t places() const
    {
        return _places;
    }

    /**
     *  Get the number without decimals
     *  @return uint32_t
     */
    uint32_t number() const
    {
        return _number;
    }

    /**
     *  Return the DecimalField
     *  To preserve precision DecimalField is returned, containing the number and places.
     *  @return return DecimalField
     */
    DecimalField value() const
    {
        return *this;
    }

    /**
     *  We are a decimal field
     *
     *  @return true, because we are a decimal field
     */
    bool isDecimal() const override
    {
        return true;
    }

    /**
     *  Get the type ID that is used to identify this type of
     *  field in a field table
     */
    virtual char typeID() const override
    {
        return 'D';
    }
};

/**
 *  end namespace
 */
}