Just to demonstrate another, probably much faster, way of doing things consider reading everything into an array and using a custom iterator to do the converting.
class ToHexIterator : public std::iterator<std::input_iterator_tag, int>{
char* it_;
char* end_;
int current_;
bool isHex(const char c){
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
}
char toUpperCase(const char c){
if (c >= 'a' && c <= 'f'){
return (c - 'a') + 'A';
}
return c;
}
int toNibble(const char c){
auto x = toUpperCase(c);
if (x >= '0' && x <= '9'){
return x - '0';
}
else {
return (x - 'A') + 10;
}
}
public:
ToHexIterator() :it_{ nullptr }, end_{ nullptr }, current_{}{} //default constructed means end iterator
ToHexIterator(char* begin, char* end) :it_{ begin }, end_{ end }, current_{}{
while (!isHex(*it_) && it_ != end_){ ++it_; }; //make sure we are pointing to valid stuff
++(*this);
}
bool operator==(const ToHexIterator &other){
return it_ == nullptr && end_ == nullptr && other.it_ == nullptr && other.end_ == nullptr;
}
bool operator!=(const ToHexIterator &other){
return !(*this == other);
}
int operator*(){
return current_;
}
ToHexIterator & operator++(){
current_ = 0;
if (it_ != end_) {
while (isHex(*it_) && it_ != end_){
current_ <<= 4;
current_ += toNibble(*it_);
++it_;
};
while (!isHex(*it_) && it_ != end_){ ++it_; };
}
else {
it_ = nullptr;
end_ = nullptr;
}
return *this;
}
ToHexIterator operator++(int){
ToHexIterator temp(*this);
++(*this);
return temp;
}
};
The basic use case would look like:
char in[] = "1,3,8,b,e,ff,10,--";
std::vector<int> v;
std::copy(ToHexIterator{ std::begin(in), std::end(in) }, ToHexIterator{}, std::back_inserter(v));
Note that it may be faster to use a look up table to do the ascii to hex nibble conversion.
Speed can be VERY dependent on compiler optimization and platform, however because some of the istringstream functions are implemented as virtuals or pointer to functions (depending on the standard library implementation) the optimizer has trouble with them. In my code there are no victuals or function pointers and the only loop is inside the std::copy implementation which the optimizer is used to dealing with. Its also generally faster to loop until two addresses are equal rather than loop until the thing some changing pointer points to is equal to something. At the end of the day its all speculation and voodoo but on MSVC13 on my machine mine is about 10X faster. Here is a live example http://ideone.com/nuwu15 on GCC which is somewhere between 10x and 3x depending on the run and depending on which test goes first (probably because of some caching effects).
All in all there is undoubtedly more room for optimization etc. and anyone who says "mine is always faster" at this level of abstraction is selling snake oil.
Update: using a compile time generated look up table increases speed further: http://ideone.com/ady8GY (note that I increased the size of the input string to decrease noise so this is not directly comparable to the above example)