Rapicorn - Experimental UI Toolkit - Source Code  13.07.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
utilities.hh
Go to the documentation of this file.
00001  // Licensed GNU LGPL v3 or later: http://www.gnu.org/licenses/lgpl.html
00002 #ifndef __RAPICORN_CORE_UTILITIES_HH__
00003 #define __RAPICORN_CORE_UTILITIES_HH__
00004 
00005 #include <rcore/inout.hh>
00006 
00007 #if !defined __RAPICORN_CORE_HH__ && !defined __RAPICORN_BUILD__
00008 #error Only <rapicorn-core.hh> can be included directly.
00009 #endif
00010 
00011 // === Convenience Macro Abbreviations ===
00012 #ifdef RAPICORN_CONVENIENCE
00013 #include <assert.h>                                             // needed to redefine assert()
00014 #define DIR_SEPARATOR           RAPICORN_DIR_SEPARATOR          ///< Shorthand for RAPICORN_DIR_SEPARATOR.
00015 #define DIR_SEPARATOR_S         RAPICORN_DIR_SEPARATOR_S        ///< Shorthand for RAPICORN_DIR_SEPARATOR_S.
00016 #define SEARCHPATH_SEPARATOR    RAPICORN_SEARCHPATH_SEPARATOR   ///< Shorthand for RAPICORN_SEARCHPATH_SEPARATOR.
00017 #define SEARCHPATH_SEPARATOR_S  RAPICORN_SEARCHPATH_SEPARATOR_S ///< Shorthand for RAPICORN_SEARCHPATH_SEPARATOR_S.
00018 #define __PRETTY_FILE__         RAPICORN_PRETTY_FILE            ///< Shorthand for #RAPICORN_PRETTY_FILE.
00019 //#define STRFUNC()                       RAPICORN_STRFUNC() // currently in cxxaux.hh
00020 #define STRLOC()         RAPICORN_STRLOC()          ///< Shorthand for RAPICORN_STRLOC() if RAPICORN_CONVENIENCE is defined.
00021 #define return_if        RAPICORN_RETURN_IF         ///< Shorthand for RAPICORN_RETURN_IF() if RAPICORN_CONVENIENCE is defined.
00022 #define return_unless    RAPICORN_RETURN_UNLESS     ///< Shorthand for RAPICORN_RETURN_UNLESS() if RAPICORN_CONVENIENCE is defined.
00023 #endif // RAPICORN_CONVENIENCE
00024 
00025 namespace Rapicorn {
00026 
00027 // == Convenient Aida Types ==
00028 using Aida::Any;
00029 
00030 // == Common (stdc++) Utilities ==
00031 using ::std::swap;
00032 using ::std::min;
00033 using ::std::max;
00034 #undef abs
00035 template<typename T> inline const T&
00036 abs (const T &value)
00037 {
00038   return max (value, -value);
00039 }
00040 #undef clamp
00041 template<typename T> inline const T&
00042 clamp (const T &value, const T &minimum, const T &maximum)
00043 {
00044   if (minimum > value)
00045     return minimum;
00046   if (maximum < value)
00047     return maximum;
00048   return value;
00049 }
00050 template <class T, size_t S> inline std::vector<T>
00051 vector_from_array (const T (&array_entries)[S]) 
00052 {
00053   std::vector<T> result;
00054   for (size_t i = 0; i < S; i++)
00055     result.push_back (array_entries[i]);
00056   return result;
00057 }
00058 
00059 /* --- template utilities --- */
00060 template<class X, class Y> class TraitConvertible {
00061   static bool f (...);
00062   static int  f (X*);
00063 public:
00064   enum { TRUTH = sizeof (f()) != sizeof (f ((Y*) 0)), };
00065 };
00066 
00067 // === source location strings ===
00068 String  pretty_file                             (const char *file_dir, const char *file);
00073 #ifdef  __FILE_DIR__
00074 #define RAPICORN_PRETTY_FILE                    (__FILE_DIR__ "/" __FILE__)
00075 #else
00076 #define RAPICORN_PRETTY_FILE                    (__FILE__)
00077 #define __FILE_DIR__                            ""
00078 #endif
00079 #define RAPICORN_STRLOC()                       ((RAPICORN_PRETTY_FILE + ::Rapicorn::String (":") + RAPICORN_STRINGIFY (__LINE__)).c_str()) ///< Return "FILE:LINE"
00080 #define RAPICORN_STRFUNC()                      (std::string (__FUNCTION__).c_str())            ///< Return "FUNCTION()"
00081 #define RAPICORN_STRINGIFY(macro_or_string)     RAPICORN_STRINGIFY_ARG (macro_or_string)        ///< Return stringiified argument
00082 #define RAPICORN_STRINGIFY_ARG(arg)     #arg
00083 
00084 // === Control Flow Helpers ===
00085 #define RAPICORN_RETURN_IF(cond, ...)           do { if (RAPICORN_UNLIKELY (cond)) return __VA_ARGS__; } while (0)
00086 #define RAPICORN_RETURN_UNLESS(cond, ...)       do { if (RAPICORN_LIKELY (cond)) break; return __VA_ARGS__; } while (0)
00087 
00088 // === Debugging Functions (internal) ===
00089 vector<String> pretty_backtrace (uint level = 0, size_t *parent_addr = NULL) __attribute__ ((noinline));
00090 void        debug_backtrace_snapshot (size_t key);
00091 String      debug_backtrace_showshot (size_t key);
00092 inline void breakpoint ();
00093 String      process_handle ();
00094 
00095 // === Macro Implementations ===
00096 #define RAPICORN_BREAKPOINT()           Rapicorn::breakpoint()  ///< Cause a debugging breakpoint, for development only.
00097 #if (defined __i386__ || defined __x86_64__)
00098 inline void breakpoint() { __asm__ __volatile__ ("int $03"); }
00099 #elif defined __alpha__ && !defined __osf__
00100 inline void breakpoint() { __asm__ __volatile__ ("bpt"); }
00101 #else   // !__i386__ && !__alpha__
00102 inline void breakpoint() { __builtin_trap(); }
00103 #endif
00104 
00105 /* --- timestamp handling --- */
00106 uint64  timestamp_startup    ();        // µseconds
00107 uint64  timestamp_realtime   ();        // µseconds
00108 uint64  timestamp_benchmark  ();        // nseconds
00109 uint64  timestamp_resolution ();        // nseconds
00110 String  timestamp_format     (uint64 stamp);
00111 
00112 /* --- file/path functionality --- */
00113 namespace Path {
00114 String  dirname         (const String &path);
00115 String  basename        (const String &path);
00116 String  abspath         (const String &path, const String &incwd = "");
00117 bool    isabs           (const String &path);
00118 bool    isdirname       (const String &path);
00119 String  skip_root       (const String &path);
00120 String  join            (const String &frag0, const String &frag1,
00121                          const String &frag2 = "", const String &frag3 = "",
00122                          const String &frag4 = "", const String &frag5 = "",
00123                          const String &frag6 = "", const String &frag7 = "",
00124                          const String &frag8 = "", const String &frag9 = "",
00125                          const String &frag10 = "", const String &frag11 = "",
00126                          const String &frag12 = "", const String &frag13 = "",
00127                          const String &frag14 = "", const String &frag15 = "");
00128 bool    check           (const String &file,
00129                          const String &mode);
00130 bool    equals          (const String &file1,
00131                          const String &file2);
00132 char*   memread         (const String &filename,
00133                          size_t       *lengthp);
00134 void    memfree         (char         *memread_mem);
00135 String  cwd             ();
00136 String       vpath_find        (const String &file, const String &mode = "e");
00137 String       searchpath_find  (const String &searchpath, const String &file, const String &mode = "e");
00138 StringVector searchpath_split (const String &searchpath);
00139 extern const String     dir_separator;         /* 1char */
00140 extern const String     searchpath_separator;  /* 1char */
00141 } // Path
00142 
00143 /* --- url handling --- */
00144 void url_show                   (const char           *url);
00145 void url_show_with_cookie       (const char           *url,
00146                                  const char           *url_title,
00147                                  const char           *cookie);
00148 bool url_test_show              (const char           *url);
00149 bool url_test_show_with_cookie  (const char           *url,
00150                                  const char           *url_title,
00151                                  const char           *cookie);
00152 
00153 /* --- cleanup registration --- */
00154 uint cleanup_add                (uint                  timeout_ms,
00155                                  void                (*destroy_data) (void*),
00156                                  void                 *data);
00157 void cleanup_force_handlers     (void);
00158 
00159 /* --- zintern support --- */
00160 uint8*  zintern_decompress      (unsigned int          decompressed_size,
00161                                  const unsigned char  *cdata,
00162                                  unsigned int          cdata_size);
00163 void    zintern_free            (uint8                *dc_data);
00164 
00165 /* --- template errors --- */
00166 namespace TEMPLATE_ERROR {
00167 // to error out, call invalid_type<YourInvalidType>();
00168 template<typename Type> void invalid_type () { bool force_compiler_error = void (0); }
00169 // to error out, derive from InvalidType<YourInvalidType>
00170 template<typename Type> class InvalidType;
00171 } // TEMPLATE_ERROR
00172 
00173 /* --- Binary Lookups --- */
00174 template<typename RandIter, class Cmp, typename Arg, int case_lookup_or_sibling_or_insertion>
00175 static inline std::pair<RandIter,bool>
00176 binary_lookup_fuzzy (RandIter  begin,
00177                      RandIter  end,
00178                      Cmp       cmp_elements,
00179                      const Arg &arg)
00180 {
00181   RandIter current = end;
00182   size_t n_elements = end - begin, offs = 0;
00183   const bool want_lookup = case_lookup_or_sibling_or_insertion == 0;
00184   // const bool want_sibling = case_lookup_or_sibling_or_insertion == 1;
00185   const bool want_insertion_pos = case_lookup_or_sibling_or_insertion > 1;
00186   ssize_t cmp = 0;
00187   while (offs < n_elements)
00188     {
00189       size_t i = (offs + n_elements) >> 1;
00190       current = begin + i;
00191       cmp = cmp_elements (arg, *current);
00192       if (cmp == 0)
00193         return want_insertion_pos ? std::make_pair (current, true) : std::make_pair (current, /*ignored*/ false);
00194       else if (cmp < 0)
00195         n_elements = i;
00196       else /* (cmp > 0) */
00197         offs = i + 1;
00198     }
00199   /* check is last mismatch, cmp > 0 indicates greater key */
00200   return (want_lookup
00201           ? std::make_pair (end, /*ignored*/ false)
00202           : (want_insertion_pos && cmp > 0)
00203           ? std::make_pair (current + 1, false)
00204           : std::make_pair (current, false));
00205 }
00206 template<typename RandIter, class Cmp, typename Arg>
00207 static inline std::pair<RandIter,bool>
00208 binary_lookup_insertion_pos (RandIter  begin,
00209                              RandIter  end,
00210                              Cmp       cmp_elements,
00211                              const Arg &arg)
00212 {
00213   /* return (end,false) for end-begin==0, or return (position,true) for exact match,
00214    * otherwise return (position,false) where position indicates the location for
00215    * the key to be inserted (and may equal end).
00216    */
00217   return binary_lookup_fuzzy<RandIter,Cmp,Arg,2> (begin, end, cmp_elements, arg);
00218 }
00219 template<typename RandIter, class Cmp, typename Arg>
00220 static inline RandIter
00221 binary_lookup_sibling (RandIter  begin,
00222                        RandIter  end,
00223                        Cmp       cmp_elements,
00224                        const Arg &arg)
00225 {
00226   /* return end for end-begin==0, otherwise return the exact match element, or,
00227    * if there's no such element, return the element last visited, which is pretty
00228    * close to an exact match (will be one off into either direction).
00229    */
00230   return binary_lookup_fuzzy<RandIter,Cmp,Arg,1> (begin, end, cmp_elements, arg).first;
00231 }
00232 template<typename RandIter, class Cmp, typename Arg>
00233 static inline RandIter
00234 binary_lookup (RandIter  begin,
00235                RandIter  end,
00236                Cmp       cmp_elements,
00237                const Arg &arg)
00238 {
00239   /* return end or exact match */
00240   return binary_lookup_fuzzy<RandIter,Cmp,Arg,0> (begin, end, cmp_elements, arg).first;
00241 }
00242 
00243 template<typename Value> static inline int 
00244 compare_lesser (const Value &v1, const Value &v2)
00245 {
00246   return -(v1 < v2) | (v2 < v1);
00247 }
00248 
00249 template<typename Value> static inline int 
00250 compare_greater (const Value &v1, const Value &v2)
00251 {
00252   return (v1 < v2) | -(v2 < v1);
00253 }
00254 
00255 // == Custom Keyed Data ==
00257 template<typename Type> class DataKey {
00258 private:
00259   /*Copy*/        DataKey    (const DataKey&);
00260   DataKey&        operator=  (const DataKey&);
00261 public:
00262   /* explicit */  DataKey    ()                 { }
00263   virtual Type    fallback   ()                 { Type d = Type(); return d; }  
00264   virtual void    destroy    (Type data)        { /* destruction hook */ }      
00265   virtual        ~DataKey    ()                 {}
00266 };
00267 
00268 class DataList {
00269   class NodeBase {
00270   protected:
00271     NodeBase      *next;
00272     DataKey<void> *key;
00273     explicit       NodeBase (DataKey<void> *k) : next (NULL), key (k) {}
00274     virtual       ~NodeBase ();
00275     friend         class DataList;
00276   };
00277   template<typename T>
00278   class Node : public NodeBase {
00279     T data;
00280   public:
00281     T        get_data ()     { return data; }
00282     T        swap     (T d)  { T result = data; data = d; return result; }
00283     virtual ~Node()
00284     {
00285       if (key)
00286         {
00287           DataKey<T> *dkey = reinterpret_cast<DataKey<T>*> (key);
00288           dkey->destroy (data);
00289         }
00290     }
00291     explicit Node (DataKey<T> *k,
00292                    T           d) :
00293       NodeBase (reinterpret_cast<DataKey<void>*> (k)),
00294       data (d)
00295     {}
00296   };
00297   NodeBase *nodes;
00298   RAPICORN_CLASS_NON_COPYABLE (DataList);
00299 public:
00300   DataList() :
00301     nodes (NULL)
00302   {}
00303   template<typename T> void
00304   set (DataKey<T> *key,
00305        T           data)
00306   {
00307     Node<T> *node = new Node<T> (key, data);
00308     set_data (node);
00309   }
00310   template<typename T> T
00311   get (DataKey<T> *key) const
00312   {
00313     NodeBase *nb = get_data (reinterpret_cast<DataKey<void>*> (key));
00314     if (nb)
00315       {
00316         Node<T> *node = reinterpret_cast<Node<T>*> (nb);
00317         return node->get_data();
00318       }
00319     else
00320       return key->fallback();
00321   }
00322   template<typename T> T
00323   swap (DataKey<T> *key,
00324         T           data)
00325   {
00326     NodeBase *nb = get_data (reinterpret_cast<DataKey<void>*> (key));
00327     if (nb)
00328       {
00329         Node<T> *node = reinterpret_cast<Node<T>*> (nb);
00330         return node->swap (data);
00331       }
00332     else
00333       {
00334         set (key, data);
00335         return key->fallback();
00336       }
00337   }
00338   template<typename T> T
00339   swap (DataKey<T> *key)
00340   {
00341     NodeBase *nb = rip_data (reinterpret_cast<DataKey<void>*> (key));
00342     if (nb)
00343       {
00344         Node<T> *node = reinterpret_cast<Node<T>*> (nb);
00345         T d = node->get_data();
00346         nb->key = NULL; // rip key to prevent data destruction
00347         delete nb;
00348         return d;
00349       }
00350     else
00351       return key->fallback();
00352   }
00353   template<typename T> void
00354   del (DataKey<T> *key)
00355   {
00356     NodeBase *nb = rip_data (reinterpret_cast<DataKey<void>*> (key));
00357     if (nb)
00358       delete nb;
00359   }
00360   void clear_like_destructor();
00361   ~DataList();
00362 private:
00363   void      set_data (NodeBase      *node);
00364   NodeBase* get_data (DataKey<void> *key) const;
00365   NodeBase* rip_data (DataKey<void> *key);
00366 };
00367 
00368 } // Rapicorn
00369 
00370 #endif /* __RAPICORN_CORE_UTILITIES_HH__ */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines