Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2024-05-18 08:29:47

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