C++ initialize variable based on condition [closed] - c++

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I am currently trying to figure out how to initialize variables based on conditions. So this is the current code that I want to modify:
int dimsOut[4];
dimsOut[0] = data->nDataVar();
dimsOut[1] = dims[0];
dimsOut[2] = dims[1];
dimsOut[3] = dims[2];
const size_t dataSize = data->primType().getTypeSize() * dimsOut[0] * dimsOut[1] * dimsOut[2] * dimsOut[3];
Since this is part of a giant project (mostly C++98 with some parts of C++03) I want to try to modify as less as possible to avoid any problems in the rest of the code.
So what I want to do is simply in case data->nDataVar() returns 1 that the code above executes and in case it returns something else it should
basically do this
int dimsOut[3];
dimsOut[0] = data->nDataVar();
dimsOut[1] = dims[0];
dimsOut[2] = dims[1];
const size_t dataSize = data->primType().getTypeSize() * dimsOut[0] * dimsOut[1] * dimsOut[2];
I am aware that it is not possible to use if-statements since the variables would go out of scope.
Edit: I solved my problem now. It is not beautiful, but it does what it is supposed to do.
Edit2: small change
int decide_dimension = data->nDataVar();
std::vector<int> dimsOut;
dimsOut.resize(3);
dimsOut[0] = dims[0];
dimsOut[1] = dims[1];
dimsOut[2] = dims[2];
if (decide_dimension != 1)
{
dimsOut.push_back(data->nDataVar());
}
const size_t dataSize = data->primType().getTypeSize() * dimsOut[0] * dimsOut[1] * dimsOut[2] * ((decide_dimension == 1) ? 1 : dimsOut[3]);

You can use the ternary or conditional operator. The basic form is:
condition ? valueIfTrue : valueIfFalse
Example:
const char* x = (SomeFunction() == 0) ? "is null" : "is not null";
When SomeFunction() returns 0, x is initialised with "is null", otherwise
with "is not null".

What you want to achieve is not possible. The only thing you can do, is to initialize them with a ternary as suggested or move the initialization into a if block and leave the declaration out.

You say you are modifying an existing old project. In that case it makes sense to keep changes minimal.
However, you can't define the size of a static array at run time. If you want, you can keep the array as it currently is and make sure you don't use the 4th element when data->nDataVar() != 1.
Then:
const size_t dataSize = data->primType().getTypeSize() * dimsOut[0] * dimsOut[1] * dimsOut[2] * (data->nDataVar() != 1 ? 1 : dimsOut[3]);
It's worth mentioning the dimsOut array seems completely unnecessary to calculate the value of dataSize, but who knows what else your code is doing with it. If it is only used inside a single function/method then you could easily replace it with something else, such as std::vector.

Your question is a bit confusing, or rather not enough information was provided. It is not clear if the dimsOut[] variable is needed elsewhere. In case it is used ONLY for the computation of dataSize, you can use directly the dims[] array and do:
int typeSize = data->primType().getTypeSize() * data->nDataVar();
int dimension = dims[0] * dims[1] * ((condition) ? dims[2] : 1);
const size_t dataSize = typeSize * dimension;
In case that dimsOut is used elsewhere, then you can use the first block modifying the dimsOut[3] assignment with the ternary operator:
int dimsOut[4];
dimsOut[0] = data->nDataVar();
dimsOut[1] = dims[0];
dimsOut[2] = dims[1];
dimsOut[3] = (condition) ? dims[2] : 1;
const size_t dataSize = data->primType().getTypeSize() * dimsOut[0] * dimsOut[1] * dimsOut[2] * dimsOut[3];

Related

How do I reuse my hasher in another hasher?

