|
||||
File indexing completed on 2025-01-17 09:55:19
0001 /*- 0002 * Copyright (c) 2009, 2020 Oracle and/or its affiliates. All rights reserved. 0003 * 0004 * See the file LICENSE for license information. 0005 * 0006 * $Id$ 0007 */ 0008 0009 #ifndef _DB_STL_UTILITY_H__ 0010 #define _DB_STL_UTILITY_H__ 0011 0012 #include "dbstl_inner_utility.h" 0013 0014 START_NS(dbstl) 0015 0016 // This class allows users to configure dynamically how a specific type of 0017 // object is copied, stored, restored, and how to measure the type's 0018 // instance size. 0019 /** \defgroup dbstl_helper_classes dbstl helper classes 0020 Classes of this module help to achieve various features of dbstl. 0021 */ 0022 /** \ingroup dbstl_helper_classes 0023 @{ 0024 This class is used to register callbacks to manipulate an object of a 0025 complex type. These callbacks are used by dbstl at runtime to 0026 manipulate the object. 0027 0028 A complex type is a type whose members are not located in a contiguous 0029 chunk of memory. For example, the following class A is a complex type 0030 because for any instance a of class A, a.b_ points to another object 0031 of type B, and dbstl treats the object that a.b_ points to as part of 0032 the data of the instance a. Hence, if the user needs to store a.b_ into 0033 a dbstl container, the user needs to register an appropriate callback to 0034 de-reference and store the object referenced by a.b. Similarly, the 0035 user also needs to register callbacks to marshall an array as well as 0036 to count the number of elements in such an array. 0037 0038 class A { int m; B *p_; }; 0039 class B { int n; }; 0040 0041 The user also needs to register callbacks for 0042 i). returning an object¡¯s size in bytes; 0043 ii). Marshalling and unmarshalling an object; 0044 iii). Copying a complex object and and assigning an object to another 0045 object of the same type; 0046 iv). Element comparison. 0047 v). Compare two sequences of any type of objects; Measuring the length 0048 of an object sequence and copy an object sequence. 0049 0050 Several elements located in a contiguous chunk of memory form a sequence. 0051 An element of a sequence may be a simple object located at a contigous 0052 memory chunk, or a complex object, i.e. some of its members may contain 0053 references (pointers) to another region of memory. It is not necessary 0054 to store a special object to denote the end of the sequence. The callback 0055 to traverse the constituent elements of the sequence needs to able to 0056 determine the end of the sequence. 0057 0058 Marshalling means packing the object's data members into a contiguous 0059 chunk of memory; unmarshalling is the opposite of marshalling. In other 0060 words, when you unmarshall an object, its data members are populated 0061 with values from a previously marshalled version of the object. 0062 0063 The callbacks need not be set to every type explicitly. . dbstl will 0064 check if a needed callback function of this type is provided. 0065 If one is available, dbstl will use the registered callback. If the 0066 appropriate callback is not provided, dbstl will use reasonable defaults 0067 to do the job. 0068 0069 For returning the size of an object, the default behavior is to use the 0070 sizeof() operator; For marshalling and unmarshalling, dbstl uses memcpy, 0071 so the default behavior is sufficient for simple types whose data reside 0072 in a contiguous chunk of memory; Dbstl uses uses >, == and < for 0073 comparison operations; For char* and wchar_t * strings, dbstl already 0074 provides the appropriate callbacks, so you do not need to register them. 0075 In general, if the default behavior is adequate, you don't need to 0076 register the corresponding callback. 0077 0078 If you have registered proper callbacks, the DbstlElemTraits<T> can also be 0079 used as the char_traits<T> class for std::basic_string<T, char_traits<T> >, 0080 and you can enable your class T to form a basic_string<T, DbstlElemTraits<T>>, 0081 and use basic_string's functionality and the algorithms to manipulate it. 0082 */ 0083 template <typename T> 0084 class _exported DbstlElemTraits : public DbstlGlobalInnerObject 0085 { 0086 public: 0087 /// \name Callback_typedefs Function callback type definitions. 0088 /// Following are the callback function types, there is one function 0089 /// pointer data member for each of the type, and a pair of set/get 0090 /// functions for each function callback data member, and this is 0091 /// the structure of this class. 0092 //@{ 0093 /// Assign object src to object dest. Most often assignment callback 0094 /// is not needed - the class copy constructor is sufficient. 0095 /// This description talks about the function of this type, rather 0096 /// than the type itself, this is true to all the types in the group. 0097 typedef void (*ElemAssignFunct)(T& dest, const T&src); 0098 /// Read data from the chunk of memory pointed by srcdata, and assign 0099 /// to the object dest. This is also called unmashall. 0100 typedef void (*ElemRstoreFunct)(T& dest, const void *srcdata); 0101 /// Return object elem's size in bytes. 0102 typedef u_int32_t (*ElemSizeFunct)(const T& elem); 0103 /// Copy object elem's data to be persisted into a memory chunk 0104 /// referenced by dest. The dest memory is large enough. 0105 /// elem may not reside on a 0106 /// consecutive chunk of memory. This is also called marshal. 0107 typedef void (*ElemCopyFunct)(void *dest, const T&elem); 0108 typedef int (*ElemCompareFunct)(const T&a, const T&b); 0109 /// Compares first num number of elements of sequence a and b, returns 0110 /// negative/0/positive value if a is less/equal/greater than b. 0111 typedef int (*SequenceNCompareFunct)(const T *a, const T *b, 0112 size_t num); 0113 /// Compares sequence a and b, returns negative/0/positive 0114 /// value if a is less/equal/greater than b. 0115 typedef int (*SequenceCompareFunct)(const T *a, const T *b); 0116 /// Return the sequence's number of elements. 0117 typedef u_int32_t (*SequenceLenFunct)(const T *seqs); 0118 0119 /// Copy the sequence seqs's first num elements to seqd. 0120 /// The sequence seqs of type T objects may not reside in a continuous 0121 /// chunk of memory, but the seqd sequence points to a consecutive 0122 /// chunk of memory large enough to hold all objects from seqs. 0123 /// And if T is a complex type, you should register your ElemCopyFunct 0124 /// object marshalling manipulator 0125 typedef void (*SequenceCopyFunct)(T *seqd, const T *seqs, size_t num); 0126 //@} 0127 0128 typedef T char_type; 0129 typedef long int_type; 0130 0131 /// \name Interface compatible with std::string's char_traits. 0132 /// Following are char_traits funcitons, which make this class 0133 /// char_traits compatiable, so that it can be used in 0134 /// std::basic_string template, and be manipulated by the c++ stl 0135 /// algorithms. 0136 //@{ 0137 /// Assignone object to another. 0138 static void assign(T& left, const T& right) 0139 { 0140 if (inst_->assign_) 0141 inst_->assign_(left, right); 0142 else 0143 left = right; 0144 } 0145 0146 /// Check for equality of two objects. 0147 static bool eq(const T& left, const T& right) 0148 { 0149 if (inst_->elemcmp_) 0150 return inst_->elemcmp_(left, right) == 0; 0151 else 0152 return left == right; 0153 } 0154 0155 /// \brief Less than comparison. 0156 /// 0157 /// Returns if object left is less than object right. 0158 static bool lt(const T& left, const T& right) 0159 { 0160 if (inst_->elemcmp_) 0161 return inst_->elemcmp_(left, right) < 0; 0162 else 0163 return left < right; 0164 } 0165 0166 /// \brief Sequence comparison. 0167 /// 0168 /// Compares the first cnt number of elements in the two 0169 /// sequences seq1 and seq2, returns negative/0/positive if seq1 is 0170 /// less/equal/greater than seq2. 0171 static int compare(const T *seq1, const T *seq2, size_t cnt) 0172 { 0173 if (inst_->seqncmp_) 0174 return inst_->seqncmp_(seq1, seq2, cnt); 0175 else { 0176 for (; 0 < cnt; --cnt, ++seq1, ++seq2) 0177 if (!eq(*seq1, *seq2)) 0178 return (lt(*seq1, *seq2) ? -1 : +1); 0179 } 0180 return (0); 0181 } 0182 0183 /// Returns the number of elements in sequence seq1. Note that seq1 0184 /// may or may not end with a trailing '\0', it is completely user's 0185 /// responsibility for this decision, though seq[0], seq[1],... 0186 /// seq[length - 1] are all sequence seq's memory. 0187 static size_t length(const T *seq) 0188 { 0189 assert(inst_->seqlen_ != NULL); 0190 return (size_t)inst_->seqlen_(seq); 0191 } 0192 0193 /// Copy first cnt number of elements from seq2 to seq1. 0194 static T * copy(T *seq1, const T *seq2, size_t cnt) 0195 { 0196 if (inst_->seqcpy_) 0197 inst_->seqcpy_(seq1, seq2, cnt); 0198 else { 0199 T *pnext = seq1; 0200 for (; 0 < cnt; --cnt, ++pnext, ++seq2) 0201 assign(*pnext, *seq2); 0202 } 0203 return (seq1); 0204 } 0205 0206 /// Find within the first cnt elements of sequence seq the position 0207 /// of element equal to elem. 0208 static const T * find(const T *seq, size_t cnt, const T& elem) 0209 { 0210 for (; 0 < cnt; --cnt, ++seq) 0211 if (eq(*seq, elem)) 0212 return (seq); 0213 return (0); 0214 } 0215 0216 /// \brief Sequence movement. 0217 /// 0218 /// Move first cnt number of elements from seq2 to seq1, seq1 and seq2 0219 /// may or may not overlap. 0220 static T * move(T *seq1, const T *seq2, size_t cnt) 0221 { 0222 T *pnext = seq1; 0223 if (seq2 < pnext && pnext < seq2 + cnt) 0224 for (pnext += cnt, seq2 += cnt; 0 < cnt; --cnt) 0225 assign(*--pnext, *--seq2); 0226 else 0227 for (; 0 < cnt; --cnt, ++pnext, ++seq2) 0228 assign(*pnext, *seq2); 0229 return (seq1); 0230 } 0231 0232 /// Assign first cnt number of elements of sequence seq with the 0233 /// value of elem. 0234 static T * assign(T *seq, size_t cnt, T elem) 0235 { 0236 T *pnext = seq; 0237 for (; 0 < cnt; --cnt, ++pnext) 0238 assign(*pnext, elem); 0239 return (seq); 0240 } 0241 0242 static T to_char_type(const int_type& meta_elem) 0243 { // convert metacharacter to character 0244 return ((T)meta_elem); 0245 } 0246 0247 static int_type to_int_type(const T& elem) 0248 { // convert character to metacharacter 0249 return ((int_type)elem); 0250 } 0251 0252 static bool eq_int_type(const int_type& left, 0253 const int_type& right) 0254 { // test for metacharacter equality 0255 return (left == right); 0256 } 0257 0258 static int_type eof() 0259 { // return end-of-file metacharacter 0260 return ((int_type)EOF); 0261 } 0262 0263 static int_type not_eof(const int_type& meta_elem) 0264 { // return anything but EOF 0265 return (meta_elem != eof() ? (int_type)meta_elem : 0266 (int_type)!eof()); 0267 } 0268 0269 //@} 0270 0271 /// Factory method to create a singeleton instance of this class. 0272 /// The created object will be deleted by dbstl upon process exit. 0273 inline static DbstlElemTraits *instance() 0274 { 0275 if (!inst_) { 0276 inst_ = new DbstlElemTraits(); 0277 register_global_object(inst_); 0278 } 0279 return inst_; 0280 } 0281 0282 /// \name Set/get functions for callback function pointers. 0283 /// These are the setters and getters for each callback function 0284 /// pointers. 0285 //@{ 0286 inline void set_restore_function(ElemRstoreFunct f) 0287 { 0288 restore_ = f; 0289 } 0290 0291 inline ElemRstoreFunct get_restore_function() { return restore_; } 0292 0293 inline void set_assign_function(ElemAssignFunct f) 0294 { 0295 assign_ = f; 0296 } 0297 0298 inline ElemAssignFunct get_assign_function() { return assign_; } 0299 0300 inline ElemSizeFunct get_size_function() { return size_; } 0301 0302 inline void set_size_function(ElemSizeFunct f) { size_ = f; } 0303 0304 inline ElemCopyFunct get_copy_function() { return copy_; } 0305 0306 inline void set_copy_function(ElemCopyFunct f) { copy_ = f; } 0307 0308 inline void set_sequence_len_function(SequenceLenFunct f) 0309 { 0310 seqlen_ = f; 0311 } 0312 0313 inline SequenceLenFunct get_sequence_len_function() { return seqlen_; } 0314 0315 inline SequenceCopyFunct get_sequence_copy_function() 0316 { 0317 return seqcpy_; 0318 } 0319 0320 inline void set_sequence_copy_function(SequenceCopyFunct f) 0321 { 0322 seqcpy_ = f; 0323 } 0324 0325 inline void set_compare_function(ElemCompareFunct f) 0326 { 0327 elemcmp_ = f; 0328 } 0329 0330 inline ElemCompareFunct get_compare_function() 0331 { 0332 return elemcmp_; 0333 } 0334 0335 inline void set_sequence_compare_function(SequenceCompareFunct f) 0336 { 0337 seqcmp_ = f; 0338 } 0339 0340 inline SequenceCompareFunct get_sequence_compare_function() 0341 { 0342 return seqcmp_; 0343 } 0344 0345 inline void set_sequence_n_compare_function(SequenceNCompareFunct f) 0346 { 0347 seqncmp_ = f; 0348 } 0349 0350 inline SequenceNCompareFunct get_sequence_n_compare_function() 0351 { 0352 return seqncmp_; 0353 } 0354 //@} 0355 0356 ~DbstlElemTraits(){} 0357 protected: 0358 inline DbstlElemTraits() 0359 { 0360 assign_ = NULL; 0361 restore_ = NULL; 0362 size_ = NULL; 0363 copy_ = NULL; 0364 seqlen_ = NULL; 0365 seqcpy_ = NULL; 0366 seqcmp_ = NULL; 0367 seqncmp_ = NULL; 0368 elemcmp_ = NULL; 0369 } 0370 0371 static DbstlElemTraits *inst_; 0372 0373 // Data members to hold registered function pointers. 0374 ElemAssignFunct assign_; 0375 ElemRstoreFunct restore_; 0376 ElemSizeFunct size_; 0377 ElemCopyFunct copy_; 0378 ElemCompareFunct elemcmp_; 0379 SequenceCompareFunct seqcmp_; 0380 SequenceNCompareFunct seqncmp_; 0381 SequenceLenFunct seqlen_; 0382 SequenceCopyFunct seqcpy_; 0383 }; //DbstlElemTraits 0384 //@} // dbstl_helper_classes 0385 0386 template<typename T> 0387 DbstlElemTraits<T> *DbstlElemTraits<T>::inst_ = NULL; 0388 0389 /** 0390 \ingroup dbstl_helper_classes 0391 @{ 0392 You can persist all bytes in a chunk of contiguous memory by constructing 0393 an DbstlDbt object A(use malloc to allocate the required number of bytes for 0394 A.data and copy the bytes to be stored into A.data, set other 0395 fields as necessary) and store A into a container, e.g. db_vector<DbstlDbt>, 0396 this stores the bytes rather than the object A into the underlying database. 0397 The DbstlDbt class can help you avoid memory leaks, 0398 so it is strongly recommended that you use DbstlDbt rather than Dbt class. 0399 0400 DbstlDbt derives from Dbt class, and it does an deep copy on copy construction 0401 and assignment --by calling malloc to allocate its own memory and then 0402 copying the bytes to it; Conversely the destructor will free the memory on 0403 destruction if the data pointer is non-NULL. The destructor assumes the 0404 memory is allocated via malloc, hence why you are required to call 0405 malloc to allocate memory in order to use DbstlDbt. 0406 0407 DbstlDbt simply inherits all methods from Dbt with no extra 0408 new methods except the constructors/destructor and assignment operator, so it 0409 is easy to use. 0410 0411 In practice you rarely need to use DbstlDbt 0412 or Dbt because dbstl enables you to store any complex 0413 objects or primitive data. Only when you need to store raw bytes, 0414 e.g. a bitmap, do you need to use DbstlDbt. 0415 0416 Hence, DbstlDbt is the right class to 0417 use to store any object into Berkeley DB via dbstl without memory leaks. 0418 0419 Don't free the memory referenced by DbstlDbt objects, it will be freed when the 0420 DbstlDbt object is destructed. 0421 0422 Please refer to the two examples using DbstlDbt in 0423 TestAssoc::test_arbitrary_object_storage and 0424 TestAssoc::test_char_star_string_storage member functions, 0425 which illustrate how to correctly use DbstlDbt in order to store raw bytes. 0426 0427 This class handles the task of allocating and de-allocating memory internally. 0428 Although it can be used to store data which cannot be handled by the 0429 DbstlElemTraits 0430 class, in practice, it is usually more convenient to register callbacks in the 0431 DbstlElemTraits class for the type you are storing/retrieving using dbstl. 0432 */ 0433 class DbstlDbt : public Dbt 0434 { 0435 inline void deep_copy(const DbstlDbt &d) 0436 { 0437 u_int32_t len; 0438 if (d.get_data() != NULL && d.get_size() > 0) { 0439 if (d.get_flags() & DB_DBT_USERMEM) 0440 len = d.get_ulen(); 0441 else 0442 len = d.get_size(); 0443 0444 set_data(DbstlMalloc(len)); 0445 memcpy(get_data(), d.get_data(), len); 0446 } 0447 } 0448 0449 public: 0450 /// Construct an object with an existing chunk of memory of size1 0451 /// bytes, refered by data1, 0452 DbstlDbt(void *data1, u_int32_t size1) : Dbt(data1, size1){} 0453 DbstlDbt() : Dbt(){} 0454 /// The memory will be free'ed by the destructor. 0455 ~DbstlDbt() 0456 { 0457 free_mem(); 0458 } 0459 0460 /// This copy constructor does a deep copy. 0461 DbstlDbt(const DbstlDbt &d) : Dbt(d) 0462 { 0463 deep_copy(d); 0464 } 0465 0466 /// The memory will be reallocated if neccessary. 0467 inline const DbstlDbt &operator = (const DbstlDbt &d) 0468 { 0469 ASSIGNMENT_PREDCOND(d) 0470 0471 if (d.get_data() != NULL && d.get_size() > 0) { 0472 free_mem(); 0473 memcpy(this, &d, sizeof(d)); 0474 } 0475 0476 deep_copy(d); 0477 return d; 0478 } 0479 0480 protected: 0481 /// Users don't need to call this function. 0482 inline void free_mem() 0483 { 0484 if (get_data()) { 0485 free(get_data()); 0486 memset(this, 0, sizeof(*this)); 0487 } 0488 } 0489 0490 }; 0491 //@} // dbstl_help_classes 0492 END_NS 0493 0494 #endif // ! _DB_STL_UTILITY_H__ 0495 0496
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |