Rapicorn - Experimental UI Toolkit - Source Code 10.08.1
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/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__ */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines