How to make my “custom integer type” perform better?Comparing sets of different types using variantsTrying to find a good design for reading in values of different types from a fileVariadic template data pack strucuture designed for debug/trace log (variable-sized records)Array-like container for uints shorter than 8 bits (Rev 1)Storing collections of objects of any typeCheck if a string is palindrome or two strings are the opposite of each otherProtected Pointer: a unique_ptr wrapper that auto encrypts and decrypts data in memoryType-safe flag sets (bit fields) that make senseC++ std::array wrapperEmulating Virtual Registers Part 3

Who are the people reviewing far more papers than they're submitting for review?

Asked to Not Use Transactions and to Use A Workaround to Simulate One

Is it appropriate to CC a lot of people on an email?

Python web-scraper to download table of transistor counts from Wikipedia

Seven Places at Once - Another Google Earth Challenge?

How to make my “custom integer type” perform better?

Pronunciation of "солнце"

What was the ultimate objective of The Party in 1984?

What does this Blight Tower UI mean?

Transit visa to Hong Kong

How would you translate Evangelii Nuntiandi?

Why does '/' contain '..'?

Is there a generally agreed upon solution to Bradley's Infinite Regress without appeal to Paraconsistent Logic?

Teleport everything in a large zone; or teleport all living things and make a lot of equipment disappear

What is the word for a person who destroys monuments?

How would co-authoring a paper whose main subject isn't about what I'll do in the future help me?

What's the benefit of prohibiting the use of techniques/language constructs that have not been taught?

Exam design: give maximum score per question or not?

Why is the year in this ISO timestamp not 2019?

Are there any “Third Order” acronyms used in space exploration?

A Pixelated Sequence - Find the Continuation

Statistical tests for benchmark comparison

Output Distinct Factor Cuboids

Why does JavaScript convert an array of one string to a string, when used as an object key?



How to make my “custom integer type” perform better?


Comparing sets of different types using variantsTrying to find a good design for reading in values of different types from a fileVariadic template data pack strucuture designed for debug/trace log (variable-sized records)Array-like container for uints shorter than 8 bits (Rev 1)Storing collections of objects of any typeCheck if a string is palindrome or two strings are the opposite of each otherProtected Pointer: a unique_ptr wrapper that auto encrypts and decrypts data in memoryType-safe flag sets (bit fields) that make senseC++ std::array wrapperEmulating Virtual Registers Part 3






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;








3












$begingroup$


During a project at my work I needed a convenient way to store values taking up the smallest amount of bits necessary, not in memory but later when they're serialized into an array of unsigned short ints. For instance, a value that could be between 0 and 7 was only supposed to be 3 bits long. I ended up developing my own solution based on std::bitset with some additional code in order to make it work with signed values. Another goal was to make it work as close to a regular integer type as possible. This is the code (https://github.com/AndersHogqvist/custom_int):



#include <bitset>
#include <type_traits>

template<size_t Size>
class TypeBase
public:
size_t size() const
return data_.size();


unsigned long to_ulong() const
return data_.to_ulong();


unsigned long long to_ullong() const
return data_.to_ullong();


std::bitset<Size> data() const
return data_;


std::string to_string() const
return data_.to_string();


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
TypeBase<Size> &operator=(const T value)
data_ = std::bitset<Size>(value);
return *this;


bool operator==(const TypeBase<Size> &other) const
return data_ == other.data();


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
bool operator==(const T value) const
return data_.to_ullong() == value;


bool operator!=(const TypeBase<Size> &other) const
return !(*this == other);


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
bool operator!=(const T value) const
return data_ != std::bitset<Size>(value);


bool operator<(const TypeBase<Size> &other) const
if (data_ == other.data_)
return false;

return less_than_(other.data_);


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
bool operator<(const T value) const
return less_than_(std::bitset<Size>(value));


bool operator<=(const TypeBase<Size> &other) const
if (data_ == other.data_)
return true;

return less_than_or_eq_(other.data_);


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
bool operator<=(const T value) const
return less_than_or_eq_(std::bitset<Size>(value));


bool operator>(const TypeBase<Size> &other) const
if (data_ == other.data_)
return false;

return greater_than_(other.data_);


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
bool operator>(const T value) const
return greater_than_(std::bitset<Size>(value));


bool operator>=(const TypeBase<Size> &other) const
if (data_ == other.data_)
return true;

return greater_than_or_eq_(other.data_);


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
bool operator>=(const T value) const
return greater_than_or_eq_(std::bitset<Size>(value));


TypeBase<Size> &operator+(const TypeBase<Size> &other)
bool carry = false;
for (size_t ix = 0; ix < Size; ++ix)
data_[ix] = add_(data_[ix], other.data_[ix], carry);

return *this;


TypeBase<Size> &operator+(const std::bitset<Size> &other)
bool carry = false;
for (size_t ix = 0; ix < Size; ++ix)
data_[ix] = add_(data_[ix], other[ix], carry);

return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
TypeBase<Size> &operator+(const T value)
bool carry = false;
std::bitset<Size> other(value);
for (size_t ix = 0; ix < Size; ++ix)
data_[ix] = add_(data_[ix], other[ix], carry);

return *this;


TypeBase<Size> &operator+=(const TypeBase<Size> &other)
bool carry = false;
for (size_t ix = 0; ix < Size; ++ix)
data_[ix] = add_(data_[ix], other.data_[ix], carry);

return *this;


TypeBase<Size> &operator+=(const std::bitset<Size> &other)
bool carry = false;
for (size_t ix = 0; ix < Size; ++ix)
data_[ix] = add_(data_[ix], other[ix], carry);

return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
TypeBase<Size> &operator+=(const T value)
bool carry = false;
std::bitset<Size> other(value);
for (size_t ix = 0; ix < Size; ++ix)
data_[ix] = add_(data_[ix], other[ix], carry);

return *this;


TypeBase<Size> &operator++(int)
bool carry = false;
std::bitset<Size> other(1);
for (size_t ix = 0; ix < Size; ++ix)
data_[ix] = add_(data_[ix], other[ix], carry);

return *this;


TypeBase<Size> &operator-(const TypeBase<Size> &other)
subtract_(other.data_);
return *this;


TypeBase<Size> &operator-(const std::bitset<Size> &other)
subtract_(other);
return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
TypeBase<Size> &operator-(const T value)
subtract_(std::bitset<Size>(value));
return *this;


TypeBase<Size> &operator-=(const TypeBase<Size> &other)
subtract_(other.data_);
return *this;


TypeBase<Size> &operator-=(const std::bitset<Size> &other)
subtract_(other);
return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
TypeBase<Size> &operator-=(const T value)
subtract_(std::bitset<Size>(value));
return *this;


TypeBase<Size> &operator--(int)
subtract_(std::bitset<Size>(1));
return *this;


TypeBase<Size> &operator*(const TypeBase<Size> &other)
multiply_(other.data_);
return *this;


TypeBase<Size> &operator*(const std::bitset<Size> &other)
multiply_(other);
return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
TypeBase<Size> &operator*(const T value)
multiply_(std::bitset<Size>(value));
return *this;


TypeBase<Size> &operator*=(const TypeBase<Size> &other)
multiply_(other.data_);
return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
TypeBase<Size> &operator*=(const T value)
multiply_(std::bitset<Size>(value));
return *this;


TypeBase<Size> &operator/(const TypeBase<Size> &other)
data_ = data_.to_ullong() / other.to_ullong();
return *this;


