/** * Decimal field type for AMQP * * @copyright 2014 Copernica BV */ /** * Include guard */ #pragma once /** * 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(ReceivedFrame &frame) { _places = frame.nextUint8(); _number = frame.nextUint32(); } /** * Destructor */ virtual ~DecimalField() {} /** * Create a new identical instance of this object * @return Field* */ virtual std::shared_ptr clone() const override { return std::make_shared(_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, _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 */ operator double() const { return _number / pow(10, _places); } /** * Casts decimalfield to float * e.g. "float x = decimalfield" will work * * @return float value of decimalfield in float format */ operator float() const { return static_cast(_number / pow(10, _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 */ }