I have been given a task to write a C++ program that stores an unordered_set of objects street. At the same time, object street is to contain some general info and an unordered_set of objects house. I have written a structure-hasher for house
struct house_hasher {
std::hash<std::string> number_hash;
std::hash<size_t> storeys_hash;
std::hash<size_t> aparts_hash;
std::hash<size_t> residents_hash;
std::hash<std::string> street_name_hash;
std::hash<double> pfsm_hash;
std::hash<double*> pea_hash;
std::hash<double*> sea_hash;
std::hash<bool*> ps_hash;
size_t operator()(const house& h) const {
const size_t coef = 2'946'901;
size_t hash_value = 0;
hash_value = (pow(coef, 8) * number_hash(h.getter_number()) +
pow(coef, 7) * storeys_hash(h.getter_storeys_n()) +
pow(coef, 6) * aparts_hash(h.getter_aparts_n()) +
pow(coef, 5) * residents_hash(h.getter_residents_n()) +
pow(coef, 4) * street_name_hash(h.getter_street_name()) +
pow(coef, 3) * pfsm_hash(h.getter_price_for_square_meter()) +
pow(coef, 2) * pea_hash(h.getter_payments_each_apartments()) +
coef * sea_hash(h.getter_square_each_apartments()) +
ps_hash(h.getter_payments_statuses()));
return hash_value;
}
};
to enable adding house to the container and it works correctly. But the thing is that I have to write a structure-hasher for object street since it must be addable as well. I assume I could easily add another structure and copy-paste the code from the initial structure to the one mentioned, so that the part, that hashes houses, repeats twice in the project but still it seems to be stupid.
What I want to do is to create one more structure-hasher for streets but to use the object of house_hasher in it and be able to hash houses like that
struct street_hasher {
std::hash<std::string> name_hash;
std::hash<size_t> number_hash;
std::hash<size_t> houses_hash;
std::hash<std::unordered_set<house, house_hasher>> uset_houses_hash;
size_t operator()(const street& s) const {
const size_t coef = 2'946'901;
size_t hash_value = 0;
size_t add_hash = 0;
house_hasher hasher_for_house;
std::unordered_set<house, house_hasher>::iterator uset_it = s.getter_street_uset_houses().begin();
for (uset_it; uset_it != s.getter_street_uset_houses().end(); ++uset_it) {
add_hash += hasher_for_house(*uset_it);
}
hash_value = (pow(coef, 3) * name_hash(s.getter_street_name()) +
pow(coef, 2) * number_hash(s.getter_street_number()) +
coef * houses_hash(s.getter_street_houses_n()) +
add_hash);
return hash_value;
}
};
However, this does not seem to be correct. VS throws an error C2280 "std::_Uhash_compare<_Kty,_Hasher,_Keyeq>::_Uhash_compare(const std::_Uhash_compare<_Kty,_Hasher,_Keyeq> &)": предпринята попытка ссылки на удаленную функцию
The last few words say an attempt to refer to deleted function occurred.
I have tried a lot of ideas of mine and those found on the net. Still, there is no output. Could anybody please tell me how to solve this tricky problem?
Thanks in advance!
The solution is to arrange the street_hasher structure this way (it works but I am sure there is another way to make this work which would be more elegant and laconic):
struct street_hasher {
std::hash<std::string> name_hash;
std::hash<size_t> number_hash;
std::hash<size_t> houses_hash;
size_t operator()(const street& s) const {
const size_t coef = 2'946'901;
size_t hash_value = 0;
size_t add_hash = 0;
house_hasher hasher_for_house; // need this to hash houses
std::unordered_set < house, house_hasher > uset = s.getter_street_uset_houses();
std::unordered_set<house, house_hasher>::iterator uset_it = uset.begin();
std::unordered_set<house, house_hasher>::iterator end_it = uset.end();
size_t houses_it = s.getter_street_houses_n() + 2;
// there is 2 as we have y = 3 more attributes to hash in street
// but we start with the power of n - 1, where n = houses_n + y =>
// => n = s.getter_street_houses_n() + 3
// => n - 1 = s.getter_street_houses_n() + 2
hash_value = (pow(coef, houses_it) * name_hash(s.getter_street_name()) +
pow(coef, houses_it - 1) * number_hash(s.getter_street_number()) +
pow(coef, houses_it - 2) * houses_hash(s.getter_street_houses_n()) +
add_hash);
houses_it -= 3;
for (uset_it; uset_it != end_it; ++uset_it) {
add_hash += pow(coef, houses_it) * hasher_for_house(*uset_it);
--houses_it;
}
// I guess it is much safer to treat each house as an independent attribute
hash_value += add_hash;
return hash_value;
}
};
I have deleted std::hash<std::unordered_set<house, house_hasher>> uset_houses_hash; from the header and it stopped throwing the error. After one problem went away, another one came. The compiler was angry at how I initialized the loop saying list iterators incompatible. I have just rearranged the function a bit by setting so-called static house_hasher and iterators. As an addition, I came up with a thought to deal with each house in unordered_set as with a different attribute of street, so that we avoid collisions (I may have just said something stupid but still let it be this way). Thus, such way of hashing seems to me say more safer. Anyway, it works!
Cheers!

What does this cast assign? C Style Casting