TypeBase<Size> &operator/(const std::bitset<Size> &other)
data_ = data_.to_ullong() / other.to_ullong();
return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
TypeBase<Size> &operator/(const T value)
data_ = data_.to_ullong() / value;
return *this;


TypeBase<Size> &operator/=(const TypeBase<Size> &other)
data_ = data_.to_ullong() / other.to_ullong();
return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
TypeBase<Size> &operator/=(const T value)
data_ = data_.to_ullong() / value;
return *this;


template<size_t S>
friend std::ostream &operator <<(std::ostream &out, const TypeBase<S> &u);
protected:
TypeBase() = default;
~TypeBase() = default;

std::bitset<Size> data_;

bool add_(bool b1, bool b2, bool &carry)

void subtract_(const std::bitset<Size> &other)
bool borrow = false;
for (int i = 0; i < Size; i++)
if (borrow)
if (data_[i])
data_[i] = other[i];
borrow = other[i];

else
data_[i] = !other[i];
borrow = true;


else
if (data_[i])
data_[i] = !other[i];
borrow = false;

else
data_[i] = other[i];
borrow = other[i];





void multiply_(const std::bitset<Size> &other)
std::bitset<Size> tmp = data_;
data_.reset();
if (tmp.count() < other.count())
for (int i = 0; i < Size; i++)
if (tmp[i])
operator+=(other << i);



else
for (int i = 0; i < Size; i++)
if (other[i])
operator+=(tmp << i);





bool less_than_or_eq_(const std::bitset<Size> &other) const
for (int i = Size - 1; i >= 0; i--)
if (data_[i] && !other[i])
return false;

if (!data_[i] && other[i])
return true;


return true;


bool less_than_(const std::bitset<Size> &other) const
for (int i = Size - 1; i >= 0; i--)
if (data_[i] && !other[i])
return false;

if (!data_[i] && other[i])
return true;


return false;


bool greater_than_or_eq_(const std::bitset<Size> &other) const
for (int i = Size - 1; i >= 0; i--)
if (data_[i] && !other[i])
return true;

if (!data_[i] && other[i])
return false;


return true;


bool greater_than_(const std::bitset<Size> &other) const
for (int i = Size - 1; i >= 0; i--)
if (data_[i] && !other[i])
return true;

if (!data_[i] && other[i])
return false;


return false;

;

template<size_t Size>
class Int : public TypeBase<Size>
public:
Int() = default;

template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
Int(const T value)
TypeBase<Size>::operator=(value);


~Int() = default;

Int<Size> &operator=(const TypeBase<Size> &other)
if (this->data_ == other.data())
return *this;

this->data_ = other.data();
return *this;


long long to_int() const
if (this->data_[Size - 1])
std::bitset<Size> tmp = this->data_;
tmp.flip();
return tmp.to_ullong() * -1 - 1;

return this->data_.to_ullong();


Int<Size> &operator/(const TypeBase<Size> &other)
this->data_ = to_int() / other.to_ullong();
return *this;


Int<Size> &operator/(const std::bitset<Size> &other)
this->data_ = to_int() / other.to_ullong();
return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
Int<Size> &operator/(const T value)
this->data_ = to_int() / value;
return *this;


Int<Size> &operator/=(const TypeBase<Size> &other)
this->data_ = to_int() / other.to_ullong();
return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
Int<Size> &operator/=(const T value)
this->data_ = to_int() / value;
return *this;

;

template<size_t Size>
std::ostream &operator<<(std::ostream &out, const Int<Size> &u)
out << u.to_int();
return out;


template<size_t Size>
class UInt : public TypeBase<Size>
public:
UInt() = default;

template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
UInt(const T value)
TypeBase<Size>::operator=(value);


~UInt() = default;

UInt<Size> &operator=(const TypeBase<Size> &other)
if (this->data_ == other.data())
return *this;

this->data_ = other.data();
return *this;


unsigned long long to_int() const
return this->data_.to_ullong();

;

template<size_t Size>
std::ostream &operator<<(std::ostream &out, const UInt<Size> &u)
out << u.to_ullong();
return out;



Here are some examples on how it's supposed to be used:



#include <iostream>

#include "custom_int.h"

using namespace std;

int main()
Int<13> test1 = 1;
UInt<5> test2;

cout << "test1: " << test1 << endl;
cout << "test2: " << test2 << endl;

test1++;
cout << "test1: " << test1 << endl;

test1--;
cout << "test1: " << test1 << endl;

test1 -= 10;
cout << "test1: " << test1 << endl;

auto test3 = test1;

cout << "test3: " << test3 << endl;

test3 /= 3;

cout << "test3: " << test3 << endl;

test2 += 20;

cout << "test2: " << test2 << endl;

test2 = test2 / 10;

cout << "test2: " << test2 << endl;



I'm by no means a seasoned C++ developer, so even if I believe it's working the way it should I would love to have some input on what can be improved.



What I'm mostly concerned about is the performance (unnecessary copying etc). It's supposed to be used in a real time application so I need it to be as fast as possible.










share|improve this question









New contributor



Zenit_swe is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






$endgroup$













  • $begingroup$
    Is it intended to work for integers wider than unsigned long long?
    $endgroup$
    – harold
    7 hours ago










  • $begingroup$
    @harold, in my project I was handling up to 64 bit unsigned ints, so i haven't really thought about anything larger than that.
    $endgroup$
    – Zenit_swe
    7 hours ago






  • 1




    $begingroup$
    I rolled back your last edit. Editing code after the answer was posted is against the CR policy, because it invalidates the answer.
    $endgroup$
    – vnp
    5 hours ago










  • $begingroup$
    sorry for that @vnp
    $endgroup$
    – Zenit_swe
    4 hours ago






  • 1




    $begingroup$
    Please do not update the code in your question to incorporate feedback from answers, doing so goes against the Question + Answer style of Code Review. This is not a forum where you should keep the most updated version in your question. Please see what you may and may not do after receiving answers. If your code has significantly improved, preferably with edits of yourself as well, you could ask a new question, a follow-up.
    $endgroup$
    – Mast
    4 hours ago

















3












$begingroup$


During a project at my work I needed a convenient way to store values taking up the smallest amount of bits necessary, not in memory but later when they're serialized into an array of unsigned short ints. For instance, a value that could be between 0 and 7 was only supposed to be 3 bits long. I ended up developing my own solution based on std::bitset with some additional code in order to make it work with signed values. Another goal was to make it work as close to a regular integer type as possible. This is the code (https://github.com/AndersHogqvist/custom_int):



#include <bitset>
#include <type_traits>

template<size_t Size>
class TypeBase
public:
size_t size() const
return data_.size();


unsigned long to_ulong() const
return data_.to_ulong();


unsigned long long to_ullong() const
return data_.to_ullong();


std::bitset<Size> data() const
return data_;


std::string to_string() const
return data_.to_string();


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
TypeBase<Size> &operator=(const T value)
data_ = std::bitset<Size>(value);
return *this;


bool operator==(const TypeBase<Size> &other) const
return data_ == other.data();


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
bool operator==(const T value) const
return data_.to_ullong() == value;


bool operator!=(const TypeBase<Size> &other) const
return !(*this == other);


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
bool operator!=(const T value) const
return data_ != std::bitset<Size>(value);


bool operator<(const TypeBase<Size> &other) const
if (data_ == other.data_)
return false;

return less_than_(other.data_);


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
bool operator<(const T value) const
return less_than_(std::bitset<Size>(value));


