Changeset View
Standalone View
src/amount.h
// Copyright (c) 2009-2010 Satoshi Nakamoto | // Copyright (c) 2009-2010 Satoshi Nakamoto | ||||
// Copyright (c) 2009-2016 The Bitcoin Core developers | // Copyright (c) 2009-2016 The Bitcoin Core developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#ifndef BITCOIN_AMOUNT_H | #ifndef BITCOIN_AMOUNT_H | ||||
#define BITCOIN_AMOUNT_H | #define BITCOIN_AMOUNT_H | ||||
#include "serialize.h" | #include "serialize.h" | ||||
#include <cstdlib> | #include <cstdlib> | ||||
#include <iostream> | |||||
CCulianu: You might also want to #include <type_traits> here for header paranoia. std::enable_if lives… | |||||
schancelAuthorUnsubmitted Done Inline ActionsWill do. schancel: Will do. | |||||
#include <string> | #include <string> | ||||
struct CAmountNew { | |||||
private: | |||||
int64_t amount; | |||||
public: | |||||
CAmountNew() : amount(0) {} | |||||
template <typename T, typename std::enable_if<(std::is_integral<T>::value), | |||||
T>::type = 0> | |||||
CAmountNew(T _camount) : amount(_camount) {} | |||||
CAmountNew(const CAmountNew &_camount) : amount(_camount.amount) {} | |||||
// Allow access to underlying value for non-monetary operations | |||||
int64_t GetSatoshis() const { return amount; } | |||||
/* | |||||
* Implement standard operators | |||||
*/ | |||||
CAmountNew &operator+=(const CAmountNew a) { | |||||
CCulianuUnsubmitted Done Inline ActionsSuggest: pass by reference eg const CAmountNew & in all of these. CCulianu: Suggest: pass by reference eg
```const CAmountNew &```
in all of these. | |||||
deadalnixUnsubmitted Done Inline ActionsI don't think it is really necessary. This clearly work as a value type better than as a reference type. Now, because C++ doesn't differentiate between the 2 but if you get it wrong you'll regret it dearly (see slicing for instance) it's probably a good idea to come up with some naming convention that distinguish the 2. I suggest ISomething for interfaces, CSomething for reference type kind of classes and no prefix for value types. We assume value type are cheap to copy and if they aren't, make them non copiable by default. Does that work ? If so, then this class should just be named Amount deadalnix: I don't think it is really necessary. This clearly work as a value type better than as a… | |||||
schancelAuthorUnsubmitted Done Inline ActionsI'll make that change. schancel: I'll make that change. | |||||
amount += a.amount; | |||||
return *this; | |||||
} | |||||
CAmountNew &operator-=(const CAmountNew a) { | |||||
CCulianuUnsubmitted Done Inline ActionsDitto... and ditto for all the operators below. CCulianu: Ditto... and ditto for all the operators below. | |||||
amount -= a.amount; | |||||
return *this; | |||||
} | |||||
friend bool operator<(const CAmountNew a, const CAmountNew b) { | |||||
return a.amount < b.amount; | |||||
} | |||||
friend bool operator>(const CAmountNew a, const CAmountNew b) { | |||||
CCulianuUnsubmitted Done Inline ActionsSuggest: Implementing the real comparison only for operator< and operator== and then making operator >,<=, >=, != all be implemented in terms of those 2 basic operators. Eg: operator<=(lhs, rhs) { return !(lhs > rhs); } operator>=(lhs, rhs) { return !(lhs < rhs); } operator>(lhs, rhs) { return rhs < lhs; } operator!=(lhs, rhs) { return !(lhs == rhs); } CCulianu: Suggest: Implementing the real comparison only for operator< and operator== and then making… | |||||
schancelAuthorUnsubmitted Done Inline ActionsSGTM. Will do schancel: SGTM. Will do | |||||
return a.amount > b.amount; | |||||
} | |||||
friend bool operator==(const CAmountNew a, const CAmountNew b) { | |||||
return a.amount == b.amount; | |||||
} | |||||
friend bool operator!=(const CAmountNew a, const CAmountNew b) { | |||||
return a.amount != b.amount; | |||||
} | |||||
friend bool operator<=(const CAmountNew a, const CAmountNew b) { | |||||
return a.amount <= b.amount; | |||||
} | |||||
friend bool operator>=(const CAmountNew a, const CAmountNew b) { | |||||
return a.amount >= b.amount; | |||||
} | |||||
friend CAmountNew operator+(const CAmountNew a, const CAmountNew b) { | |||||
return CAmountNew(a.amount + b.amount); | |||||
} | |||||
friend CAmountNew operator-(const CAmountNew a, const CAmountNew b) { | |||||
return CAmountNew(a.amount - b.amount); | |||||
} | |||||
// Implemented for allowing COIN as a base unit. | |||||
template <typename T, typename std::enable_if<(std::is_integral<T>::value), | |||||
T>::type = 0> | |||||
friend CAmountNew operator*(const T a, const CAmountNew b) { | |||||
return CAmountNew(a * b.amount); | |||||
} | |||||
// Used for converting to a string | |||||
template <typename T, typename std::enable_if<(std::is_integral<T>::value), | |||||
T>::type = 0> | |||||
friend T operator/(const CAmountNew a, const T b) { | |||||
return T(a.amount) / b; | |||||
} | |||||
// Used for converting to a string | |||||
template <typename T, typename std::enable_if<(std::is_integral<T>::value), | |||||
T>::type = 0> | |||||
friend T operator%(const CAmountNew a, const T b) { | |||||
CCulianuUnsubmitted Done Inline ActionsQuestion: Why are all of these friends and not just member functions? Any reason? CCulianu: Question: Why are all of these friends and not just member functions?
Any reason?
| |||||
CCulianuUnsubmitted Done Inline ActionsNevermind: I see you want to take advantage of implicit conversion etc so yeah you need friend for these. CCulianu: Nevermind: I see you want to take advantage of implicit conversion etc so yeah you need friend… | |||||
return T(a.amount) % b; | |||||
} | |||||
// ostream support | |||||
friend std::ostream &operator<<(std::ostream &stream, | |||||
const CAmountNew &ca) { | |||||
return stream << ca.amount; | |||||
} | |||||
std::string ToString() const; | |||||
// serialization support | |||||
ADD_SERIALIZE_METHODS; | |||||
template <typename Stream, typename Operation> | |||||
inline void SerializationOp(Stream &s, Operation ser_action) { | |||||
READWRITE(amount); | |||||
} | |||||
}; | |||||
/** Amount in satoshis (Can be negative) */ | /** Amount in satoshis (Can be negative) */ | ||||
typedef int64_t CAmount; | typedef int64_t CAmount; | ||||
static const CAmount COIN = 100000000; | static const CAmountNew COIN = 100000000; | ||||
static const CAmount CENT = 1000000; | static const CAmountNew CENT = 1000000; | ||||
extern const std::string CURRENCY_UNIT; | extern const std::string CURRENCY_UNIT; | ||||
/** | /** | ||||
* No amount larger than this (in satoshi) is valid. | * No amount larger than this (in satoshi) is valid. | ||||
* | * | ||||
* Note that this constant is *not* the total money supply, which in Bitcoin | * Note that this constant is *not* the total money supply, which in Bitcoin | ||||
* currently happens to be less than 21,000,000 BCC for various reasons, but | * currently happens to be less than 21,000,000 BCC for various reasons, but | ||||
* rather a sanity check. As this sanity check is used by consensus-critical | * rather a sanity check. As this sanity check is used by consensus-critical | ||||
* validation code, the exact value of the MAX_MONEY constant is consensus | * validation code, the exact value of the MAX_MONEY constant is consensus | ||||
* critical; in unusual circumstances like a(nother) overflow bug that allowed | * critical; in unusual circumstances like a(nother) overflow bug that allowed | ||||
* for the creation of coins out of thin air modification could lead to a fork. | * for the creation of coins out of thin air modification could lead to a fork. | ||||
*/ | */ | ||||
static const CAmount MAX_MONEY = 21000000 * COIN; | static const CAmountNew MAX_MONEY = 21000000 * COIN; | ||||
inline bool MoneyRange(const CAmount &nValue) { | inline bool MoneyRange(const CAmount &nValue) { | ||||
return (nValue >= 0 && nValue <= MAX_MONEY); | return (nValue >= 0 && nValue <= MAX_MONEY); | ||||
} | } | ||||
/** | /** | ||||
* Fee rate in satoshis per kilobyte: CAmount / kB | * Fee rate in satoshis per kilobyte: CAmount / kB | ||||
*/ | */ | ||||
class CFeeRate { | class CFeeRate { | ||||
▲ Show 20 Lines • Show All 53 Lines • Show Last 20 Lines |
You might also want to #include <type_traits> here for header paranoia. std::enable_if lives in <type_traits> and as it happens now it got pulled in for us -- but this is not guaranteed into the infinite future of C++ impl's.. so I would suggest explicitly including the <type_traits> header.