Rapicorn - Experimental UI Toolkit - Source Code
13.07.0
|
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__ */