utils.h

Go to the documentation of this file.
00001 /*
00002  *  Copyright (C) 2004-2005 Alo Sarv <madcat_@users.sourceforge.net>
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017  */
00018 
00019 /** @file utils.h Various useful utility functions. */
00020 
00021 #ifndef __UTILS_H__
00022 #define __UTILS_H__
00023 
00024 #include <stdexcept>
00025 #include <iostream>
00026 #include <sstream>
00027 #include <hn/osdep.h>
00028 #include <hn/endian.h>
00029 #include <hn/gettickcount.h>
00030 #include <sys/stat.h>
00031 #include <boost/static_assert.hpp>
00032 #include <boost/scoped_array.hpp>
00033 #include <boost/shared_array.hpp>
00034 #include <boost/filesystem/path.hpp>
00035 
00036 /**
00037  * Various utility functions
00038  */
00039 namespace Utils {
00040         /**
00041          * Convert passed data into hexadecimal notation.
00042          *
00043          * @param data       Data to be decoded.
00044          * @param length     Length of data.
00045          * @return           Hexadecimal notation of the data.
00046          */
00047         std::string DLLEXPORT decode(const char *data, uint32_t length);
00048 
00049         /**
00050          * Convert hexadecimal character string into binary format.
00051          *
00052          * @param data      Data to be encoded.
00053          * @param length    Length of data.
00054          * @return          Binary representation of the passed data.
00055          *
00056          * \note Throws std::runtime_error from hex2dec if passed data is not
00057          *       well-formed hexadecimal stream.
00058          */
00059         std::string DLLEXPORT encode(const char *data, uint32_t length);
00060 
00061         inline std::string decode(const std::string &data) {
00062                 return decode(data.data(), data.size());
00063         }
00064         inline std::string decode(const std::string &data, uint32_t length) {
00065                 return decode(data.data(), length);
00066         }
00067         inline std::string decode(boost::shared_array<char> data, uint32_t len){
00068                 return decode(data.get(), len);
00069         }
00070         inline std::string encode(const std::string &data) {
00071                 return encode(data.data(), data.size());
00072         }
00073         inline std::string encode(const std::string &data, uint32_t length) {
00074                 return encode(data.data(), length);
00075         }
00076         inline std::string encode(boost::shared_array<char> data, uint32_t len){
00077                 return encode(data.get(), len);
00078         }
00079 
00080         /**
00081          * Copy string from source to destination, overwriting destination
00082          * memory. This function assumes source string is null-terminated,
00083          * and copies until the terminating zero (including it). The destination
00084          * pointer is passed by reference and modified as neccesery during
00085          * memory reallocations to point to newly allocated memory region.
00086          *
00087          * @param src     Source, null-terminated string
00088          * @param dest    Destination
00089          */
00090         inline void copyString(const char *src, char *&dest) {
00091                 uint32_t len = strlen(src)+1;
00092                 if (dest == 0) {
00093                         dest = reinterpret_cast<char*>(malloc(len));
00094                 } else {
00095                         dest = reinterpret_cast<char*>(realloc(dest, len));
00096                 }
00097                 memcpy(dest, src, len);
00098         }
00099 
00100         /**
00101          * Retrieve the size of a file.
00102          *
00103          * @param path     Full path to the file being interested in.
00104          * @return         Size of the file.
00105          */
00106         inline uint64_t getFileSize(const boost::filesystem::path &loc) {
00107                 struct stat results;
00108                 stat(loc.native_file_string().c_str(), &results);
00109                 return results.st_size;
00110         }
00111 
00112         /**
00113          * Retrieve the last modification date of a file.
00114          *
00115          * @param path     Full path to the file being interested in.
00116          * @return         Last modification time as reported by the OS.
00117          */
00118         inline uint32_t getModDate(const boost::filesystem::path &loc) {
00119                 struct stat results;
00120                 stat(loc.native_file_string().c_str(), &results);
00121                 return results.st_mtime;
00122         }
00123 
00124         /**
00125          * Exception class, thrown when read methods detect attempt to read
00126          * past end of stream. We use this exception instead of any of
00127          * pre-defined standard exceptions to make explicit differenciating
00128          * between stream I/O errors and other generic errors thrown by STL.
00129          */
00130         class ReadError : public std::runtime_error {
00131         public:
00132                 ReadError(const std::string &msg) : std::runtime_error(msg) {}
00133         };
00134 
00135         //! Primary template is not implemented, and causes compile-time
00136         //! error if instanciated.
00137         template<class T> inline T getVal(std::istream &i) {
00138                 BOOST_STATIC_ASSERT(sizeof(T::__type_not_supported__));
00139         }
00140 
00141         //! @name Specializations for reading various datas
00142         //@{
00143         template<>
00144         inline uint8_t getVal(std::istream &i) {
00145                 BOOST_STATIC_ASSERT(sizeof(uint8_t) == 1);
00146                 uint8_t tmp;
00147                 i.read(reinterpret_cast<char*>(&tmp), 1);
00148                 if (!i.good()) {
00149                         throw ReadError("reading from stream");
00150                 }
00151                 return tmp;
00152         }
00153         template<>
00154         inline uint16_t getVal(std::istream &i) {
00155                 BOOST_STATIC_ASSERT(sizeof(uint16_t) == 2);
00156                 uint16_t tmp;
00157                 i.read(reinterpret_cast<char*>(&tmp), 2);
00158                 tmp = SWAP16_ON_BE(tmp);
00159                 if (!i.good()) {
00160                         throw ReadError("reading from stream");
00161                 }
00162                 return tmp;
00163         }
00164         template<>
00165         inline uint32_t getVal(std::istream &i) {
00166                 BOOST_STATIC_ASSERT(sizeof(uint32_t) == 4);
00167                 uint32_t tmp;
00168                 i.read(reinterpret_cast<char*>(&tmp), 4);
00169                 tmp = SWAP32_ON_BE(tmp);
00170                 if (!i.good()) {
00171                         throw ReadError("reading from stream");
00172                 }
00173                 return tmp;
00174         }
00175         template<>
00176         inline uint64_t getVal(std::istream &i) {
00177                 BOOST_STATIC_ASSERT(sizeof(uint64_t) == 8);
00178                 uint64_t tmp;
00179                 i.read(reinterpret_cast<char*>(&tmp), 8);
00180                 tmp = SWAP64_ON_BE(tmp);
00181                 if (!i.good()) {
00182                         throw ReadError("reading from stream");
00183                 }
00184                 return tmp;
00185         }
00186         template<>
00187         inline float getVal(std::istream &i) {
00188                 BOOST_STATIC_ASSERT(sizeof(float) == 4);
00189                 float tmp;
00190                 i.read(reinterpret_cast<char*>(&tmp), 4);
00191                 tmp = (float)SWAP32_ON_BE(*(uint32_t*)(&tmp));
00192                 if (!i.good()) {
00193                         throw ReadError("reading from stream");
00194                 }
00195                 return tmp;
00196         }
00197         template<>
00198         inline std::string getVal(std::istream &i) {
00199                 uint16_t len = getVal<uint16_t>(i);
00200                 boost::scoped_array<char> buf(new char[len]);
00201                 i.read(buf.get(), len);
00202                 if (!i.good()) {
00203                         throw ReadError("reading from stream");
00204                 }
00205                 return std::string(buf.get(), len);
00206         }
00207         template<class T>
00208         inline T getVal(std::istream &i, uint16_t len) {
00209                 T tmp;
00210                 i.read(&tmp, len);
00211                 if (!i.good()) {
00212                         throw ReadError("reading from stream");
00213                 }
00214                 return tmp;
00215         }
00216         template<>
00217         inline std::string getVal(std::istream &i, uint16_t len) {
00218                 boost::scoped_array<char> tmp(new char[len]);
00219                 i.read(tmp.get(), len);
00220                 if (!i.good()) {
00221                         throw ReadError("reading from stream");
00222                 }
00223                 return std::string(tmp.get(), len);
00224         }
00225         //@}
00226 
00227         //! Write. Primary template not implemented and causes compile-time
00228         //! failure if instanciated.
00229         template<class T> inline void putVal(std::ostream &o, T val) {
00230                 BOOST_STATIC_ASSERT(sizeof(T::__undefined_type__));
00231         }
00232 
00233         //! @name Writing function template specializations.
00234         //@{
00235         template<>
00236         inline void putVal(std::ostream &o, uint8_t val) {
00237                 BOOST_STATIC_ASSERT(sizeof(uint8_t) == 1);
00238                 o.put(val);
00239         }
00240         template<>
00241         inline void putVal(std::ostream &o, uint16_t val) {
00242                 BOOST_STATIC_ASSERT(sizeof(val) == 2);
00243                 val = SWAP16_ON_BE(val);
00244                 o.write(reinterpret_cast<char*>(&val), 2);
00245         }
00246         template<>
00247         inline void putVal(std::ostream &o, uint32_t val) {
00248                 BOOST_STATIC_ASSERT(sizeof(val) == 4);
00249                 val = SWAP32_ON_BE(val);
00250                 o.write(reinterpret_cast<char*>(&val), 4);
00251         }
00252         template<>
00253         inline void putVal(std::ostream &o, uint64_t val) {
00254                 BOOST_STATIC_ASSERT(sizeof(val) == 8);
00255                 val = SWAP64_ON_BE(val);
00256                 o.write(reinterpret_cast<char*>(&val), 8);
00257         }
00258         template<>
00259         inline void putVal(std::ostream &o, float val) {
00260                 BOOST_STATIC_ASSERT(sizeof(val) == 4);
00261                 val = (float)SWAP32_ON_BE(*(uint32_t*)&val);
00262                 o.write(reinterpret_cast<char*>(&val), 4);
00263         }
00264         template<>
00265         inline void putVal(std::ostream &o, const std::string &str) {
00266                 putVal<uint16_t>(o, str.size());
00267                 o.write(str.data(), str.size());
00268         }
00269         template<>
00270         inline void putVal(std::ostream &o, std::string str) {
00271                 putVal<uint16_t>(o, str.size());
00272                 o.write(str.data(), str.size());
00273         }
00274         inline void putVal(
00275                 std::ostream &o, const std::string &str, uint16_t len
00276         ) {
00277                 o.write(str.data(), len);
00278         }
00279         inline void putVal(
00280                 std::ostream &o, const char *const str, uint16_t len
00281         ) {
00282                 CHECK_THROW(str);
00283                 o.write(str, len);
00284         }
00285         inline void putVal(
00286                 std::ostream &o, const uint8_t *const str, uint16_t len
00287         ) {
00288                 CHECK_THROW(str);
00289                 o.write(reinterpret_cast<const char*>(str), len);
00290         }
00291         inline void putVal(
00292                 std::ostream &o, const boost::shared_array<char> &str,
00293                 uint16_t len
00294         ) {
00295                 CHECK_THROW(str);
00296                 o.write(str.get(), len);
00297         }
00298         //@}
00299 
00300         /**
00301          * Dumps the hexadecimal representation of a value to stream.
00302          *
00303          * @param o      Stream to write to
00304          * @param val    Value to write
00305          * @return       The original stream
00306          */
00307         template<class T> std::ostream& hexDump(std::ostream &o, T val) {
00308                 o << std::hex << "0x";
00309                 if (static_cast<int>(val)< 16) {
00310                         o << "0";
00311                 }
00312                 return o << static_cast<int>(val) << std::dec;
00313         }
00314 
00315         /**
00316          * Creates hexadecimal dump of value into a string.
00317          *
00318          * @param val    Value to convert to hex
00319          * @return       String containing the hex representation of the value
00320          */
00321         template<typename T> std::string hexDump(T val) {
00322                 std::ostringstream o;
00323                 o << std::hex << "0x";
00324                 if (static_cast<int>(val) < 16) {
00325                         o << "0";
00326                 }
00327                 o << static_cast<int>(val) << std::dec;
00328                 return o.str();
00329         }
00330         /**
00331          * Specalization - for dumping pointer types. Note: using %p argument
00332          * at boost::format generally works better and is more readable for this
00333          * purpose...
00334          *
00335          * @param val    Value to dump
00336          * @return       Hexadeciman representation of value
00337          */
00338         template<typename T> std::string hexDump(T *val) {
00339                 std::ostringstream o;
00340                 o << std::hex << "0x" << val << std::dec;
00341                 return o.str();
00342         }
00343 
00344         /**
00345          * Print hexadecimal dump of specified data into specified stream.
00346          *
00347          * @param o         Stream to write to
00348          * @param data      Data to be written
00349          */
00350         void DLLEXPORT hexDump(std::ostream &o, const std::string &data);
00351 
00352         /**
00353          * Convert passed string into formatted hexadecimal string.
00354          *
00355          * @param data      Data to convert
00356          * @return          Formatted hex-dump of the data.
00357          */
00358         std::string DLLEXPORT hexDump(const std::string &data);
00359 
00360         /**
00361         * Simple time measuring class, wrapped around getTick() method.
00362         */
00363         class DLLEXPORT StopWatch {
00364         public:
00365                 //! Constructs and starts the timer
00366                 StopWatch() : start(getTick()) {}
00367 
00368                 /**
00369                  * Retrieves the elapsed time since the construction of the
00370                  * object.
00371                  *
00372                  * @return Time elapsed in milliseconds
00373                  */
00374                 uint64_t elapsed() const { return getTick() - start; }
00375 
00376                 //! Output operator to streams
00377                 friend std::ostream& operator<<(
00378                         std::ostream &o, const StopWatch &s
00379                 ) {
00380                         return o << s.elapsed();
00381                 }
00382         private:
00383                 uint64_t start;      //!< Timer start time
00384         };
00385 
00386         /**
00387          * Convert bytes to string representation
00388          *
00389          * @param bytes      Amount of bytes to check
00390          * @return           Human-readable string, e.g. "4.56 GB"
00391          */
00392         inline std::string bytesToString(uint64_t bytes) {
00393                 boost::format fmt("%.2f %s");
00394                 if (bytes >= 1024ll*1024ll*1024ll*1024ll) {
00395                         fmt % (bytes/1024.0/1024.0/1024.0/1024.0) % "TB";
00396                 } else if (bytes >= 1024*1024*1024) {
00397                         fmt % (bytes/1024.0/1024.0/1024.0) % "GB";
00398                 } else if (bytes >= 1024*1024) {
00399                         fmt % (bytes/1024.0/1024.0) % "MB";
00400                 } else if (bytes >= 1024) {
00401                         fmt % (bytes/1024.0) % "KB";
00402                 } else if (bytes == 1) {
00403                         return "1 byte";
00404                 } else {
00405                         return (boost::format("%d bytes") % bytes).str();
00406                 }
00407                 return fmt.str();
00408         }
00409 
00410         /**
00411          * Simple generic function object for usage in standard containers,
00412          * where pointer types are stored, but actual object comparisons are
00413          * needed.
00414          * Usage:
00415          * \code
00416          * std::set<MyType*, PtrLess<MyType> > myset;
00417          * \endcode
00418          */
00419         template<typename T>
00420         struct PtrLess {
00421                 bool operator()(const T *const &x, const T *const &y) const {
00422                         return *x < *y;
00423                 }
00424                 bool operator()(const T &x, const T &y) const {
00425                         return *x < *y;
00426                 }
00427         };
00428 
00429 } //! namespace Utils
00430 
00431 #endif