bool operator<=(const TypeBase<Size> &other) const
if (data_ == other.data_)
return true;

return less_than_or_eq_(other.data_);


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
bool operator<=(const T value) const
return less_than_or_eq_(std::bitset<Size>(value));


bool operator>(const TypeBase<Size> &other) const
if (data_ == other.data_)
return false;

return greater_than_(other.data_);


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
bool operator>(const T value) const
return greater_than_(std::bitset<Size>(value));


bool operator>=(const TypeBase<Size> &other) const
if (data_ == other.data_)
return true;

return greater_than_or_eq_(other.data_);


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
bool operator>=(const T value) const
return greater_than_or_eq_(std::bitset<Size>(value));


TypeBase<Size> &operator+(const TypeBase<Size> &other)
bool carry = false;
for (size_t ix = 0; ix < Size; ++ix)
data_[ix] = add_(data_[ix], other.data_[ix], carry);

return *this;


TypeBase<Size> &operator+(const std::bitset<Size> &other)
bool carry = false;
for (size_t ix = 0; ix < Size; ++ix)
data_[ix] = add_(data_[ix], other[ix], carry);

return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
TypeBase<Size> &operator+(const T value)
bool carry = false;
std::bitset<Size> other(value);
for (size_t ix = 0; ix < Size; ++ix)
data_[ix] = add_(data_[ix], other[ix], carry);

return *this;


TypeBase<Size> &operator+=(const TypeBase<Size> &other)
bool carry = false;
for (size_t ix = 0; ix < Size; ++ix)
data_[ix] = add_(data_[ix], other.data_[ix], carry);

return *this;


TypeBase<Size> &operator+=(const std::bitset<Size> &other)
bool carry = false;
for (size_t ix = 0; ix < Size; ++ix)
data_[ix] = add_(data_[ix], other[ix], carry);

return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
TypeBase<Size> &operator+=(const T value)
bool carry = false;
std::bitset<Size> other(value);
for (size_t ix = 0; ix < Size; ++ix)
data_[ix] = add_(data_[ix], other[ix], carry);

return *this;


TypeBase<Size> &operator++(int)
bool carry = false;
std::bitset<Size> other(1);
for (size_t ix = 0; ix < Size; ++ix)
data_[ix] = add_(data_[ix], other[ix], carry);

return *this;


TypeBase<Size> &operator-(const TypeBase<Size> &other)
subtract_(other.data_);
return *this;


TypeBase<Size> &operator-(const std::bitset<Size> &other)
subtract_(other);
return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
TypeBase<Size> &operator-(const T value)
subtract_(std::bitset<Size>(value));
return *this;


TypeBase<Size> &operator-=(const TypeBase<Size> &other)
subtract_(other.data_);
return *this;


TypeBase<Size> &operator-=(const std::bitset<Size> &other)
subtract_(other);
return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
TypeBase<Size> &operator-=(const T value)
subtract_(std::bitset<Size>(value));
return *this;


TypeBase<Size> &operator--(int)
subtract_(std::bitset<Size>(1));
return *this;


TypeBase<Size> &operator*(const TypeBase<Size> &other)
multiply_(other.data_);
return *this;


TypeBase<Size> &operator*(const std::bitset<Size> &other)
multiply_(other);
return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
TypeBase<Size> &operator*(const T value)
multiply_(std::bitset<Size>(value));
return *this;


TypeBase<Size> &operator*=(const TypeBase<Size> &other)
multiply_(other.data_);
return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
TypeBase<Size> &operator*=(const T value)
multiply_(std::bitset<Size>(value));
return *this;


TypeBase<Size> &operator/(const TypeBase<Size> &other)
data_ = data_.to_ullong() / other.to_ullong();
return *this;


TypeBase<Size> &operator/(const std::bitset<Size> &other)
data_ = data_.to_ullong() / other.to_ullong();
return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
TypeBase<Size> &operator/(const T value)
data_ = data_.to_ullong() / value;
return *this;


TypeBase<Size> &operator/=(const TypeBase<Size> &other)
data_ = data_.to_ullong() / other.to_ullong();
return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
TypeBase<Size> &operator/=(const T value)
data_ = data_.to_ullong() / value;
return *this;


template<size_t S>
friend std::ostream &operator <<(std::ostream &out, const TypeBase<S> &u);
protected:
TypeBase() = default;
~TypeBase() = default;

std::bitset<Size> data_;

bool add_(bool b1, bool b2, bool &carry)

void subtract_(const std::bitset<Size> &other)
bool borrow = false;
for (int i = 0; i < Size; i++)
if (borrow)
if (data_[i])
data_[i] = other[i];
borrow = other[i];

else
data_[i] = !other[i];
borrow = true;


else
if (data_[i])
data_[i] = !other[i];
borrow = false;

else
data_[i] = other[i];
borrow = other[i];





void multiply_(const std::bitset<Size> &other)
std::bitset<Size> tmp = data_;
data_.reset();
if (tmp.count() < other.count())
for (int i = 0; i < Size; i++)
if (tmp[i])
operator+=(other << i);



else
for (int i = 0; i < Size; i++)
if (other[i])
operator+=(tmp << i);





bool less_than_or_eq_(const std::bitset<Size> &other) const
for (int i = Size - 1; i >= 0; i--)
if (data_[i] && !other[i])
return false;

if (!data_[i] && other[i])
return true;


return true;


bool less_than_(const std::bitset<Size> &other) const
for (int i = Size - 1; i >= 0; i--)
if (data_[i] && !other[i])
return false;

if (!data_[i] && other[i])
return true;


return false;


bool greater_than_or_eq_(const std::bitset<Size> &other) const
for (int i = Size - 1; i >= 0; i--)
if (data_[i] && !other[i])
return true;

if (!data_[i] && other[i])
return false;


return true;


bool greater_than_(const std::bitset<Size> &other) const
for (int i = Size - 1; i >= 0; i--)
if (data_[i] && !other[i])
return true;

if (!data_[i] && other[i])
return false;


return false;

;

template<size_t Size>
class Int : public TypeBase<Size>
public:
Int() = default;

template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
Int(const T value)
TypeBase<Size>::operator=(value);


~Int() = default;

Int<Size> &operator=(const TypeBase<Size> &other)
if (this->data_ == other.data())
return *this;

this->data_ = other.data();
return *this;


long long to_int() const
if (this->data_[Size - 1])
std::bitset<Size> tmp = this->data_;
tmp.flip();
return tmp.to_ullong() * -1 - 1;

return this->data_.to_ullong();


Int<Size> &operator/(const TypeBase<Size> &other)
this->data_ = to_int() / other.to_ullong();
return *this;


Int<Size> &operator/(const std::bitset<Size> &other)
this->data_ = to_int() / other.to_ullong();
return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
Int<Size> &operator/(const T value)
this->data_ = to_int() / value;
return *this;


Int<Size> &operator/=(const TypeBase<Size> &other)
this->data_ = to_int() / other.to_ullong();
return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
Int<Size> &operator/=(const T value)
this->data_ = to_int() / value;
return *this;

;

template<size_t Size>
std::ostream &operator<<(std::ostream &out, const Int<Size> &u)
out << u.to_int();
return out;


template<size_t Size>
class UInt : public TypeBase<Size>
public:
UInt() = default;

template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
UInt(const T value)
TypeBase<Size>::operator=(value);


~UInt() = default;

UInt<Size> &operator=(const TypeBase<Size> &other)
if (this->data_ == other.data())
return *this;

