/** * util.h: Various utility functions. * * Copyright © 2007 Pippijn van Steenhoven / The Ermyth Team * Rights to this code are as documented in doc/pod/gplicense.pod. * * $Id: util.h,v 1.8 2007/09/22 14:27:26 pippijn dead $ */ #ifndef UTIL_H #define UTIL_H #include #include #include #include #include #include /** * Mostly the same as std::vector, but erase can reorder * the elements, making insert/remove O(1) instead of O(n). * * NOTE: only some forms of erase are available * (Taken from Crossfire TRT http://cf.schmorp.de/) */ template > struct unordered_vector : std::vector { typedef typename unordered_vector::iterator iterator; void erase (unsigned pos) { if (pos < this->size () - 1) (*this)[pos] = (*this)[this->size () - 1]; this->pop_back (); } void erase (iterator pos) { erase ((unsigned)(pos - this->begin ())); } void insert (T const &val) { push_back (val); } }; /** * The following templates find a sufficiently large integer type to contain * the given number of bits. * * Usage: * * unsigned_type<16>::type a; // 16-bit unsigned if available (probably unsigned short) * signed_type<8>::type a; // 8-bit signed if available (probably char) */ // Empty class if everything failed struct empty_base { }; // To allow inheritance from this and get the integer type out template struct identity { typedef T type; }; /** * The following two templates are a compile-time if-statement. */ template struct If { typedef Then ret; }; template struct If { typedef Else ret; }; // Looks whether the desired type exists template struct type_if_size : If= bits, identity, Else>::ret { }; template struct unsigned_type : type_if_size > > > { }; template struct signed_type : type_if_size > > > { }; // This is a vector that stores each element's index in the object. // This only works for pointers to objects. template > struct indexing_vector : std::vector { typedef typename indexing_vector::size_type size_type; typedef typename indexing_vector::iterator iterator; iterator find (const T *obj) { return obj->*index ? this->begin () + obj->*index - 1 : this->end (); } void erase (T *obj) { unsigned pos = obj->*index; obj->*index = 0; if (pos < this->size ()) { (*this)[pos - 1] = (*this)[this->size () - 1]; (*this)[pos - 1]->*index = pos; } this->pop_back (); } void insert (T *obj) { this->push_back (obj); obj->*index = this->size (); } }; struct str_hash { std::size_t operator () (char const *s) const { unsigned long hash = 0; // use the one-at-a-time hash function. // see http://burtleburtle.net/bob/hash/doobs.html while (*s) { hash += *s++; hash += hash << 10; hash ^= hash >> 6; } hash += hash << 3; hash ^= hash >> 11; hash += hash << 15; return hash; } }; struct str_eq { bool operator () (char const * const s1, char const * const s2) const { if (s1 == NULL || s2 == NULL) throw nullpointer_exception (); return !strcmp (s1, s2); } }; struct str_lt { bool operator () (char const * const s1, char const * const s2) const { if (s1 == NULL || s2 == NULL) throw nullpointer_exception (); return strcmp (s1, s2) < 0; } }; E int irccasecmp (char const * const s1, char const * const s2); E int ircncasecmp (char const * const s1, char const * const s2, int maxlen); struct irccase_lt { bool operator () (char const * const s1, char const * const s2) const { if (s1 == NULL || s2 == NULL) throw nullpointer_exception (); return irccasecmp (s1, s2) < 0; } }; typedef double tstamp; inline tstamp now () { #ifdef HAVE_GETTIMEOFDAY struct timeval tv; gettimeofday (&tv, 0); return tstamp (tv.tv_sec) + tstamp (tv.tv_usec) * tstamp (1e-6); #else return tstamp (time (NULL)); #endif } #if 0 /** * Comma delimited output to std::cout */ namespace impl { struct C { template C operator << (T const &t) const { std::cout << ", " << t; return C(); } C operator << (std::ostream &(* const f) (std::ostream &)) const { std::cout << f; return C(); } C operator << (std::ios_base &(* const f) (std::ios_base &)) const { std::cout << f; return C(); } }; enum Del { del }; template C operator << (Del, T const &t) { std::cout << t; return C(); } inline Del operator << (Del, std::ostream &(* const f) (std::ostream &)) { std::cout << f; return del; } inline Del operator << (Del, std::ios_base &(* const f) (std::ios_base &)) { std::cout << f; return del; } // The <<'s taking std::ios_base&(std::ios_base&)'s are for things like std::hex. // The <<'s taking std::ostream&(std::ostream&)'s are for things like std::endl. inline Del operator << (std::ostream &, Del) { return del; } // To allow: std::cout << del << 2 << 4 } using impl::del; #endif // Allow pasting things, even if one of the arguments is a macro itself #define PASTE(A, B) DOPASTE (A, B) #define DOPASTE(A, B) DODOPASTE (A, B) #define DODOPASTE(A, B) A ## B #define PASTE3(A, B, C) PASTE (PASTE (A, B), C) #define PASTE4(A, B, C, D) PASTE (PASTE3 (A, B, C), D) #define PASTE5(A, B, C, D, E) PASTE (PASTE4 (A, B, C, D), E) #define PASTE6(A, B, C, D, E, F) PASTE (PASTE5 (A, B, C, D, E), F) namespace impl { template struct static_assert; template<> struct static_assert { }; } #define static_assert(cond) ::impl::static_assert<(cond)> PASTE (static_assert_, __LINE__) E int itoa (uint32_t n, char *buf, int buflen); E int itoa (uint64_t n, char *buf, int buflen); inline int itoa (int32_t n, char *buf, int buflen) { *buf = '-'; buf += (n < 0); uint32_t u = n < 0 ? -n : n; return itoa (u, buf, buflen - 1); } inline int itoa (int64_t n, char *buf, int buflen) { *buf = '-'; buf += (n < 0); uint64_t u = n < 0 ? -n : n; return itoa (u, buf, buflen - 1); } template inline int itoa (IntType n, char (&buf)[N]) { return itoa (n, buf, N); } #endif