I'm writing a simple bitset wrapper to easily and efficiently set, clear and read bits from an 8-bit integer. I would do these three operations via operator[], but I'm stucked, and honestly I'm not sure it is possible without losing performances (really important for my purposes).
#include <stdint.h>
#include <iostream>
class BitMask {
private:
uint8_t mask;
public:
inline void set(int bit) { mask |= 1 << bit; } // deprecated
inline void clear(int bit) { mask &= ~(1 << bit); } // deprecated
inline int read(int bit) { return (mask >> bit) & 1; } // deprecated
bool operator[](int bit) const { return (mask >> bit) & 1; } // new way to read
??? // new way to write
friend std::ostream& operator<<(std::ostream& os, const BitMask& bitmask) {
for (int bit = 0; bit < 8; ++bit)
os << ((bitmask.mask >> bit) & 1 ? "1" : "0");
return os;
}
};
int main() {
BitMask bitmask1;
bitmask1.set(3);
bitmask1.clear(3);
bitmask1.read(3);
std::cout << bitmask1;
BitMask bitmask2;
bitmask2[3] = 1; // set
bitmask2[3] = 0; // clear
bitmask2[3]; // read
std::cout << bitmask2;
}
Any idea?
One way (the only way?) is to return a proxy object from your operator[] which will hold index for your bit, this way you will assign new value to your proxy object which will alter appropriate BitMask bit. For example see here: Vector, proxy class and dot operator in C++
As for a performance - it all depends how compiler will optimize your code, if your proxy class would have only inline methods then it should be fast.
Below is example how to fix your code:
#include <stdint.h>
#include <iostream>
class BitMask {
private:
uint8_t mask;
public:
inline void set(int bit) { mask |= 1 << bit; } // deprecated
inline void clear(int bit) { mask &= ~(1 << bit); } // deprecated
inline int read(int bit) const { return (mask >> bit) & 1; } // deprecated
struct proxy_bit
{
BitMask& bitmask;
int index;
proxy_bit(BitMask& p_bitmask, int p_index) : bitmask(p_bitmask), index(p_index) {}
proxy_bit& operator=(int rhs) {
if (rhs)
bitmask.set(index);
else
bitmask.clear(index);
return *this;
}
operator int() {
return bitmask.read(index);
}
};
proxy_bit operator[](int bit) { return proxy_bit(*this, bit); } // new way to read
int operator[](int bit) const { return read(bit); } // new way to read
friend std::ostream& operator<<(std::ostream& os, const BitMask& bitmask) {
for (int bit = 0; bit < 8; ++bit)
os << ((bitmask.mask >> bit) & 1 ? "1" : "0");
return os;
}
};
int main() {
BitMask bitmask1;
bitmask1.set(3);
bitmask1.clear(3);
bitmask1.read(3);
std::cout << bitmask1 << std::endl;
BitMask bitmask2;
bitmask2[3] = 1; // set
bitmask2[3] = 0; // clear
bitmask2[3]; // read
std::cout << bitmask2 << std::endl;
const BitMask bitmask3;
if (bitmask3[3]) {}
//bitmask3[3] = 1; // compile error - OK!
}
Related
I tried two ways for the same issue, one works and the other doesn't. The following version works, returning a value of 4.
int gather_list()
{
mpi::environment env;
mpi::communicator world;
std::srand(time(0) + world.rank());
int my_number = std::rand();
std::vector<int> tmp_vec;
tmp_vec.push_back(my_number);
tmp_vec.push_back(my_number + 1);
if (world.rank() == 0)
{
std::vector<int> all_numbers;
gather(world, &tmp_vec[0], tmp_vec.size(), all_numbers, 0);
std::cout << all_numbers.size() << std::endl;
} else
{
gather(world, &tmp_vec[0], tmp_vec.size(), 0);
}
return 0;
}
The following version doesn't work, returning a value of 2.
class ArchivableVecInt : public std::vector<int>
{
public:
ArchivableVecInt() = default;
explicit ArchivableVecInt(const std::vector<int> &vec)
{
auto base_ptr = static_cast<std::vector<int> *>(this);
*base_ptr = vec;
}
template<class Archiver>
void serialize(Archiver &ar, unsigned int)
{
for (auto i: *this)
{
ar & i;
}
}
protected:
};
int gather_list()
{
mpi::environment env;
mpi::communicator world;
std::srand(time(0) + world.rank());
int my_number = std::rand();
std::vector<int> tmp_vec;
tmp_vec.push_back(my_number);
tmp_vec.push_back(my_number + 1);
ArchivableVecInt my_vec(tmp_vec);
if (world.rank() == 0)
{
std::vector<ArchivableVecInt> all_numbers;
gather(world, my_vec, all_numbers, 0);
for (int proc = 0; proc < world.size(); ++proc)
std::cout << "Process #" << proc << " thought of "
<< all_numbers[proc].size() << std::endl;
} else
{
gather(world, my_vec, 0);
}
return 0;
}
I tried 2 processes, while rank 0 returns a value of 2, rank 1 returns zero. Seems the gather(world, my_vec, 0) didn't work, why?
result as below.
Thanks in advance.
In your second example your receive buffer is a vector<vector<int>> meaning that the data is not contiguous. MPI needs contiguous buffers.
I'm modifying some existing open source library and there is a struct (say named as Node) containing bit-fields, e.g.
struct Node {
std::atomic<uint32_t> size:30;
std::atomic<uint32_t> isnull:1;
};
To fit my needs, these fields need to be atomic so I was expecting to use std::atomic for this and faced compile time error:
bit-field 'size' has non-integral type 'std::atomic<uint32_t>'
According to documentation, there is a restricted set of types which can be used for std::atomic
Can anyone advise/have idea on how to get functionality of atomic fields with the minimum impact to the existing source code?
Thanks in advance!
I used an unsigned short as an example below.
This is less ideal, but you could sacrifice 8 bits and insert a std::atomic_flag in the bit field with a union. Unfortunately, std::atomic_flag type is a std::atomic_bool type.
This structure can be spin locked manually every time you access it. However, the code should have minimal performance degradation (unlike creating, locking, unlocking, destroying with a std::mutex and std::unique_lock).
This code may waste about 10-30 clock cycles to enable low cost multi-threading.
PS. Make sure the reserved 8 bits below are not messed up by the endian structure of the processor. You may have to define at the end for big-endian processors. I only tested this code on an Intel CPU (always little-endian).
#include <iostream>
#include <atomic>
#include <thread>
union Data
{
std::atomic_flag access = ATOMIC_FLAG_INIT; // one byte
struct
{
typedef unsigned short ushort;
ushort reserved : 8;
ushort count : 4;
ushort ready : 1;
ushort unused : 3;
} bits;
};
class SpinLock
{
public:
inline SpinLock(std::atomic_flag &access, bool locked=true)
: mAccess(access)
{
if(locked) lock();
}
inline ~SpinLock()
{
unlock();
}
inline void lock()
{
while (mAccess.test_and_set(std::memory_order_acquire))
{
}
}
// each attempt will take about 10-30 clock cycles
inline bool try_lock(unsigned int attempts=0)
{
while(mAccess.test_and_set(std::memory_order_acquire))
{
if (! attempts) return false;
-- attempts;
}
return true;
}
inline void unlock()
{
mAccess.clear(std::memory_order_release);
}
private:
std::atomic_flag &mAccess;
};
void aFn(int &i, Data &d)
{
SpinLock lock(d.access, false);
// manually locking/unlocking can be tighter
lock.lock();
if (d.bits.ready)
{
++d.bits.count;
}
d.bits.ready ^= true; // alternate each time
lock.unlock();
}
int main(void)
{
Data f;
f.bits.count = 0;
f.bits.ready = true;
std::thread *p[8];
for (int i = 0; i < 8; ++ i)
{
p[i] = new std::thread([&f] (int i) { aFn(i, f); }, i);
}
for (int i = 0; i < 8; ++i)
{
p[i]->join();
delete p[i];
}
std::cout << "size: " << sizeof(f) << std::endl;
std::cout << "count: " << f.bits.count << std::endl;
}
The result is as expected...
size: 2
count: 4
I start using openssl.
I want to use a public key to check a signature. But for now, I can not read my public key with openssl.
Here is my source code:
#include <iostream>
#include <openssl/ec.h>
#include <openssl/evp.h>
#include <openssl/err.h>
bool verifyPublicKey(const std::string &sRawPublicKey);
void printAllError();
int main(int argc, char* argv[])
{
if (argc < 2) {
std::cerr << "Usage: " << argv[0] << " PUBLIC KEY" << std::endl;
return EXIT_FAILURE;
}
std::string sPublicKey = argv[1];
std::cout << "Key: " << sPublicKey << std::endl;
bool bRes = verifyPublicKey(sPublicKey);
if (!bRes)
{
std::cerr << "verifyPublicKey failled" << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
bool verifyPublicKey(const std::string &sRawPublicKey)
{
bool bRes = false;
EC_KEY *eckey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
EC_KEY_set_conv_form(eckey, POINT_CONVERSION_UNCOMPRESSED);
unsigned char *p_RawPublicKey = new unsigned char[sRawPublicKey.length() + 1];
std::copy(sRawPublicKey.begin(), sRawPublicKey.end(), p_RawPublicKey);
const unsigned char *pubkey_raw_p = p_RawPublicKey;
o2i_ECPublicKey(&eckey, &pubkey_raw_p, sRawPublicKey.size());
if (!EC_KEY_check_key(eckey))
{
EC_KEY_free(eckey);
bRes = false;
printAllError();
}
else
{
EC_KEY_free(eckey);
bRes = true;
}
return bRes;
}
void printAllError()
{
while (ERR_peek_last_error() != 0)
{
std::cerr << ERR_error_string(ERR_get_error(), nullptr) << std::endl;
}
}
I run it with the following public key:
3059301306072A8648CE3D020106082A8648CE3D03010703420004E297417036EB4C6404CC9C2AC4F28468DD0A92F2C9496D187D2BCA784DB49AB540B9FD9ACE0BA49C8532825954755EC10246A71AF2AEE9AEC34BE683CDDFD212
ASN.1 Decoder:
SEQUENCE {
SEQUENCE {
OBJECTIDENTIFIER 1.2.840.10045.2.1 (ecPublicKey)
OBJECTIDENTIFIER 1.2.840.10045.3.1.7 (P-256)
}
BITSTRING 0x04E297417036EB4C6404CC9C2AC4F28468DD0A92F2C9496D187D2BCA784DB49AB540B9FD9ACE0BA49C8532825954755EC10246A71AF2AEE9AEC34BE683CDDFD212
: 0 unused bit(s)
}
With the ASN.1, I notice that the key I use is in the correct format: 0x04 || HEX(x) || HEX(y) with z = 0x04.
The output of the program is as follows:
Key: 3059301306072A8648CE3D020106082A8648CE3D03010703420004E297417036EB4C6404CC9C2AC4F28468DD0A92F2C9496D187D2BCA784DB49AB540B9FD9ACE0BA49C8532825954755EC10246A71AF2AEE9AEC34BE683CDDFD212
error:10067066:elliptic curve routines:ec_GFp_simple_oct2point:invalid encoding
error:10098010:elliptic curve routines:o2i_ECPublicKey:EC lib
error:1010206A:elliptic curve routines:ec_key_simple_check_key:point at infinity verifyPublicKey failed
I'm lost. Do you have explanations?
Moreover, is it possible to go further by giving only x and y (without ASN.1 header).
Thank you
Looks like you should feed the raw point to function o2i_ECPublicKey(), without the ASN.1 framing.
I was implementing the ring buffer and have encountered an error. What does it mean to store a reference of outer class(class ring) object(m_ring) in inner class(class iterator) and when I remove the reference(&) the program compiles correctly but crashes. Please explain what is happening.(See the comment in Ring.h) Sorry for bad English.
// Ring.h
#ifndef RING.H
#define RING.H
#include <iostream>
using namespace std;
template<class T>
class ring {
unsigned int m_size;
int m_pos;
T *m_values;
public:
class iterator;
public:
ring(unsigned int size) : m_size(size), m_pos(0)
{
m_values = new T[m_size];
}
~ring()
{
delete[] m_values;
}
void add(const T &val)
{
m_values[m_pos] = val;
m_pos++;
m_pos %= m_size;
}
T& get(int pos)
{
return m_values[pos];
}
iterator begin()
{
return iterator(0, *this);
}
iterator end()
{
return iterator(m_size, *this);
}
};
template<class T>
class ring<T>::iterator {
int m_pos;
ring &m_ring; // Removing & gives garbage output.
public:
iterator(int pos, ring& aRing) : m_pos(pos), m_ring(aRing){}
bool operator!=(const iterator &other) const
{
return other.m_pos != m_pos;
}
iterator &operator++(int)
{
m_pos++;
return *this;
}
iterator &operator++()
{
m_pos++;
return *this;
}
T &operator*()
{
// return m_ring.m_values[m_pos];
return m_ring.get(m_pos);
}
};
#endif // RING
Driver program :
// Ring_Buffer_Class.cpp
#include <iostream>
#include "ring.h"
using namespace std;
int main()
{
ring<string> textring(3);
textring.add("one");
textring.add("two");
textring.add("three");
textring.add("four");
// C++ 98
for(ring<string>::iterator it = textring.begin(); it != textring.end(); it++)
{
cout << *it << endl;
}
cout << endl;
// C++11
for(string value : textring)
{
cout << value << endl;
}
return 0;
}
I also observed that removing ~ring() (Destructor) results into correct output.
Expected output :
four
two
three
four
two
three
I'm trying to figure out how much the execution time of boost::variant differ from a polymorphism approach. In my first test I got very different results on gcc 4.9.1 and clang+llvm 3.5.
You can find the code below. Here are my results:
clang+llvm
polymorphism: 2.16401
boost::variant: 3.83487
gcc:
polymorphism: 2.46161
boost::variant: 1.33326
I compiled both with -O3.
Is someone able to explain that?
code
#include <iostream>
#include <vector>
#include <algorithm>
#include <boost/variant.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <ctime>
struct value_type {
value_type() {}
virtual ~value_type() {}
virtual void inc() = 0;
};
struct int_type : value_type {
int_type() : value_type() {}
virtual ~int_type() {}
void inc() { value += 1; }
private:
int value = 0;
};
struct float_type : value_type {
float_type() : value_type() {}
virtual ~float_type() {}
void inc() { value += 1; }
private:
float value = 0;
};
void dyn_test() {
std::vector<std::unique_ptr<value_type>> v;
for (int i = 0; i < 1024; i++) {
if (i % 2 == 0)
v.emplace_back(new int_type());
else
v.emplace_back(new float_type());
}
for (int i = 0; i < 900000; i++) {
std::for_each(v.begin(), v.end(), [](auto &item) { item->inc(); });
}
}
struct visitor : boost::static_visitor<> {
template <typename T> void operator()(T &item) { item += 1; }
};
using mytype = boost::variant<int, float>;
void static_test() {
std::vector<mytype> v;
for (int i = 0; i < 1024; i++) {
if (i % 2 == 0)
v.emplace_back(0);
else
v.emplace_back(0.f);
}
visitor vi;
for (int i = 0; i < 900000; i++) {
std::for_each(v.begin(), v.end(), boost::apply_visitor(vi));
}
}
template <typename F> double measure(F f) {
clock_t start = clock();
f();
clock_t end = clock();
float seconds = (float)(end - start) / CLOCKS_PER_SEC;
return seconds;
}
int main() {
std::cout << "polymorphism: " << measure([] { dyn_test(); }) << std::endl;
std::cout << "boost::variant: " << measure([] { static_test(); }) << std::endl;
return 0;
}
assembler
gcc
clang+llvm
Clang is known to miscompile some std::vector functions from various Standard libraries, due to some edge cases in their inliner. I don't know if those have been fixed by now but quite possibly not. Since unique_ptr is smaller and simpler than boost::variant it's more likely that it does not trigger these edge cases.
The code you post is practically "Why boost::variant is great". A dynamic allocation and random pointer index in addition to the regular indirections that both perform? That's a heavy hit (relatively).