this->data_ = other.data();
return *this;


unsigned long long to_int() const
return this->data_.to_ullong();

;

template<size_t Size>
std::ostream &operator<<(std::ostream &out, const UInt<Size> &u)
out << u.to_ullong();
return out;



Here are some examples on how it's supposed to be used:



#include <iostream>

#include "custom_int.h"

using namespace std;

int main()
Int<13> test1 = 1;
UInt<5> test2;

cout << "test1: " << test1 << endl;
cout << "test2: " << test2 << endl;

test1++;
cout << "test1: " << test1 << endl;

test1--;
cout << "test1: " << test1 << endl;

test1 -= 10;
cout << "test1: " << test1 << endl;

auto test3 = test1;

cout << "test3: " << test3 << endl;

test3 /= 3;

cout << "test3: " << test3 << endl;

test2 += 20;

cout << "test2: " << test2 << endl;

test2 = test2 / 10;

cout << "test2: " << test2 << endl;



I'm by no means a seasoned C++ developer, so even if I believe it's working the way it should I would love to have some input on what can be improved.



What I'm mostly concerned about is the performance (unnecessary copying etc). It's supposed to be used in a real time application so I need it to be as fast as possible.










share|improve this question









New contributor



Zenit_swe is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






$endgroup$













  • $begingroup$
    Is it intended to work for integers wider than unsigned long long?
    $endgroup$
    – harold
    7 hours ago










  • $begingroup$
    @harold, in my project I was handling up to 64 bit unsigned ints, so i haven't really thought about anything larger than that.
    $endgroup$
    – Zenit_swe
    7 hours ago






  • 1




    $begingroup$
    I rolled back your last edit. Editing code after the answer was posted is against the CR policy, because it invalidates the answer.
    $endgroup$
    – vnp
    5 hours ago










  • $begingroup$
    sorry for that @vnp
    $endgroup$
    – Zenit_swe
    4 hours ago






  • 1




    $begingroup$
    Please do not update the code in your question to incorporate feedback from answers, doing so goes against the Question + Answer style of Code Review. This is not a forum where you should keep the most updated version in your question. Please see what you may and may not do after receiving answers. If your code has significantly improved, preferably with edits of yourself as well, you could ask a new question, a follow-up.
    $endgroup$
    – Mast
    4 hours ago













3












3








3





$begingroup$


During a project at my work I needed a convenient way to store values taking up the smallest amount of bits necessary, not in memory but later when they're serialized into an array of unsigned short ints. For instance, a value that could be between 0 and 7 was only supposed to be 3 bits long. I ended up developing my own solution based on std::bitset with some additional code in order to make it work with signed values. Another goal was to make it work as close to a regular integer type as possible. This is the code (https://github.com/AndersHogqvist/custom_int):



#include <bitset>
#include <type_traits>

template<size_t Size>
class TypeBase
public:
size_t size() const
return data_.size();


unsigned long to_ulong() const
return data_.to_ulong();


unsigned long long to_ullong() const
return data_.to_ullong();


std::bitset<Size> data() const
return data_;


std::string to_string() const
return data_.to_string();


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
TypeBase<Size> &operator=(const T value)
data_ = std::bitset<Size>(value);
return *this;


bool operator==(const TypeBase<Size> &other) const
return data_ == other.data();


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
bool operator==(const T value) const
return data_.to_ullong() == value;


bool operator!=(const TypeBase<Size> &other) const
return !(*this == other);


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
bool operator!=(const T value) const
return data_ != std::bitset<Size>(value);


bool operator<(const TypeBase<Size> &other) const
if (data_ == other.data_)
return false;

return less_than_(other.data_);


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
bool operator<(const T value) const
return less_than_(std::bitset<Size>(value));


bool operator<=(const TypeBase<Size> &other) const
if (data_ == other.data_)
return true;

return less_than_or_eq_(other.data_);


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
bool operator<=(const T value) const
return less_than_or_eq_(std::bitset<Size>(value));


bool operator>(const TypeBase<Size> &other) const
if (data_ == other.data_)
return false;

return greater_than_(other.data_);


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
bool operator>(const T value) const
return greater_than_(std::bitset<Size>(value));


bool operator>=(const TypeBase<Size> &other) const
if (data_ == other.data_)
return true;

return greater_than_or_eq_(other.data_);


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
bool operator>=(const T value) const
return greater_than_or_eq_(std::bitset<Size>(value));


TypeBase<Size> &operator+(const TypeBase<Size> &other)
bool carry = false;
for (size_t ix = 0; ix < Size; ++ix)
data_[ix] = add_(data_[ix], other.data_[ix], carry);

return *this;


TypeBase<Size> &operator+(const std::bitset<Size> &other)
bool carry = false;
for (size_t ix = 0; ix < Size; ++ix)
data_[ix] = add_(data_[ix], other[ix], carry);

return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
TypeBase<Size> &operator+(const T value)
bool carry = false;
std::bitset<Size> other(value);
for (size_t ix = 0; ix < Size; ++ix)
data_[ix] = add_(data_[ix], other[ix], carry);

return *this;


TypeBase<Size> &operator+=(const TypeBase<Size> &other)
bool carry = false;
for (size_t ix = 0; ix < Size; ++ix)
data_[ix] = add_(data_[ix], other.data_[ix], carry);

return *this;


TypeBase<Size> &operator+=(const std::bitset<Size> &other)
bool carry = false;
for (size_t ix = 0; ix < Size; ++ix)
data_[ix] = add_(data_[ix], other[ix], carry);

return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
TypeBase<Size> &operator+=(const T value)
bool carry = false;
std::bitset<Size> other(value);
for (size_t ix = 0; ix < Size; ++ix)
data_[ix] = add_(data_[ix], other[ix], carry);

return *this;


TypeBase<Size> &operator++(int)
bool carry = false;
std::bitset<Size> other(1);
for (size_t ix = 0; ix < Size; ++ix)
data_[ix] = add_(data_[ix], other[ix], carry);

return *this;


TypeBase<Size> &operator-(const TypeBase<Size> &other)
subtract_(other.data_);
return *this;


TypeBase<Size> &operator-(const std::bitset<Size> &other)
subtract_(other);
return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
TypeBase<Size> &operator-(const T value)
subtract_(std::bitset<Size>(value));
return *this;


TypeBase<Size> &operator-=(const TypeBase<Size> &other)
subtract_(other.data_);
return *this;


TypeBase<Size> &operator-=(const std::bitset<Size> &other)
subtract_(other);
return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
TypeBase<Size> &operator-=(const T value)
subtract_(std::bitset<Size>(value));
return *this;


TypeBase<Size> &operator--(int)
subtract_(std::bitset<Size>(1));
return *this;


TypeBase<Size> &operator*(const TypeBase<Size> &other)
multiply_(other.data_);
return *this;


TypeBase<Size> &operator*(const std::bitset<Size> &other)
multiply_(other);
return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
TypeBase<Size> &operator*(const T value)
multiply_(std::bitset<Size>(value));
return *this;


TypeBase<Size> &operator*=(const TypeBase<Size> &other)
multiply_(other.data_);
return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
TypeBase<Size> &operator*=(const T value)
multiply_(std::bitset<Size>(value));
return *this;


TypeBase<Size> &operator/(const TypeBase<Size> &other)
data_ = data_.to_ullong() / other.to_ullong();
return *this;


TypeBase<Size> &operator/(const std::bitset<Size> &other)
data_ = data_.to_ullong() / other.to_ullong();
return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
TypeBase<Size> &operator/(const T value)
data_ = data_.to_ullong() / value;
return *this;


