c++ - Optimizing loop that has QString manipulations -
in project, wrote function decompress qstring compressed using basic compression format wrote in seperate function. after testing, i've found function thing causing massive slowdowns since run on huge qstring's , called on 2900 times.
i've been trying change function runs faster. i've dabbled qstringref's no results (i might have done wrong). qbytearrays , qbyterefs hard work , check values (imo).
i really need optimizing function runs fast! fast possible! believe constant calling of .mid slowing things down, don't know other way read/write bytes.
edit: better question, there common practice i'm missing when come decompression functions? use zlib later in same program , compresses faster simple function wrote below. why that? zlib differently?
thanks time in advance. :)
here very small compressed qstring like:
//compressed //this qstring hexadecimal representation of qbytearray // qstring com("010203ff0504ff0a05ff00ff01ff02ff0306);
and, here same qstring after decompression:
//decompressed qstring decom("0102030404040404040505050505050505050505ffffffffffff06060606);
sorry if don't understand format right away... doesn't matter much. maybe helps:
-a byte "ff" tells we're decompress -the byte after "ff" number of times repeat next byte + 1 -unless number 0, 1, or 2, "ff" value repeated examples: -"010203" decompressed "010203" -"ff0401" decompressed "0101010101" -"ff02" decompressed "ffffff"
this decompression function wrote:
int hextoints(qstring num_hex) //converts byte number { uint num_uint; bool ok; num_uint = num_hex.touint(&ok,16); return (int)num_uint; } void decompress(qstring com, qstring &decom) { qstring c; //current byte qstring n; //new/next byte int bytepos(0); //current position in qstring int byterepeat; //number of times repeat byte n c = com.mid(bytepos, 2); //get first byte (01) decom.clear(); //clear decom in case had values prior { bytepos = bytepos + 2; //move current position next byte if(c == "ff") //is decompression happening? { c = com.mid(bytepos, 2); //current byte "next" byte byterepeat = hextoints(c); //c tells how many times next byte needs repeated if(byterepeat <= 2) //if c's value <= 2... ff value { n = "ff"; //new byte ff bytepos = bytepos + 2; //update current position } else //if not, c number of times next byte should appended { n = com.mid(bytepos + 2, 2); //new byte next byte bytepos = bytepos + 4; //update current position } for(int j = 0; j<=byterepeat; j++)//append n correct number of times decom.append(n); } else //guess we're not decompressing, append c decom.append(c); c = com.mid(bytepos, 2); //get new current byte }while(bytepos < com.length()); //stop when bytes read }
current optimized function based on comments: (5%-10% faster in debug mode only)
void decompress2(const qstring com, qstring &decom) { qstringref c; qstring n; int bytepos(0); int byterepeat; c = com.midref(bytepos, 2); decom.clear(); { bytepos = bytepos + 2; if(c == "ff") { c = com.midref(bytepos, 2); byterepeat = c.tostring().toint(0,16); if(byterepeat <= 2) { n = "ff"; bytepos = bytepos + 2; } else { n = com.mid(bytepos + 2, 2); bytepos = bytepos + 4; } for(int j = 0; j<=byterepeat; j++) decom.append(n); } else decom.append(c); c = com.midref(bytepos, 2); }while(bytepos < com.length()); }
you shouldn't treating array of bytes string. that's silly , noted, dead slow. use raw byte values instead , operate on them.
i know shouldn't writing code other people, had absolutely nothing better do, here in straight c++. know you're using qt , i'm of below code has equivalent in terms of qt's bytearray, that's can figure out then, if pure c++ not option.
#include <vector> #include <cstdint> #include <iomanip> #include <iostream> std::vector<std::uint8_t> decompress(const std::vector<std::uint8_t>& com) { std::vector<std::uint8_t> decom; decom.reserve(com.size()); // conservative estimate of required size for(auto = begin(com); != end(com); ++it) { if(*it == 0xff) { ++it; if(it != end(com)) { std::uint8_t number_of_repeats = *it; if(number_of_repeats <= 2) { std::fill_n(std::back_inserter(decom), number_of_repeats, 0xff); continue; } else { ++it; if(it != end(com)) std::fill_n(std::back_inserter(decom), number_of_repeats, *it); else throw 42; // handle error in way } } else throw 42; // handle error in way } else decom.push_back(*it); } return decom; } int main() { std::vector<std::uint8_t> com{0x01, 0x02, 0x03, 0xff, 0x05, 0x04, 0xff, 0x0a, 0x05, 0xff, 0x00, 0xff, 0x01, 0xff, 0x02, 0xff, 0x03, 0x06}; for(const auto& value : com) std::cout << std::hex << std::setfill('0') << std::setw(2) << static_cast<unsigned short>(value) << ' '; std::cout << '\n'; auto result = decompress(com); for(const auto& value : result) std::cout << std::hex << std::setfill('0') << std::setw(2) << static_cast<unsigned short>(value) << ' '; }
live demo here. take no responsibility respect correctness, efficiency or otherwise usability of code. written in under 5 minutes.
note believe decompressed string in long example wrong. according rules, should be
01 02 03 04 04 04 04 04 05 05 05 05 05 05 05 05 05 05 ff ff ff 06 06 06
starting 06
repeated 3 times, 2 times ff
, 1 time ff
0 times ff
, rest.
Comments
Post a Comment