|
Rapicorn - Experimental UI Toolkit - Source Code 10.08.1
|
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/rapicorncdefs.h> 00006 #include <string> 00007 #include <vector> 00008 #include <map> 00009 #include <tr1/memory> // shared_ptr 00010 #include <plic/runtime.hh> 00011 00012 #if !defined __RAPICORN_CORE_HH__ && !defined __RAPICORN_BUILD__ 00013 #error Only <rapicorn-core.hh> can be included directly. 00014 #endif 00015 00016 /* --- internally used headers and macros --- */ 00017 #ifdef RAPICORN_CONVENIENCE 00018 /* macro shorthands */ 00019 #define DIR_SEPARATOR RAPICORN_DIR_SEPARATOR 00020 #define DIR_SEPARATOR_S RAPICORN_DIR_SEPARATOR_S 00021 #define SEARCHPATH_SEPARATOR RAPICORN_SEARCHPATH_SEPARATOR 00022 #define SEARCHPATH_SEPARATOR_S RAPICORN_SEARCHPATH_SEPARATOR_S 00023 #define CODELOC() RAPICORN_CODELOC() 00024 #endif // RAPICORN_CONVENIENCE 00025 00026 namespace Rapicorn { 00027 using namespace Plic; 00028 00029 /* --- short integer types --- */ 00030 typedef RapicornUInt8 uint8; 00031 typedef RapicornUInt16 uint16; 00032 typedef RapicornUInt32 uint32; 00033 typedef RapicornUInt64 uint64; 00034 typedef RapicornInt8 int8; 00035 typedef RapicornInt16 int16; 00036 typedef RapicornInt32 int32; 00037 typedef RapicornInt64 int64; 00038 typedef RapicornUnichar unichar; 00039 00040 /* --- convenient stdc++ types --- */ 00041 using std::tr1::bad_weak_ptr; 00042 using std::tr1::enable_shared_from_this; 00043 using std::tr1::shared_ptr; 00044 using std::tr1::weak_ptr; 00045 using std::vector; 00046 using std::map; 00047 typedef std::string String; 00048 typedef vector<String> StringVector; 00049 00050 /* --- common (stdc++) utilities --- */ 00051 using ::std::swap; 00052 using ::std::min; 00053 using ::std::max; 00054 #undef abs 00055 template<typename T> inline const T& 00056 abs (const T &value) 00057 { 00058 return max (value, -value); 00059 } 00060 #undef clamp 00061 template<typename T> inline const T& 00062 clamp (const T &value, const T &minimum, const T &maximum) 00063 { 00064 if (minimum > value) 00065 return minimum; 00066 if (maximum < value) 00067 return maximum; 00068 return value; 00069 } 00070 template <class T, size_t S> inline std::vector<T> 00071 vector_from_array (const T (&array_entries)[S]) 00072 { 00073 std::vector<T> result; 00074 for (size_t i = 0; i < S; i++) 00075 result.push_back (array_entries[i]); 00076 return result; 00077 } 00078 00079 /* --- template utilities --- */ 00080 template<class X, class Y> class TraitConvertible { 00081 static bool f (...); 00082 static int f (X*); 00083 public: 00084 enum { TRUTH = sizeof (f()) != sizeof (f ((Y*) 0)), }; 00085 }; 00086 00087 /* --- helper macros --- */ 00088 #define RAPICORN_STRINGIFY(macro_or_string) RAPICORN_STRINGIFY_ARG (macro_or_string) 00089 #define RAPICORN_STRINGIFY_ARG(arg) #arg 00090 #define RAPICORN_CODELOC_STRING() std::string (std::string (__FILE__) + ":" + RAPICORN_STRINGIFY (__LINE__) + ":" + __FUNCTION__ + "()") 00091 #define RAPICORN_CODELOC() (RAPICORN_CODELOC_STRING().c_str()) 00092 00093 /* --- typeid base type --- */ 00094 class VirtualTypeid { 00095 protected: 00096 virtual ~VirtualTypeid (); 00097 public: 00098 String typeid_name (); 00099 String typeid_pretty_name (); 00100 static String cxx_demangle (const char *mangled_identifier); 00101 }; 00102 00103 /* --- NonCopyable --- */ 00104 class NonCopyable { 00105 NonCopyable& operator= (const NonCopyable&); 00106 /*Copy*/ NonCopyable (const NonCopyable&); 00107 protected: 00108 /*Con*/ NonCopyable () {} 00109 /*Des*/ ~NonCopyable () {} 00110 }; 00111 00112 /* --- private class copies, class ClassDoctor --- */ 00113 #ifdef __RAPICORN_BUILD__ 00114 class ClassDoctor; 00115 #else 00116 class ClassDoctor {}; 00117 #endif 00118 00119 /* === printing, errors, warnings, debugging === */ 00120 void printerr (const char *format, ...) RAPICORN_PRINTF (1, 2); 00121 void printerr (const std::string &msg); 00122 void printout (const char *format, ...) RAPICORN_PRINTF (1, 2); 00123 inline void breakpoint (); 00124 String process_handle (); 00125 00126 /* === internal convenience === */ 00127 #ifdef RAPICORN_CONVENIENCE 00128 #define CHECK RAPICORN_CHECK // (condition) 00129 #define PCHECK RAPICORN_PCHECK // (condition) 00130 #define ASSERT RAPICORN_ASSERT // (condition) 00131 #define PASSERT RAPICORN_PASSERT // (condition) 00132 #define DEBUG RAPICORN_DEBUG 00133 #define PDEBUG RAPICORN_PDEBUG 00134 #define return_if_fail RAPICORN_RETURN_IF_FAIL // (condition) 00135 #define return_val_if_fail RAPICORN_RETURN_VAL_IF_FAIL // (condition, value) 00136 #define assert_unreached RAPICORN_ASSERT_UNREACHED // () 00137 #define assert_not_reached RAPICORN_ASSERT_UNREACHED // () 00138 #define BREAKPOINT Rapicorn::breakpoint // () 00139 #define FIXME RAPICORN_FIXME 00140 #ifndef assert 00141 #define assert ASSERT 00142 #endif 00143 #endif // RAPICORN_CONVENIENCE 00144 00145 #if (defined __i386__ || defined __x86_64__) && defined __GNUC__ && __GNUC__ >= 2 00146 inline void breakpoint() { __asm__ __volatile__ ("int $03"); } 00147 #elif defined __alpha__ && !defined __osf__ && defined __GNUC__ && __GNUC__ >= 2 00148 inline void breakpoint() { __asm__ __volatile__ ("bpt"); } 00149 #else /* !__i386__ && !__alpha__ */ 00150 inline void breakpoint() { __builtin_trap(); } 00151 #endif 00152 #ifdef __SOURCE_FILE__ 00153 #define RAPICORN__FILE__ __SOURCE_FILE__ 00154 #elif defined __BASE_FILE__ 00155 #define RAPICORN__FILE__ __BASE_FILE__ 00156 #else 00157 #define RAPICORN__FILE__ __FILE__ 00158 #endif 00159 #define RAPICORN__FUNC__ Rapicorn::Logging::string_func (__func__, __PRETTY_FUNCTION__) 00160 00161 /* === Logging and Assertions === */ 00162 class Logging { 00163 static bool m_debugging; // cached for speedups 00164 public: 00165 static void configure (const char *option); 00166 static int conftest (const char *option, int vdefault = 0); 00167 static bool debugging () { return RAPICORN_UNLIKELY (m_debugging); } 00168 static void message (const char *kind, const char *file, int line, const char *func, 00169 const char *format, ...) RAPICORN_PRINTF (5, 6); 00170 static void messagev (const char *kind, String file, const char *format, va_list vargs); 00171 static String string_func (const char *func, const char *pretty_func = NULL); 00172 static void abort () RAPICORN_NORETURN; 00173 }; 00174 00175 static inline void fatal (const char *format, ...) RAPICORN_PRINTF (1, 2) RAPICORN_NORETURN; 00176 static inline void pfatal (const char *format, ...) RAPICORN_PRINTF (1, 2) RAPICORN_NORETURN; 00177 static inline void critical (const char *format, ...) RAPICORN_PRINTF (1, 2); 00178 static inline void pcritical (const char *format, ...) RAPICORN_PRINTF (1, 2); 00179 static inline void fatal (const char *format, ...) { va_list a; va_start (a, format); Logging::messagev ("FATAL", RAPICORN__FILE__, format, a); va_end (a); while (1); } 00180 static inline void pfatal (const char *format, ...) { va_list a; va_start (a, format); Logging::messagev ("PFATAL", RAPICORN__FILE__, format, a); va_end (a); while (1); } 00181 static inline void critical (const char *format, ...) { va_list a; va_start (a, format); Logging::messagev ("CRITICAL", RAPICORN__FILE__, format, a); va_end (a); } 00182 static inline void pcritical (const char *format, ...) { va_list a; va_start (a, format); Logging::messagev ("PCRITICAL", RAPICORN__FILE__, format, a); va_end (a); } 00183 #define RAPICORN_ASSERT_NOT_REACHED RAPICORN_ASSERT_UNREACHED 00184 #define RAPICORN_ASSERT_UNREACHED() do { Rapicorn::Logging::message ("FATAL", RAPICORN__FILE__, __LINE__, RAPICORN__FUNC__.c_str(), "encountered unreachable assertion"); Rapicorn::Logging::abort(); } while (0) 00185 #define RAPICORN_RETURN_IF_FAIL(expr) do { if (RAPICORN_LIKELY (expr)) break; Rapicorn::Logging::message ("CHECK", RAPICORN__FILE__, __LINE__, RAPICORN__FUNC__.c_str(), "assumption failed: %s", #expr); return; } while (0) 00186 #define RAPICORN_RETURN_VAL_IF_FAIL(expr,rv) do { if (RAPICORN_LIKELY (expr)) break; Rapicorn::Logging::message ("CHECK", RAPICORN__FILE__, __LINE__, RAPICORN__FUNC__.c_str(), "assumption failed: %s", #expr); return rv; } while (0) 00187 #define RAPICORN_ASSERT(expr) do { if (RAPICORN_LIKELY (expr)) break; Rapicorn::Logging::message ("ABORT", RAPICORN__FILE__, __LINE__, RAPICORN__FUNC__.c_str(), "assertion failed: %s", #expr); } while (0) 00188 #define RAPICORN_PASSERT(expr) do { if (RAPICORN_LIKELY (expr)) break; Rapicorn::Logging::message ("PABORT", RAPICORN__FILE__, __LINE__, RAPICORN__FUNC__.c_str(), "assertion failed (%s)", #expr); } while (0) 00189 #define RAPICORN_CHECK(expr) do { if (RAPICORN_LIKELY (expr)) break; Rapicorn::Logging::message ("CHECK", RAPICORN__FILE__, __LINE__, RAPICORN__FUNC__.c_str(), "assumption failed: %s", #expr); } while (0) 00190 #define RAPICORN_PCHECK(expr) do { if (RAPICORN_LIKELY (expr)) break; Rapicorn::Logging::message ("PCHECK", RAPICORN__FILE__, __LINE__, RAPICORN__FUNC__.c_str(), "assumption failed (%s)", #expr); } while (0) 00191 #define RAPICORN_DEBUG(...) do { if (RAPICORN_UNLIKELY (Rapicorn::Logging::debugging())) Rapicorn::Logging::message ("DEBUG", RAPICORN__FILE__, __LINE__, RAPICORN__FUNC__.c_str(), __VA_ARGS__); } while (0) 00192 #define RAPICORN_PDEBUG(...) do { if (RAPICORN_UNLIKELY (Rapicorn::Logging::debugging())) Rapicorn::Logging::message ("PDEBUG", RAPICORN__FILE__, __LINE__, RAPICORN__FUNC__.c_str(), __VA_ARGS__); } while (0) 00193 #define RAPICORN_FIXME(...) do { Rapicorn::Logging::message ("DEBUG", RAPICORN__FILE__, __LINE__, RAPICORN__FUNC__.c_str(), __VA_ARGS__); } while (0) 00194 00195 /* --- timestamp handling --- */ 00196 uint64 timestamp_startup (); // µseconds 00197 uint64 timestamp_realtime (); // µseconds 00198 uint64 timestamp_benchmark (); // nseconds 00199 uint64 timestamp_resolution (); // nseconds 00200 00201 /* --- file/path functionality --- */ 00202 namespace Path { 00203 String dirname (const String &path); 00204 String basename (const String &path); 00205 String abspath (const String &path, const String &incwd = ""); 00206 bool isabs (const String &path); 00207 bool isdirname (const String &path); 00208 String skip_root (const String &path); 00209 String join (const String &frag0, const String &frag1, 00210 const String &frag2 = "", const String &frag3 = "", 00211 const String &frag4 = "", const String &frag5 = "", 00212 const String &frag6 = "", const String &frag7 = "", 00213 const String &frag8 = "", const String &frag9 = "", 00214 const String &frag10 = "", const String &frag11 = "", 00215 const String &frag12 = "", const String &frag13 = "", 00216 const String &frag14 = "", const String &frag15 = ""); 00217 bool check (const String &file, 00218 const String &mode); 00219 bool equals (const String &file1, 00220 const String &file2); 00221 char* memread (const String &filename, 00222 size_t *lengthp); 00223 void memfree (char *memread_mem); 00224 String cwd (); 00225 String vpath_find (const String &file, const String &mode = "e"); 00226 String searchpath_find (const String &searchpath, const String &file, const String &mode = "e"); 00227 StringVector searchpath_split (const String &searchpath); 00228 extern const String dir_separator; /* 1char */ 00229 extern const String searchpath_separator; /* 1char */ 00230 } // Path 00231 00232 /* --- url handling --- */ 00233 void url_show (const char *url); 00234 void url_show_with_cookie (const char *url, 00235 const char *url_title, 00236 const char *cookie); 00237 bool url_test_show (const char *url); 00238 bool url_test_show_with_cookie (const char *url, 00239 const char *url_title, 00240 const char *cookie); 00241 00242 /* --- cleanup registration --- */ 00243 uint cleanup_add (uint timeout_ms, 00244 void (*destroy_data) (void*), 00245 void *data); 00246 void cleanup_force_handlers (void); 00247 00248 /* --- memory utils --- */ 00249 void* malloc_aligned (size_t total_size, 00250 size_t alignment, 00251 uint8 **free_pointer); 00252 00253 /* --- Id Allocator --- */ 00254 class IdAllocator : protected NonCopyable { 00255 protected: 00256 explicit IdAllocator (); 00257 public: 00258 virtual ~IdAllocator (); 00259 virtual uint alloc_id () = 0; 00260 virtual void release_id (uint unique_id) = 0; 00261 virtual bool seen_id (uint unique_id) = 0; 00262 static IdAllocator* _new (uint startval = 1); 00263 }; 00264 00265 /* --- C++ demangling --- */ 00266 char* cxx_demangle (const char *mangled_identifier); 00267 00268 /* --- zintern support --- */ 00269 uint8* zintern_decompress (unsigned int decompressed_size, 00270 const unsigned char *cdata, 00271 unsigned int cdata_size); 00272 void zintern_free (uint8 *dc_data); 00273 00274 /* --- template errors --- */ 00275 namespace TEMPLATE_ERROR { 00276 // to error out, call invalid_type<YourInvalidType>(); 00277 template<typename Type> void invalid_type () { bool force_compiler_error = void (0); } 00278 // to error out, derive from InvalidType<YourInvalidType> 00279 template<typename Type> class InvalidType; 00280 } 00281 00282 /* --- Deletable --- */ 00292 struct Deletable : public virtual VirtualTypeid { 00297 class DeletionHook { 00298 DeletionHook *prev; 00299 DeletionHook *next; 00300 friend class Deletable; 00301 protected: 00302 virtual ~DeletionHook (); /* { if (deletable) deletable_remove_hook (deletable); deletable = NULL; } */ 00303 virtual void monitoring_deletable (Deletable &deletable) = 0; 00304 virtual void dismiss_deletable () = 0; 00305 public: 00306 explicit DeletionHook () : prev (NULL), next (NULL) {} 00307 bool deletable_add_hook (void *any) { return false; } 00308 bool deletable_add_hook (Deletable *deletable); 00309 bool deletable_remove_hook (void *any) { return false; } 00310 bool deletable_remove_hook (Deletable *deletable); 00311 }; 00312 private: 00313 void add_deletion_hook (DeletionHook *hook); 00314 void remove_deletion_hook (DeletionHook *hook); 00315 protected: 00316 void invoke_deletion_hooks (); 00317 virtual ~Deletable (); 00318 }; 00319 00320 /* --- ReferenceCountable --- */ 00321 class ReferenceCountable : public virtual Deletable { 00322 volatile mutable uint32 ref_field; 00323 static const uint32 FLOATING_FLAG = 1 << 31; 00324 static void stackcheck (const void*); 00325 inline bool ref_cas (uint32 oldv, uint32 newv) const 00326 { return __sync_bool_compare_and_swap (&ref_field, oldv, newv); } 00327 inline uint32 ref_get() const 00328 { return __sync_fetch_and_add (&ref_field, 0); } 00329 protected: 00330 inline uint32 00331 ref_count() const 00332 { 00333 return ref_get() & ~FLOATING_FLAG; 00334 } 00335 public: 00336 ReferenceCountable (uint allow_stack_magic = 0) : 00337 ref_field (FLOATING_FLAG + 1) 00338 { 00339 if (allow_stack_magic != 0xbadbad) 00340 stackcheck (this); 00341 } 00342 bool 00343 floating() const 00344 { 00345 return 0 != (ref_get() & FLOATING_FLAG); 00346 } 00347 void 00348 ref() const 00349 { 00350 // fast-path: use one atomic op and deferred checks 00351 uint32 old_ref = __sync_fetch_and_add (&ref_field, 1); 00352 uint32 new_ref = old_ref + 1; // ...and_add (,1) 00353 RAPICORN_ASSERT (old_ref & ~FLOATING_FLAG); // check dead objects 00354 RAPICORN_ASSERT (new_ref & ~FLOATING_FLAG); // check overflow 00355 } 00356 void 00357 ref_sink() const 00358 { 00359 ref(); 00360 uint32 old_ref = ref_get(); 00361 uint32 new_ref = old_ref & ~FLOATING_FLAG; 00362 if (RAPICORN_UNLIKELY (old_ref != new_ref)) 00363 { 00364 while (RAPICORN_UNLIKELY (!ref_cas (old_ref, new_ref))) 00365 { 00366 old_ref = ref_get(); 00367 new_ref = old_ref & ~FLOATING_FLAG; 00368 } 00369 if (old_ref & FLOATING_FLAG) 00370 unref(); 00371 } 00372 } 00373 bool 00374 finalizing() const 00375 { 00376 return ref_count() < 1; 00377 } 00378 void 00379 unref() const 00380 { 00381 uint32 old_ref = ref_field; // skip read-barrier for fast-path 00382 if (RAPICORN_LIKELY (old_ref & ~(FLOATING_FLAG | 1)) && // old_ref >= 2 00383 RAPICORN_LIKELY (ref_cas (old_ref, old_ref - 1))) 00384 return; // trying fast-path with single atomic op 00385 old_ref = ref_get(); 00386 if (RAPICORN_UNLIKELY (1 == (old_ref & ~FLOATING_FLAG))) 00387 { 00388 ReferenceCountable *self = const_cast<ReferenceCountable*> (this); 00389 self->pre_finalize(); 00390 old_ref = ref_get(); 00391 } 00392 RAPICORN_ASSERT (old_ref & ~FLOATING_FLAG); // old_ref > 1 ? 00393 while (RAPICORN_UNLIKELY (!ref_cas (old_ref, old_ref - 1))) 00394 { 00395 old_ref = ref_get(); 00396 RAPICORN_ASSERT (old_ref & ~FLOATING_FLAG); // catch underflow 00397 } 00398 if (RAPICORN_UNLIKELY (1 == (old_ref & ~FLOATING_FLAG))) 00399 { 00400 ReferenceCountable *self = const_cast<ReferenceCountable*> (this); 00401 self->finalize(); 00402 self->delete_this(); // usually: delete this; 00403 } 00404 } 00405 void ref_diag (const char *msg = NULL) const; 00406 template<class Obj> static Obj& ref (Obj &obj) { obj.ref(); return obj; } 00407 template<class Obj> static Obj* ref (Obj *obj) { obj->ref(); return obj; } 00408 template<class Obj> static Obj& ref_sink (Obj &obj) { obj.ref_sink(); return obj; } 00409 template<class Obj> static Obj* ref_sink (Obj *obj) { obj->ref_sink(); return obj; } 00410 template<class Obj> static void unref (Obj &obj) { obj.unref(); } 00411 template<class Obj> static void unref (Obj *obj) { obj->unref(); } 00412 template<class Obj> static void sink (Obj &obj) { obj.ref_sink(); obj.unref(); } 00413 template<class Obj> static void sink (Obj *obj) { obj->ref_sink(); obj->unref(); } 00414 protected: 00415 virtual void pre_finalize (); 00416 virtual void finalize (); 00417 virtual void delete_this (); 00418 virtual ~ReferenceCountable (); 00419 }; 00420 template<class Obj> static Obj& ref (Obj &obj) { obj.ref(); return obj; } 00421 template<class Obj> static Obj* ref (Obj *obj) { obj->ref(); return obj; } 00422 template<class Obj> static Obj& ref_sink (Obj &obj) { obj.ref_sink(); return obj; } 00423 template<class Obj> static Obj* ref_sink (Obj *obj) { obj->ref_sink(); return obj; } 00424 template<class Obj> static void unref (Obj &obj) { obj.unref(); } 00425 template<class Obj> static void unref (Obj *obj) { obj->unref(); } 00426 template<class Obj> static void sink (Obj &obj) { obj.ref_sink(); obj.unref(); } 00427 template<class Obj> static void sink (Obj *obj) { obj->ref_sink(); obj->unref(); } 00428 00429 /* --- Locatable --- */ 00430 class Locatable : public virtual ReferenceCountable { 00431 mutable uint m_locatable_index; 00432 protected: 00433 explicit Locatable (); 00434 virtual ~Locatable (); 00435 public: 00436 uint64 locatable_id () const; 00437 static Locatable* from_locatable_id (uint64 locatable_id); 00438 }; 00439 00440 /* --- Binary Lookups --- */ 00441 template<typename RandIter, class Cmp, typename Arg, int case_lookup_or_sibling_or_insertion> 00442 static inline std::pair<RandIter,bool> 00443 binary_lookup_fuzzy (RandIter begin, 00444 RandIter end, 00445 Cmp cmp_elements, 00446 const Arg &arg) 00447 { 00448 RandIter current = end; 00449 size_t n_elements = end - begin, offs = 0; 00450 const bool want_lookup = case_lookup_or_sibling_or_insertion == 0; 00451 // const bool want_sibling = case_lookup_or_sibling_or_insertion == 1; 00452 const bool want_insertion_pos = case_lookup_or_sibling_or_insertion > 1; 00453 ssize_t cmp = 0; 00454 while (offs < n_elements) 00455 { 00456 size_t i = (offs + n_elements) >> 1; 00457 current = begin + i; 00458 cmp = cmp_elements (arg, *current); 00459 if (cmp == 0) 00460 return want_insertion_pos ? std::make_pair (current, true) : std::make_pair (current, /*ignored*/ false); 00461 else if (cmp < 0) 00462 n_elements = i; 00463 else /* (cmp > 0) */ 00464 offs = i + 1; 00465 } 00466 /* check is last mismatch, cmp > 0 indicates greater key */ 00467 return (want_lookup 00468 ? std::make_pair (end, /*ignored*/ false) 00469 : (want_insertion_pos && cmp > 0) 00470 ? std::make_pair (current + 1, false) 00471 : std::make_pair (current, false)); 00472 } 00473 template<typename RandIter, class Cmp, typename Arg> 00474 static inline std::pair<RandIter,bool> 00475 binary_lookup_insertion_pos (RandIter begin, 00476 RandIter end, 00477 Cmp cmp_elements, 00478 const Arg &arg) 00479 { 00480 /* return (end,false) for end-begin==0, or return (position,true) for exact match, 00481 * otherwise return (position,false) where position indicates the location for 00482 * the key to be inserted (and may equal end). 00483 */ 00484 return binary_lookup_fuzzy<RandIter,Cmp,Arg,2> (begin, end, cmp_elements, arg); 00485 } 00486 template<typename RandIter, class Cmp, typename Arg> 00487 static inline RandIter 00488 binary_lookup_sibling (RandIter begin, 00489 RandIter end, 00490 Cmp cmp_elements, 00491 const Arg &arg) 00492 { 00493 /* return end for end-begin==0, otherwise return the exact match element, or, 00494 * if there's no such element, return the element last visited, which is pretty 00495 * close to an exact match (will be one off into either direction). 00496 */ 00497 return binary_lookup_fuzzy<RandIter,Cmp,Arg,1> (begin, end, cmp_elements, arg).first; 00498 } 00499 template<typename RandIter, class Cmp, typename Arg> 00500 static inline RandIter 00501 binary_lookup (RandIter begin, 00502 RandIter end, 00503 Cmp cmp_elements, 00504 const Arg &arg) 00505 { 00506 /* return end or exact match */ 00507 return binary_lookup_fuzzy<RandIter,Cmp,Arg,0> (begin, end, cmp_elements, arg).first; 00508 } 00509 00510 /* --- generic named data --- */ 00511 template<typename Type> 00512 class DataKey { 00513 private: 00514 /*Copy*/ DataKey (const DataKey&); 00515 DataKey& operator= (const DataKey&); 00516 public: 00517 /* explicit */ DataKey () { } 00518 virtual Type fallback () { Type d = Type(); return d; } 00519 virtual void destroy (Type data) { /* destruction hook */ } 00520 virtual ~DataKey () {} 00521 }; 00522 00523 class DataList { 00524 class NodeBase { 00525 protected: 00526 NodeBase *next; 00527 DataKey<void> *key; 00528 explicit NodeBase (DataKey<void> *k) : next (NULL), key (k) {} 00529 virtual ~NodeBase (); 00530 friend class DataList; 00531 }; 00532 template<typename T> 00533 class Node : public NodeBase { 00534 T data; 00535 public: 00536 T get_data () { return data; } 00537 T swap (T d) { T result = data; data = d; return result; } 00538 virtual ~Node() 00539 { 00540 if (key) 00541 { 00542 DataKey<T> *dkey = reinterpret_cast<DataKey<T>*> (key); 00543 dkey->destroy (data); 00544 } 00545 } 00546 explicit Node (DataKey<T> *k, 00547 T d) : 00548 NodeBase (reinterpret_cast<DataKey<void>*> (k)), 00549 data (d) 00550 {} 00551 }; 00552 NodeBase *nodes; 00553 public: 00554 DataList() : 00555 nodes (NULL) 00556 {} 00557 template<typename T> void 00558 set (DataKey<T> *key, 00559 T data) 00560 { 00561 Node<T> *node = new Node<T> (key, data); 00562 set_data (node); 00563 } 00564 template<typename T> T 00565 get (DataKey<T> *key) const 00566 { 00567 NodeBase *nb = get_data (reinterpret_cast<DataKey<void>*> (key)); 00568 if (nb) 00569 { 00570 Node<T> *node = reinterpret_cast<Node<T>*> (nb); 00571 return node->get_data(); 00572 } 00573 else 00574 return key->fallback(); 00575 } 00576 template<typename T> T 00577 swap (DataKey<T> *key, 00578 T data) 00579 { 00580 NodeBase *nb = get_data (reinterpret_cast<DataKey<void>*> (key)); 00581 if (nb) 00582 { 00583 Node<T> *node = reinterpret_cast<Node<T>*> (nb); 00584 return node->swap (data); 00585 } 00586 else 00587 { 00588 set (key, data); 00589 return key->fallback(); 00590 } 00591 } 00592 template<typename T> T 00593 swap (DataKey<T> *key) 00594 { 00595 NodeBase *nb = rip_data (reinterpret_cast<DataKey<void>*> (key)); 00596 if (nb) 00597 { 00598 Node<T> *node = reinterpret_cast<Node<T>*> (nb); 00599 T d = node->get_data(); 00600 nb->key = NULL; // rip key to prevent data destruction 00601 delete nb; 00602 return d; 00603 } 00604 else 00605 return key->fallback(); 00606 } 00607 template<typename T> void 00608 del (DataKey<T> *key) 00609 { 00610 NodeBase *nb = rip_data (reinterpret_cast<DataKey<void>*> (key)); 00611 if (nb) 00612 delete nb; 00613 } 00614 void clear_like_destructor(); 00615 ~DataList(); 00616 private: 00617 void set_data (NodeBase *node); 00618 NodeBase* get_data (DataKey<void> *key) const; 00619 NodeBase* rip_data (DataKey<void> *key); 00620 }; 00621 00622 /* --- DataListContainer --- */ 00623 class DataListContainer { 00624 DataList data_list; 00625 public: /* generic data API */ 00626 template<typename Type> inline void set_data (DataKey<Type> *key, Type data) { data_list.set (key, data); } 00627 template<typename Type> inline Type get_data (DataKey<Type> *key) const { return data_list.get (key); } 00628 template<typename Type> inline Type swap_data (DataKey<Type> *key, Type data) { return data_list.swap (key, data); } 00629 template<typename Type> inline Type swap_data (DataKey<Type> *key) { return data_list.swap (key); } 00630 template<typename Type> inline void delete_data (DataKey<Type> *key) { data_list.del (key); } 00631 }; 00632 00633 /* --- BaseObject --- */ 00634 class BaseObject : public virtual Locatable, public virtual DataListContainer, protected NonCopyable { 00635 protected: 00636 class InterfaceMatcher; 00637 template<class C> class InterfaceMatch; 00638 static BaseObject* plor_get (const String &plor_url); 00639 void plor_name (const String &plor_name); 00640 public: 00641 String plor_name () const; 00642 virtual void dispose (); 00643 }; 00644 class NullInterface : std::exception {}; 00645 00646 struct BaseObject::InterfaceMatcher : protected NonCopyable { 00647 explicit InterfaceMatcher (const String &ident) : m_ident (ident), m_match_found (false) {} 00648 bool done () const { return m_match_found; } 00649 virtual bool match (BaseObject *object, const String &ident = String()) = 0; 00650 protected: 00651 const String &m_ident; 00652 bool m_match_found; 00653 }; 00654 00655 template<class C> 00656 struct BaseObject::InterfaceMatch : BaseObject::InterfaceMatcher { 00657 typedef C& Result; 00658 explicit InterfaceMatch (const String &ident) : InterfaceMatcher (ident), m_instance (NULL) {} 00659 C& result (bool may_throw) const; 00660 virtual bool match (BaseObject *obj, const String &ident); 00661 protected: 00662 C *m_instance; 00663 }; 00664 template<class C> 00665 struct BaseObject::InterfaceMatch<C&> : InterfaceMatch<C> { 00666 explicit InterfaceMatch (const String &ident) : InterfaceMatch<C> (ident) {} 00667 }; 00668 template<class C> 00669 struct BaseObject::InterfaceMatch<C*> : InterfaceMatch<C> { 00670 typedef C* Result; 00671 explicit InterfaceMatch (const String &ident) : InterfaceMatch<C> (ident) {} 00672 C* result (bool may_throw) const { return InterfaceMatch<C>::m_instance; } 00673 }; 00674 00675 template<class C> bool 00676 BaseObject::InterfaceMatch<C>::match (BaseObject *obj, const String &ident) 00677 { 00678 if (!m_instance) 00679 { 00680 const String &id = m_ident; 00681 if (id.empty() || id == ident) 00682 { 00683 m_instance = dynamic_cast<C*> (obj); 00684 m_match_found = m_instance != NULL; 00685 } 00686 } 00687 return m_match_found; 00688 } 00689 00690 template<class C> C& 00691 BaseObject::InterfaceMatch<C>::result (bool may_throw) const 00692 { 00693 if (!this->m_instance && may_throw) 00694 throw NullInterface(); 00695 return *this->m_instance; 00696 } 00697 00698 } // Rapicorn 00699 00700 #endif /* __RAPICORN_CORE_UTILITIES_HH__ */
1.7.4