TypeBase<Size> &operator/=(const TypeBase<Size> &other)
data_ = data_.to_ullong() / other.to_ullong();
return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
TypeBase<Size> &operator/=(const T value)
data_ = data_.to_ullong() / value;
return *this;


template<size_t S>
friend std::ostream &operator <<(std::ostream &out, const TypeBase<S> &u);
protected:
TypeBase() = default;
~TypeBase() = default;

std::bitset<Size> data_;

bool add_(bool b1, bool b2, bool &carry)

void subtract_(const std::bitset<Size> &other)
bool borrow = false;
for (int i = 0; i < Size; i++)
if (borrow)
if (data_[i])
data_[i] = other[i];
borrow = other[i];

else
data_[i] = !other[i];
borrow = true;


else
if (data_[i])
data_[i] = !other[i];
borrow = false;

else
data_[i] = other[i];
borrow = other[i];





void multiply_(const std::bitset<Size> &other)
std::bitset<Size> tmp = data_;
data_.reset();
if (tmp.count() < other.count())
for (int i = 0; i < Size; i++)
if (tmp[i])
operator+=(other << i);



else
for (int i = 0; i < Size; i++)
if (other[i])
operator+=(tmp << i);





bool less_than_or_eq_(const std::bitset<Size> &other) const
for (int i = Size - 1; i >= 0; i--)
if (data_[i] && !other[i])
return false;

if (!data_[i] && other[i])
return true;


return true;


bool less_than_(const std::bitset<Size> &other) const
for (int i = Size - 1; i >= 0; i--)
if (data_[i] && !other[i])
return false;

if (!data_[i] && other[i])
return true;


return false;


bool greater_than_or_eq_(const std::bitset<Size> &other) const
for (int i = Size - 1; i >= 0; i--)
if (data_[i] && !other[i])
return true;

if (!data_[i] && other[i])
return false;


return true;


bool greater_than_(const std::bitset<Size> &other) const
for (int i = Size - 1; i >= 0; i--)
if (data_[i] && !other[i])
return true;

if (!data_[i] && other[i])
return false;


return false;

;

template<size_t Size>
class Int : public TypeBase<Size>
public:
Int() = default;

template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
Int(const T value)
TypeBase<Size>::operator=(value);


~Int() = default;

Int<Size> &operator=(const TypeBase<Size> &other)
if (this->data_ == other.data())
return *this;

this->data_ = other.data();
return *this;


long long to_int() const
if (this->data_[Size - 1])
std::bitset<Size> tmp = this->data_;
tmp.flip();
return tmp.to_ullong() * -1 - 1;

return this->data_.to_ullong();


Int<Size> &operator/(const TypeBase<Size> &other)
this->data_ = to_int() / other.to_ullong();
return *this;


Int<Size> &operator/(const std::bitset<Size> &other)
this->data_ = to_int() / other.to_ullong();
return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
Int<Size> &operator/(const T value)
this->data_ = to_int() / value;
return *this;


Int<Size> &operator/=(const TypeBase<Size> &other)
this->data_ = to_int() / other.to_ullong();
return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
Int<Size> &operator/=(const T value)
this->data_ = to_int() / value;
return *this;

;

template<size_t Size>
std::ostream &operator<<(std::ostream &out, const Int<Size> &u)
out << u.to_int();
return out;


template<size_t Size>
class UInt : public TypeBase<Size>
public:
UInt() = default;

template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
UInt(const T value)
TypeBase<Size>::operator=(value);


~UInt() = default;

UInt<Size> &operator=(const TypeBase<Size> &other)
if (this->data_ == other.data())
return *this;

this->data_ = other.data();
return *this;


unsigned long long to_int() const
return this->data_.to_ullong();

;

template<size_t Size>
std::ostream &operator<<(std::ostream &out, const UInt<Size> &u)
out << u.to_ullong();
return out;



Here are some examples on how it's supposed to be used:



#include <iostream>

#include "custom_int.h"

using namespace std;

int main()
Int<13> test1 = 1;
UInt<5> test2;

cout << "test1: " << test1 << endl;
cout << "test2: " << test2 << endl;

test1++;
cout << "test1: " << test1 << endl;

test1--;
cout << "test1: " << test1 << endl;

test1 -= 10;
cout << "test1: " << test1 << endl;

auto test3 = test1;

cout << "test3: " << test3 << endl;

test3 /= 3;

cout << "test3: " << test3 << endl;

test2 += 20;

cout << "test2: " << test2 << endl;

test2 = test2 / 10;

cout << "test2: " << test2 << endl;



I'm by no means a seasoned C++ developer, so even if I believe it's working the way it should I would love to have some input on what can be improved.



What I'm mostly concerned about is the performance (unnecessary copying etc). It's supposed to be used in a real time application so I need it to be as fast as possible.










share|improve this question









New contributor



Zenit_swe is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






$endgroup$




During a project at my work I needed a convenient way to store values taking up the smallest amount of bits necessary, not in memory but later when they're serialized into an array of unsigned short ints. For instance, a value that could be between 0 and 7 was only supposed to be 3 bits long. I ended up developing my own solution based on std::bitset with some additional code in order to make it work with signed values. Another goal was to make it work as close to a regular integer type as possible. This is the code (https://github.com/AndersHogqvist/custom_int):



#include <bitset>
#include <type_traits>

template<size_t Size>
class TypeBase
public:
size_t size() const
return data_.size();


unsigned long to_ulong() const
return data_.to_ulong();


unsigned long long to_ullong() const
return data_.to_ullong();


std::bitset<Size> data() const
return data_;


std::string to_string() const
return data_.to_string();


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
TypeBase<Size> &operator=(const T value)
data_ = std::bitset<Size>(value);
return *this;


bool operator==(const TypeBase<Size> &other) const
return data_ == other.data();


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
bool operator==(const T value) const
return data_.to_ullong() == value;


bool operator!=(const TypeBase<Size> &other) const
return !(*this == other);


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
bool operator!=(const T value) const
return data_ != std::bitset<Size>(value);


bool operator<(const TypeBase<Size> &other) const
if (data_ == other.data_)
return false;

return less_than_(other.data_);


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
bool operator<(const T value) const
return less_than_(std::bitset<Size>(value));


bool operator<=(const TypeBase<Size> &other) const
if (data_ == other.data_)
return true;

return less_than_or_eq_(other.data_);


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
bool operator<=(const T value) const
return less_than_or_eq_(std::bitset<Size>(value));


bool operator>(const TypeBase<Size> &other) const
if (data_ == other.data_)
return false;

return greater_than_(other.data_);


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
bool operator>(const T value) const
return greater_than_(std::bitset<Size>(value));


bool operator>=(const TypeBase<Size> &other) const
if (data_ == other.data_)
return true;

return greater_than_or_eq_(other.data_);


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
bool operator>=(const T value) const
return greater_than_or_eq_(std::bitset<Size>(value));


TypeBase<Size> &operator+(const TypeBase<Size> &other)
bool carry = false;
for (size_t ix = 0; ix < Size; ++ix)
data_[ix] = add_(data_[ix], other.data_[ix], carry);

return *this;


TypeBase<Size> &operator+(const std::bitset<Size> &other)
bool carry = false;
for (size_t ix = 0; ix < Size; ++ix)
data_[ix] = add_(data_[ix], other[ix], carry);