this is my first question on here.
I am currently trying to understand how this code works.
I basically want to assign a certain value to an array named "hv" of type uint8_t.
I do not quite understand what this cast does/how it works.
for (i = 0; i < 4; i++) {
hv[i] = *(uint16_t *)(h1 + 8 + i * 2);
}
I do understand that it is trying to cast the 2nd part to an uint16_t pointer but i do not know what the first asterisk does.
Help would be greatly appreciated.
I assume that h1 is a pointer. Otherwise this makes no sense at all.
The expression (h1 + 8 + i * 2) will give a new pointer, which is offseted relative to h1. Exactly by now much depends on sizeof(*h1). The offset vill be (8+i*2)*sizeof(*h1) bytes.
Putting (uint_16_t *) in front of this will convert it to a uint_16_t pointer. Putting an asterisk in front of that will give you the content of that memory location, treated as an uint_16_t.
The code is equivalent to:
for (i = 0; i < 4; i++) {
uint_16_t * tmp = (uint16_t *)(h1 + 8 + i * 2);
hv[i] = *tmp;
}

C++ optimizations

I'm doing some real-time stuff and I need a lot of speed. But in my code, I have this :
float maxdepth;
uint32_t faceindex;
for (uint32_t tr_iterator = 0; tr_iterator < facesNum-1; tr_iterator++)
{
maxdepth = VXTrisDepth[tr_iterator];
faceindex = tr_iterator;
uint32_t tr_literator = 3*tr_iterator;
uint32_t facelindex = 3*faceindex;
for (uint32_t tr_titerator = tr_iterator+1; tr_titerator < facesNum; tr_titerator++)
{
float depth = VXTrisDepth[tr_titerator];
if (depth > maxdepth)
{
maxdepth = depth;
faceindex = tr_titerator;
}
}
Vei2 itmpx = trs[tr_literator+0];
trs[tr_literator+0] = trs[facelindex+0];
trs[facelindex+0] = itmpx;
itmpx = trs[tr_literator+1];
trs[tr_literator+1] = trs[facelindex+1];
trs[facelindex+1] = itmpx;
itmpx = trs[tr_literator+2];
trs[tr_literator+2] = trs[facelindex+2];
trs[facelindex+2] = itmpx;
float id = VXTrisDepth[tr_iterator];
VXTrisDepth[tr_iterator] = VXTrisDepth[faceindex];
VXTrisDepth[faceindex] = id;
}
VXTrisDepth is just an array of float, faceindex is a uint32_t and is a big number, trs is an array of Vei2, and Vei2 is just a integer 2D vector.
The problem is that when we have something like 16074 in facenum, this loop takes 700ms to run on my computer, and that's way too much, any idea of optimizations ?
I've rewritten it a bit to find out what you really was doing.
Warning all code is untested
float maxdepth;
uint32_t faceindex;
for (uint32_t tr_iterator = 0; tr_iterator < facesNum-1; tr_iterator++) {
faceindex = tr_iterator;
uint32_t tr_literator = 3*tr_iterator;
uint32_t facelindex = 3*faceindex;
auto fi = std::max_element(&VXTrisDepth[tr_iterator], &VXTrisDepth[facesNum]);
maxdepth = *fi;
faceindex = std::distance(&VXTrisDepth[0], fi);
// hmm was this originally a VEC3...
std::swap(trs[tr_literator+0], trs[facelindex+0]);
std::swap(trs[tr_literator+1], trs[facelindex+1]);
std::swap(trs[tr_literator+2], trs[facelindex+2]);
// with the above this looks like a struct of arrays. SOA vs AOS
std::swap(VXTrisDepth[tr_iterator], VXTrisDepth[faceindex]);
}
Now it looks like selection sort of two arrays which is O(N^2) no wonder it feels slow.
There are multiple methods to sort this
External index, make an array with length facesNum, initalized from zero to facesNum-1 and sort them using the index into VXTrisDepth. Then reorder the 2 original arrays according to the index array.
External pair of index and key, to make it easy use std::pair, sort it and then reorder the original 2 arrays.
sort the 2 arrays as if it was one, slight hack. using std::swap you need to specialize on a type so it can be misused to swap 2 arrays. No extra storage needed.
Lets try an easy version with the external pair.
We need 3 stages
make helper array O(N)
sort helper array O(N lg N)
reorder original arrays O(N)
And some more code
// make helper array
using hPair = std::pair<float, int>; // order is important
std::vector<hPair> helper;
helper.reserve(numFaces);
for (int idx = 0; idx < facesNum; idx++)
helper.emplace_back(VXTrisDepth[idx], idx);
// sort it using std::pair's operator < or write your own
std::sort(helper.begin(), helper.end());
// reorder the SOA arrays
auto vx = std::begin(VXTrisDepth);
for (auto& help : helper) {
int tr_literator = help.second;
std::swap(trs[tr_literator+0], trs[facelindex+0]);
std::swap(trs[tr_literator+1], trs[facelindex+1]);
std::swap(trs[tr_literator+2], trs[facelindex+2]);
*vs++ = help.first; // we already have the sorted depth in helper.
//std::swap(VXTrisDepth[tr_iterator], VXTrisDepth[faceindex]);
}
Remember to test that it still works ... you already have a test framework right?