return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
TypeBase<Size> &operator+(const T value)
bool carry = false;
std::bitset<Size> other(value);
for (size_t ix = 0; ix < Size; ++ix)
data_[ix] = add_(data_[ix], other[ix], carry);

return *this;


TypeBase<Size> &operator+=(const TypeBase<Size> &other)
bool carry = false;
for (size_t ix = 0; ix < Size; ++ix)
data_[ix] = add_(data_[ix], other.data_[ix], carry);

return *this;


TypeBase<Size> &operator+=(const std::bitset<Size> &other)
bool carry = false;
for (size_t ix = 0; ix < Size; ++ix)
data_[ix] = add_(data_[ix], other[ix], carry);

return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
TypeBase<Size> &operator+=(const T value)
bool carry = false;
std::bitset<Size> other(value);
for (size_t ix = 0; ix < Size; ++ix)
data_[ix] = add_(data_[ix], other[ix], carry);

return *this;


TypeBase<Size> &operator++(int)
bool carry = false;
std::bitset<Size> other(1);
for (size_t ix = 0; ix < Size; ++ix)
data_[ix] = add_(data_[ix], other[ix], carry);

return *this;


TypeBase<Size> &operator-(const TypeBase<Size> &other)
subtract_(other.data_);
return *this;


TypeBase<Size> &operator-(const std::bitset<Size> &other)
subtract_(other);
return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
TypeBase<Size> &operator-(const T value)
subtract_(std::bitset<Size>(value));
return *this;


TypeBase<Size> &operator-=(const TypeBase<Size> &other)
subtract_(other.data_);
return *this;


TypeBase<Size> &operator-=(const std::bitset<Size> &other)
subtract_(other);
return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
TypeBase<Size> &operator-=(const T value)
subtract_(std::bitset<Size>(value));
return *this;


TypeBase<Size> &operator--(int)
subtract_(std::bitset<Size>(1));
return *this;


TypeBase<Size> &operator*(const TypeBase<Size> &other)
multiply_(other.data_);
return *this;


TypeBase<Size> &operator*(const std::bitset<Size> &other)
multiply_(other);
return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
TypeBase<Size> &operator*(const T value)
multiply_(std::bitset<Size>(value));
return *this;


TypeBase<Size> &operator*=(const TypeBase<Size> &other)
multiply_(other.data_);
return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
TypeBase<Size> &operator*=(const T value)
multiply_(std::bitset<Size>(value));
return *this;


TypeBase<Size> &operator/(const TypeBase<Size> &other)
data_ = data_.to_ullong() / other.to_ullong();
return *this;


TypeBase<Size> &operator/(const std::bitset<Size> &other)
data_ = data_.to_ullong() / other.to_ullong();
return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
TypeBase<Size> &operator/(const T value)
data_ = data_.to_ullong() / value;
return *this;


TypeBase<Size> &operator/=(const TypeBase<Size> &other)
data_ = data_.to_ullong() / other.to_ullong();
return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
TypeBase<Size> &operator/=(const T value)
data_ = data_.to_ullong() / value;
return *this;


template<size_t S>
friend std::ostream &operator <<(std::ostream &out, const TypeBase<S> &u);
protected:
TypeBase() = default;
~TypeBase() = default;

std::bitset<Size> data_;

bool add_(bool b1, bool b2, bool &carry)

void subtract_(const std::bitset<Size> &other)
bool borrow = false;
for (int i = 0; i < Size; i++)
if (borrow)
if (data_[i])
data_[i] = other[i];
borrow = other[i];

else
data_[i] = !other[i];
borrow = true;


else
if (data_[i])
data_[i] = !other[i];
borrow = false;

else
data_[i] = other[i];
borrow = other[i];





void multiply_(const std::bitset<Size> &other)
std::bitset<Size> tmp = data_;
data_.reset();
if (tmp.count() < other.count())
for (int i = 0; i < Size; i++)
if (tmp[i])
operator+=(other << i);



else
for (int i = 0; i < Size; i++)
if (other[i])
operator+=(tmp << i);





bool less_than_or_eq_(const std::bitset<Size> &other) const
for (int i = Size - 1; i >= 0; i--)
if (data_[i] && !other[i])
return false;

if (!data_[i] && other[i])
return true;


return true;


bool less_than_(const std::bitset<Size> &other) const
for (int i = Size - 1; i >= 0; i--)
if (data_[i] && !other[i])
return false;

if (!data_[i] && other[i])
return true;


return false;


bool greater_than_or_eq_(const std::bitset<Size> &other) const
for (int i = Size - 1; i >= 0; i--)
if (data_[i] && !other[i])
return true;

if (!data_[i] && other[i])
return false;


return true;


bool greater_than_(const std::bitset<Size> &other) const
for (int i = Size - 1; i >= 0; i--)
if (data_[i] && !other[i])
return true;

if (!data_[i] && other[i])
return false;


return false;

;

template<size_t Size>
class Int : public TypeBase<Size>
public:
Int() = default;

template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
Int(const T value)
TypeBase<Size>::operator=(value);


~Int() = default;

Int<Size> &operator=(const TypeBase<Size> &other)
if (this->data_ == other.data())
return *this;

this->data_ = other.data();
return *this;


long long to_int() const
if (this->data_[Size - 1])
std::bitset<Size> tmp = this->data_;
tmp.flip();
return tmp.to_ullong() * -1 - 1;

return this->data_.to_ullong();


Int<Size> &operator/(const TypeBase<Size> &other)
this->data_ = to_int() / other.to_ullong();
return *this;


Int<Size> &operator/(const std::bitset<Size> &other)
this->data_ = to_int() / other.to_ullong();
return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
Int<Size> &operator/(const T value)
this->data_ = to_int() / value;
return *this;


Int<Size> &operator/=(const TypeBase<Size> &other)
this->data_ = to_int() / other.to_ullong();
return *this;


template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
Int<Size> &operator/=(const T value)
this->data_ = to_int() / value;
return *this;

;

template<size_t Size>
std::ostream &operator<<(std::ostream &out, const Int<Size> &u)
out << u.to_int();
return out;


template<size_t Size>
class UInt : public TypeBase<Size>
public:
UInt() = default;

template<typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
UInt(const T value)
TypeBase<Size>::operator=(value);


~UInt() = default;

UInt<Size> &operator=(const TypeBase<Size> &other)
if (this->data_ == other.data())
return *this;

this->data_ = other.data();
return *this;


unsigned long long to_int() const
return this->data_.to_ullong();

;

template<size_t Size>
std::ostream &operator<<(std::ostream &out, const UInt<Size> &u)
out << u.to_ullong();
return out;



Here are some examples on how it's supposed to be used:



#include <iostream>

#include "custom_int.h"

using namespace std;

int main()
Int<13> test1 = 1;
UInt<5> test2;

cout << "test1: " << test1 << endl;
cout << "test2: " << test2 << endl;

test1++;
cout << "test1: " << test1 << endl;

test1--;
cout << "test1: " << test1 << endl;

test1 -= 10;
cout << "test1: " << test1 << endl;

auto test3 = test1;

cout << "test3: " << test3 << endl;

test3 /= 3;

cout << "test3: " << test3 << endl;

test2 += 20;

cout << "test2: " << test2 << endl;

test2 = test2 / 10;

cout << "test2: " << test2 << endl;



I'm by no means a seasoned C++ developer, so even if I believe it's working the way it should I would love to have some input on what can be improved.



What I'm mostly concerned about is the performance (unnecessary copying etc). It's supposed to be used in a real time application so I need it to be as fast as possible.







c++ performance bitset






share|improve this question









New contributor



Zenit_swe is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.










share|improve this question









New contributor



Zenit_swe is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.








share|improve this question




share|improve this question








edited 4 hours ago









Mast

7,9557 gold badges39 silver badges93 bronze badges




7,9557 gold badges39 silver badges93 bronze badges






New contributor



Zenit_swe is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.








asked 8 hours ago









Zenit_sweZenit_swe

163 bronze badges




163 bronze badges




New contributor



Zenit_swe is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.




New contributor




Zenit_swe is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
















  • $begingroup$
    Is it intended to work for integers wider than unsigned long long?
    $endgroup$
    – harold
    7 hours ago










  • $begingroup$
    @harold, in my project I was handling up to 64 bit unsigned ints, so i haven't really thought about anything larger than that.
    $endgroup$
    – Zenit_swe
    7 hours ago






  • 1




    $begingroup$
    I rolled back your last edit. Editing code after the answer was posted is against the CR policy, because it invalidates the answer.
    $endgroup$
    – vnp
    5 hours ago










  • $begingroup$
    sorry for that @vnp
    $endgroup$
    – Zenit_swe
    4 hours ago






  • 1




    $begingroup$
    Please do not update the code in your question to incorporate feedback from answers, doing so goes against the Question + Answer style of Code Review. This is not a forum where you should keep the most updated version in your question. Please see what you may and may not do after receiving answers. If your code has significantly improved, preferably with edits of yourself as well, you could ask a new question, a follow-up.
    $endgroup$
    – Mast
    4 hours ago
















  • $begingroup$
    Is it intended to work for integers wider than unsigned long long?
    $endgroup$
    – harold
    7 hours ago










  • $begingroup$
    @harold, in my project I was handling up to 64 bit unsigned ints, so i haven't really thought about anything larger than that.
    $endgroup$
    – Zenit_swe
    7 hours ago






  • 1




    $begingroup$
    I rolled back your last edit. Editing code after the answer was posted is against the CR policy, because it invalidates the answer.
    $endgroup$
    – vnp
    5 hours ago










  • $begingroup$
    sorry for that @vnp
    $endgroup$
    – Zenit_swe
    4 hours ago






  • 1




    $begingroup$
    Please do not update the code in your question to incorporate feedback from answers, doing so goes against the Question + Answer style of Code Review. This is not a forum where you should keep the most updated version in your question. Please see what you may and may not do after receiving answers. If your code has significantly improved, preferably with edits of yourself as well, you could ask a new question, a follow-up.
    $endgroup$
    – Mast
    4 hours ago















$begingroup$
Is it intended to work for integers wider than unsigned long long?
$endgroup$
– harold
7 hours ago




$begingroup$
Is it intended to work for integers wider than unsigned long long?
$endgroup$
– harold
7 hours ago












$begingroup$
@harold, in my project I was handling up to 64 bit unsigned ints, so i haven't really thought about anything larger than that.
$endgroup$
– Zenit_swe
7 hours ago




$begingroup$
@harold, in my project I was handling up to 64 bit unsigned ints, so i haven't really thought about anything larger than that.
$endgroup$
– Zenit_swe
7 hours ago




1




1




$begingroup$
I rolled back your last edit. Editing code after the answer was posted is against the CR policy, because it invalidates the answer.
$endgroup$
– vnp
5 hours ago




$begingroup$
I rolled back your last edit. Editing code after the answer was posted is against the CR policy, because it invalidates the answer.
$endgroup$
– vnp
5 hours ago












$begingroup$
sorry for that @vnp
$endgroup$
– Zenit_swe
4 hours ago




$begingroup$
sorry for that @vnp
$endgroup$
– Zenit_swe
4 hours ago




1




1




$begingroup$
Please do not update the code in your question to incorporate feedback from answers, doing so goes against the Question + Answer style of Code Review. This is not a forum where you should keep the most updated version in your question. Please see what you may and may not do after receiving answers. If your code has significantly improved, preferably with edits of yourself as well, you could ask a new question, a follow-up.
$endgroup$
– Mast
4 hours ago




$begingroup$
Please do not update the code in your question to incorporate feedback from answers, doing so goes against the Question + Answer style of Code Review. This is not a forum where you should keep the most updated version in your question. Please see what you may and may not do after receiving answers. If your code has significantly improved, preferably with edits of yourself as well, you could ask a new question, a follow-up.
$endgroup$
– Mast
4 hours ago










1 Answer
1






active

oldest

votes


















3














$begingroup$

A significant performance drain is bit-by-bit computation loops such as



 TypeBase<Size> &operator+=(const TypeBase<Size> &other) 
bool carry = false;
for (size_t ix = 0; ix < Size; ++ix)
data_[ix] = add_(data_[ix], other.data_[ix], carry);

return *this;



Unfortunately, at this time such constructs are not recognized by major compilers, and probably also not by various embedded compilers (which if I recall correctly you mentioned earlier).



For small Size it could be implemented with plain old arithmetic operators,



 TypeBase<Size> &operator+=(const TypeBase<Size> &other) 
data_ = std::bitset<Size>(to_ullong() + other.to_ullong());
return *this;



Which unsurprisingly compiles to normal addition.



Larger Size is trickier to support efficiently this way.






share|improve this answer









$endgroup$














  • $begingroup$
    This is exactly why I posted it here! Thank you for your input, much appreciated. Would it be sufficient if I added a control statement that implements your solution if Size <= 64 and if not use the current bit-by-bit function?
    $endgroup$
    – Zenit_swe
    6 hours ago






  • 1




    $begingroup$
    @Zenit_swe that would do it, though it's a very sharp performance discontinuity between 64 and 65 bits then
    $endgroup$
    – harold
    6 hours ago













Your Answer






StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "196"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/4.0/"u003ecc by-sa 4.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);







Zenit_swe is a new contributor. Be nice, and check out our Code of Conduct.









draft saved

draft discarded
















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f229066%2fhow-to-make-my-custom-integer-type-perform-better%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









3














$begingroup$

A significant performance drain is bit-by-bit computation loops such as



 TypeBase<Size> &operator+=(const TypeBase<Size> &other) 
bool carry = false;
for (size_t ix = 0; ix < Size; ++ix)
data_[ix] = add_(data_[ix], other.data_[ix], carry);

return *this;



Unfortunately, at this time such constructs are not recognized by major compilers, and probably also not by various embedded compilers (which if I recall correctly you mentioned earlier).



For small Size it could be implemented with plain old arithmetic operators,



 TypeBase<Size> &operator+=(const TypeBase<Size> &other) 
data_ = std::bitset<Size>(to_ullong() + other.to_ullong());
return *this;



Which unsurprisingly compiles to normal addition.



Larger Size is trickier to support efficiently this way.






share|improve this answer









$endgroup$














  • $begingroup$
    This is exactly why I posted it here! Thank you for your input, much appreciated. Would it be sufficient if I added a control statement that implements your solution if Size <= 64 and if not use the current bit-by-bit function?
    $endgroup$
    – Zenit_swe
    6 hours ago






  • 1




    $begingroup$
    @Zenit_swe that would do it, though it's a very sharp performance discontinuity between 64 and 65 bits then
    $endgroup$
    – harold
    6 hours ago















3














$begingroup$

A significant performance drain is bit-by-bit computation loops such as



 TypeBase<Size> &operator+=(const TypeBase<Size> &other) 