Expression must be a modifiable lvalue (when attempting to append to an array)

I have the following:
uint16_t Hitcount[64]; //64-byte array buffer
uint16_t Br;
int StdWidth = 38;
int widthpad = 8;
int W;
uint16_t blocks;
if (W <= (StdWidth + widthpad) && W >= (StdWidth - widthpad) && blocks == 1) {
Hitcount += Br;
}
My goal is to appenf "Br" to the array "Hitcount" if "W" is within a certain range. However, "Hitcount" is indicating the error "Expression must be a modifiable lvalue". Don't I have my data types and everything in order?
Apologies if this is too close to other questions that have been posted. I looked at them but could not relate them to this scenario with my limited knowledge.
Hitcount += Br;
You cannot add value to a C style array like that. You either need to maintain elements count and add a value like this:
Hitcount[count++] = Br;
or you better use std::vector and add element by calling push_back:
std::vector<uint16_t> Hitcount;
// code skipped
Hitcount.push_back( Br );
Plain C/C++ arrays cannot be extended the way string objects can. Look into using std::vector.

Anti-Digest operation on string always returning the same value [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I am looking for some way to "digest" a string, but always return the same 32 (or 64) byte long value (as a hex string or plain characters). Something like the following code does:
std::string digest(const std::string& input)
{
std::string result = "";
// do something with the input string, update result accordingly
return result;
}
and a little bit more details: I want exactly the opposite of what a classical digest function does which is that for each different string it returns a different but always the same (1 to 1) value. I want a function which for each string returns every time the same value (n to 1).
Obviously, "easy" solutions as return the same constant result every time are not considered a solution :) The code should actually digest the input string and build up the result as a result of the operation.
And an example:
digest ("fox") == digest ("whale")
should be true.
Or mathematically speaking:
for ∀ a and b if a != b => digest (a) == digest(b). That is why i called this anti-digest.
A long mathematical demonstration
Your requirement is:
a!=b => digest(a)==digest(b)
Let's take another message any other message c, and suppose it's different from a and b:
a!=c => digest(a)==digest(c)
b!=c => digest(b)==digest(c)
From this you see that the digest will be constant for any c unless it is equal to a or b.
Now take another message x whatever it may be:
c!=x => digest(c)==digest(x)
By contraposing this implication, this is equivalent to :
digest(x)!=digest(c) => c==x
So suppose there would be an x with a digest different from the constant digest(c). The we have:
digest(x)!=digest(c) and digest(x)!=digest(a)
=> x==c and x==a
=> c==a
=> digest(c)!=digest(a)
But this contradict out original hypothesis about a, c, digest(a) and digest(c), so there can't be such an x. So you can conclude that your digest MUST BE a strictly constant function.
Now suppose your function would not be constant:
digest(x)!=digest(a) => x==a
but if digest is a function, it will always return the same result for the same input, meaning that x==a => digest(x) ==digest(a). This demonstrates that there is no other solution than a constant function.
In short and in C++
A function will return the same result for the same parameter, unless there are side effet (static variable or whatever). Your requirement of having same result for different values, but different result for same values is simply not feasible in a function with only one parameter.
It seems, I was somehow unclear on what I want to achieve ...
Anyway, I came up with the following:
static const size_t DIGEST_SIZE = 32;
std::string antiDigest(const std::string& a)
{
if(a.empty()) { throw "cannot digest empty string"; }
char r[DIGEST_SIZE ] = {0};
int block_size = std::min(DIGEST_SIZE, a.length());
int block_count = 1 + DIGEST_SIZE / a.length();
for(int i=0; i<block_size; i++)
{
int hlp = 0, bc = 0;
while(bc < block_count)
{
int idx = i + bc * block_size;
if(idx >= a.length()) break;
hlp += a[idx];
bc ++;
}
hlp = (int)(hlp << 3) + hlp;
unsigned int hlp2 = 0;
while(hlp)
{
int t = hlp - ((hlp/10) * 10);
hlp2 += t;
hlp /= 10;
}
bc = 0;
while(bc < block_count)
{
int idx = i + bc * block_size;
if(idx >= DIGEST_SIZE) break;
r[idx] = ( (hlp2 / 10) + (hlp2-(hlp2/10)*10)) ;
bc++;
}
}
std::stringstream result;
for(int i=0; i<DIGEST_SIZE; i++)
{
result << int_to_hex(r[i]) ;
}
return result.str();
}
On ideone: http://ideone.com/t4dibL
Obviously, this can be obfuscated even more with replacing the mathematical operations with bitwise operations, but for a proof of concept this does it.