bool carry = false;
for (size_t ix = 0; ix < Size; ++ix)
data_[ix] = add_(data_[ix], other.data_[ix], carry);

return *this;



Unfortunately, at this time such constructs are not recognized by major compilers, and probably also not by various embedded compilers (which if I recall correctly you mentioned earlier).



For small Size it could be implemented with plain old arithmetic operators,



 TypeBase<Size> &operator+=(const TypeBase<Size> &other) 
data_ = std::bitset<Size>(to_ullong() + other.to_ullong());
return *this;



Which unsurprisingly compiles to normal addition.



Larger Size is trickier to support efficiently this way.






share|improve this answer









$endgroup$














  • $begingroup$
    This is exactly why I posted it here! Thank you for your input, much appreciated. Would it be sufficient if I added a control statement that implements your solution if Size <= 64 and if not use the current bit-by-bit function?
    $endgroup$
    – Zenit_swe
    6 hours ago






  • 1




    $begingroup$
    @Zenit_swe that would do it, though it's a very sharp performance discontinuity between 64 and 65 bits then
    $endgroup$
    – harold
    6 hours ago













3














3










3







$begingroup$

A significant performance drain is bit-by-bit computation loops such as



 TypeBase<Size> &operator+=(const TypeBase<Size> &other) 
bool carry = false;
for (size_t ix = 0; ix < Size; ++ix)
data_[ix] = add_(data_[ix], other.data_[ix], carry);

return *this;



Unfortunately, at this time such constructs are not recognized by major compilers, and probably also not by various embedded compilers (which if I recall correctly you mentioned earlier).



For small Size it could be implemented with plain old arithmetic operators,



 TypeBase<Size> &operator+=(const TypeBase<Size> &other) 
data_ = std::bitset<Size>(to_ullong() + other.to_ullong());
return *this;



Which unsurprisingly compiles to normal addition.



Larger Size is trickier to support efficiently this way.






share|improve this answer









$endgroup$



A significant performance drain is bit-by-bit computation loops such as



 TypeBase<Size> &operator+=(const TypeBase<Size> &other) 
bool carry = false;
for (size_t ix = 0; ix < Size; ++ix)
data_[ix] = add_(data_[ix], other.data_[ix], carry);

return *this;



Unfortunately, at this time such constructs are not recognized by major compilers, and probably also not by various embedded compilers (which if I recall correctly you mentioned earlier).



For small Size it could be implemented with plain old arithmetic operators,



 TypeBase<Size> &operator+=(const TypeBase<Size> &other) 
data_ = std::bitset<Size>(to_ullong() + other.to_ullong());
return *this;



Which unsurprisingly compiles to normal addition.



Larger Size is trickier to support efficiently this way.







share|improve this answer












share|improve this answer



share|improve this answer










answered 6 hours ago









haroldharold

2,4569 silver badges14 bronze badges




2,4569 silver badges14 bronze badges














  • $begingroup$
    This is exactly why I posted it here! Thank you for your input, much appreciated. Would it be sufficient if I added a control statement that implements your solution if Size <= 64 and if not use the current bit-by-bit function?
    $endgroup$
    – Zenit_swe
    6 hours ago






  • 1




    $begingroup$
    @Zenit_swe that would do it, though it's a very sharp performance discontinuity between 64 and 65 bits then
    $endgroup$
    – harold
    6 hours ago
















  • $begingroup$
    This is exactly why I posted it here! Thank you for your input, much appreciated. Would it be sufficient if I added a control statement that implements your solution if Size <= 64 and if not use the current bit-by-bit function?
    $endgroup$
    – Zenit_swe
    6 hours ago






  • 1




    $begingroup$
    @Zenit_swe that would do it, though it's a very sharp performance discontinuity between 64 and 65 bits then
    $endgroup$
    – harold
    6 hours ago















$begingroup$
This is exactly why I posted it here! Thank you for your input, much appreciated. Would it be sufficient if I added a control statement that implements your solution if Size <= 64 and if not use the current bit-by-bit function?
$endgroup$
– Zenit_swe
6 hours ago




$begingroup$
This is exactly why I posted it here! Thank you for your input, much appreciated. Would it be sufficient if I added a control statement that implements your solution if Size <= 64 and if not use the current bit-by-bit function?
$endgroup$
– Zenit_swe
6 hours ago




1




1




$begingroup$
@Zenit_swe that would do it, though it's a very sharp performance discontinuity between 64 and 65 bits then
$endgroup$
– harold
6 hours ago




$begingroup$
@Zenit_swe that would do it, though it's a very sharp performance discontinuity between 64 and 65 bits then
$endgroup$
– harold
6 hours ago











Zenit_swe is a new contributor. Be nice, and check out our Code of Conduct.









draft saved

draft discarded

















Zenit_swe is a new contributor. Be nice, and check out our Code of Conduct.












Zenit_swe is a new contributor. Be nice, and check out our Code of Conduct.











Zenit_swe is a new contributor. Be nice, and check out our Code of Conduct.














Thanks for contributing an answer to Code Review Stack Exchange!


  • Please be sure to answer the question. Provide details and share your research!

But avoid


  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.

Use MathJax to format equations. MathJax reference.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f229066%2fhow-to-make-my-custom-integer-type-perform-better%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Canceling a color specificationRandomly assigning color to Graphics3D objects?Default color for Filling in Mathematica 9Coloring specific elements of sets with a prime modified order in an array plotHow to pick a color differing significantly from the colors already in a given color list?Detection of the text colorColor numbers based on their valueCan color schemes for use with ColorData include opacity specification?My dynamic color schemes

Invision Community Contents History See also References External links Navigation menuProprietaryinvisioncommunity.comIPS Community ForumsIPS Community Forumsthis blog entry"License Changes, IP.Board 3.4, and the Future""Interview -- Matt Mecham of Ibforums""CEO Invision Power Board, Matt Mecham Is a Liar, Thief!"IPB License Explanation 1.3, 1.3.1, 2.0, and 2.1ArchivedSecurity Fixes, Updates And Enhancements For IPB 1.3.1Archived"New Demo Accounts - Invision Power Services"the original"New Default Skin"the original"Invision Power Board 3.0.0 and Applications Released"the original"Archived copy"the original"Perpetual licenses being done away with""Release Notes - Invision Power Services""Introducing: IPS Community Suite 4!"Invision Community Release Notes

François Viète Contents Biography Work and thought Bibliography See also Notes Further reading External links Navigation menup. 21Google Bookspp. 75–77Google BooksDe thou (from University of Saint Andrews)ArchivedGoogle BooksGoogle BooksGoogle BooksGoogle booksGoogle Bookscc-parthenay.frL'histoire universelle (fr)Universal History (en)ArchivedAdsabs.harvard.eduPagesperso-orange.frArchive.orgChikara Sasaki. Descartes' mathematical thought p.259Google BooksGoogle BooksGoogle Bookspp. 152 and onwardGoogle BooksGoogle BooksScribd.comGoogle Books1257-7979Google BooksGoogle BooksGoogle BooksGoogle BooksGoogle BooksGoogle BooksGallica.bnf.frGoogle BooksGoogle Books"François Viète"Francois Viète: Father of Modern Algebraic NotationThe Lawyer and the GamblerAbout TarporleySite de Jean-Paul GuichardL'algèbre nouvelle"About the Harmonicon"cb120511976(data)1188044800000 0001 0913 5903n82164680ola2013766880073431702w6vt1sb70287374827140948071409480