2 * See the file LICENSE for redistribution information.
4 * Copyright (c) 2009, 2012 Oracle and/or its affiliates. All rights reserved.
15 #include "dbstl_common.h"
16 #include "dbstl_exception.h"
17 #include "dbstl_utility.h"
19 //////////////////////////////////////////////////////////////////////////
20 //////////////////////////////////////////////////////////////////////////
22 // DataItem class template definition
24 // 1. DataItem is a Dbt wrapper, it provides both typed data to/from memory
25 // chunk mapping as well as iostream support. Note that iostream functionality
26 // is not yet implemented.
27 // 2. DataItem is used inside dbstl to provide consistent Dbt object memory
29 // 3. DataItem is not only capable of mapping fixed size objects, but also
30 // varying length objects and objects not located in a consecutive chunk of
31 // memory, with the condition that user configures the required methods in
33 // 4. DataItem can not be a class template because inside it, the "member
34 // function template override" support is needed.
46 typedef DataItem self;
48 ////////////////////////////////////////////////////////////////////
49 ////////////////////////////////////////////////////////////////////
51 // DataItem memory management
53 // The dbt_ member is the current dbt, data is stored in the dbt's
54 // referenced memory, it may
55 // deep copy from constructor and from other Dbt, depending on
56 // the constructors "onstack" parameter --- if true, this object
57 // is only used as a stack object inside a function,
58 // so do shallow copy; otherwise do deep copy.
59 // There is always a DB_DBT_USERMEM flag set to the dbt,
60 // its ulen data member stores the length of referenced memory,
61 // its size data member stores the actual size of data;
62 // If onstack is true, its dlen is INVALID_DLEN, and freemem()
63 // will not free such memory because this object only reference
64 // other object's memory, its the referenced object's responsibility
65 // to free their memory.
67 // A DataItem object is not used everywhere, so it is impossible for
68 // such an object to have two kinds of usages as above at the same
69 // time, so we are safe doing so.
72 // Free dbt_'s referenced memory if that memory is allocated in heap
76 void *buf = dbt_.get_data();
78 if (buf != NULL && (dbt_.get_flags() & DB_DBT_USERMEM) != 0
79 && dbt_.get_dlen() != INVALID_DLEN)
81 memset(&dbt_, 0, sizeof(dbt_));
86 // Deep copy, because dbt2.data pointed memory may be short lived.
87 inline void set_dbt(const DbstlDbt&dbt2, bool onstack)
101 buf = DbstlReAlloc(buf, s2);
105 pdbt->flags |= DB_DBT_USERMEM;
108 memcpy(buf, pdbt2->data, s2);
111 dbt_ = (const Dbt)dbt2;
112 pdbt->dlen = (INVALID_DLEN);
116 // Deep copy, because dbt2.data pointed memory may be short lived.
117 inline void set_dbt(const Dbt&dbt2, bool onstack)
123 pdbt2 = (DBT *)&dbt2;
131 buf = DbstlReAlloc(buf, s2);
135 pdbt->flags |= DB_DBT_USERMEM;
138 memcpy(buf, pdbt2->data, s2);
142 pdbt->dlen = (INVALID_DLEN);
146 inline void set_dbt(const DBT&dbt2, bool onstack)
150 DBT *pdbt = (DBT *)&dbt_;
157 buf = DbstlReAlloc(buf, s2);
161 pdbt->flags |= DB_DBT_USERMEM;
164 memcpy(buf, dbt2.data, s2);
167 // The following is right because Dbt derives from
168 // DBT with no extra members or any virtual functions.
169 memcpy(&dbt_, &dbt2, sizeof(dbt2));
170 pdbt->dlen = INVALID_DLEN;
174 // Return to the initial state.
177 void *buf = dbt_.get_data();
179 memset(buf, 0, dbt_.get_ulen());
184 inline Dbt& get_dbt()
189 // Return data of this object. If no data return -1, if it has data
192 // !!!XXX Note that the type parameter T can only be in this function
193 // because "template type parameter overload" applies only to a
194 // functions template argument list, rather than that of classes.
195 // If you put the "template<Typename T>" to this class's declaration,
196 // making it a class template, then when T is any of Dbt, DBT, or
197 // DataItem<T>, there will be two copies of this function. One will be
198 // this function's instantiated version, the other one is one of the
199 // three functions defined below.
201 template <Typename T>
202 inline int get_data(T& data) const
205 typedef DbstlElemTraits<T> EM;
206 typename EM::ElemRstoreFunct restore;
209 if ((pdata = dbt_.get_data()) != NULL) {
210 if ((restore = EM::instance()->
211 get_restore_function()) != NULL)
212 restore(data, pdata);
221 ////////////////////////////////////////////////////////////////////
223 // Begin functions supporting direct naked string storage.
225 // Always store the data, rather than the container object.
227 // The returned string lives no longer than the next iterator
230 inline int get_data(char*& data) const
232 data = (char*)dbt_.get_data();
236 inline int get_data(string &data) const
238 data = (string::pointer) dbt_.get_data();
242 inline int get_data(wchar_t*& data) const
244 data = (wchar_t*)dbt_.get_data();
249 inline int get_data(wstring &data) const
251 data = (wstring::pointer) dbt_.get_data();
256 ////////////////////////////////////////////////////////////////////
258 // Supporting storing arbitrary type of sequence.
259 template <Typename T>
260 inline int get_data(T*& data) const
262 data = (T*)dbt_.get_data();
266 inline int get_data(DataItem& data) const
270 if (dbt_.get_data()) {
271 data.set_dbt(dbt_, false);
278 ////////////////////////////////////////////////////////////////////
280 // Begin functions supporting Dbt storage.
282 // This member function allows storing a Dbt type, so that user can
283 // store the varying length data into Dbt.
285 // This method is required to copy a data element's bytes to another
286 // Dbt object, used inside by dbstl.
287 // If there is no data return -1, if it has data return 0.
289 inline int get_data(Dbt& data) const
294 DBT *pdbt = (DBT *)&dbt_, *pdata = (DBT *)&data;
299 if (pdata->ulen < sz) {
300 pdata->data = DbstlReAlloc(addr, sz);
303 pdata->flags |= DB_DBT_USERMEM;
306 memcpy(pdata->data, pdbt->data, sz);
313 inline int get_data(DBT& data) const
319 if (dbt_.get_data()) {
321 if (data.ulen < (sz = dbt_.get_size())) {
322 data.data = DbstlReAlloc(addr, sz);
323 // User need to free this memory
324 data.flags = data.flags | DB_DBT_USERMEM;
329 memcpy(data.data, dbt_.get_data(), sz);
336 inline int get_data(DbstlDbt& data) const
341 DBT *pdbt = (DBT *)&dbt_, *pdata = (DBT *)&data;
346 if (pdata->ulen < sz) {
347 pdata->data = DbstlReAlloc(addr, sz);
350 pdata->flags |= DB_DBT_USERMEM;
353 memcpy(pdata->data, pdbt->data, sz);
360 ////////////////////////////////////////////////////////////////////
362 // Deep copy in assignment and copy constructor.
363 inline const DbstlDbt& operator=(const DbstlDbt& t2)
369 // Deep copy in assignment and copy constructor.
370 inline const Dbt& operator=(const Dbt& t2)
376 // Deep copy in assignment and copy constructor.
377 inline const DBT& operator=(const DBT& t2)
383 // Deep copy in assignment and copy constructor.
384 template <Typename T>
385 inline const T& operator = (const T&dt)
392 // Generic way of storing an object or variable. Note that DataItem
393 // is not a class template but a class with function templates.
394 // Variable t locates on a consecutive chunk of memory, and objects
395 // of T have the same size.
397 template <Typename T>
398 void make_dbt(const T& dt, bool onstack)
400 typedef DbstlElemTraits<T> EM;
402 typename EM::ElemSizeFunct sizef;
403 typename EM::ElemCopyFunct copyf;
404 DBT *pdbt = (DBT *)&dbt_;
406 if ((sizef = EM::instance()->get_size_function()) != NULL)
411 copyf = EM::instance()->get_copy_function();
413 if (onstack && copyf == NULL) {
415 pdbt->data = ((void*)&dt);
416 // We have to set DB_DBT_USERMEM for DB_THREAD to work.
417 pdbt->flags = (DB_DBT_USERMEM);
420 // This is a flag that this memory can't be freed
421 // because it is on stack.
422 pdbt->dlen = (INVALID_DLEN);
426 // Not on stack, allocate enough space and "copy" the object
427 // using shall copy or customized copy.
428 if (pdbt->ulen < sz) {
429 pdbt->data = (DbstlReAlloc(pdbt->data, sz));
430 assert(pdbt->data != NULL);
433 pdbt->flags = (DB_DBT_USERMEM);
438 copyf(pdbt->data, dt);
440 memcpy(pdbt->data, &dt, sz);
443 inline const char*&operator = (const char*&dt)
449 inline const wchar_t*&operator = (const wchar_t*&dt)
455 inline const string &operator=(const string &dt)
462 inline const wstring &operator=(const wstring &dt)
469 template <Typename T>
470 inline const T*&operator = (const T*&dt)
476 inline const self& operator=(const self&dbt1)
478 ASSIGNMENT_PREDCOND(dbt1)
479 this->set_dbt(dbt1.dbt_, false);
484 inline DataItem(const self&dbt1)
486 set_dbt(dbt1.dbt_, false);
490 inline DataItem(u_int32_t sz)
493 DBT *pdbt = (DBT *)&dbt_;
496 buf = DbstlMalloc(sz);
501 pdbt->flags = DB_DBT_USERMEM;
504 // Deep copy. The onstack parameter means whether the object referenced
505 // by this DataItem is on used with a function call where this DataItem
506 // object is used. If so, we don't deep copy the object, simply refer
507 // to its memory location. The meaining is the same for this parameter
508 // in constructors that follow.
509 inline DataItem(const Dbt&dbt2, bool onstack)
511 set_dbt(dbt2, onstack);
514 inline DataItem(const DbstlDbt&dbt2, bool onstack)
516 set_dbt(dbt2, onstack);
519 inline DataItem(const DBT&dbt2, bool onstack)
521 set_dbt(dbt2, onstack);
524 // Deep copy. There is a partial specialization for char*/wchar_t*/
527 inline DataItem(const T& dt, bool onstack)
529 make_dbt(dt, onstack);
532 inline ~DataItem(void)
539 // Store a char*/wchar_t* string. Need four versions for char*
540 // and wchar_t* respectively to catch all
541 // possibilities otherwise the most generic one will be called.
542 // Note that the two const decorator matters when doing type
544 inline void make_dbt_chars(const char *t, bool onstack)
546 DBT *d = (DBT *)&dbt_;
550 (u_int32_t)((strlen(t) + 1) * sizeof(char)));
553 d->flags |= DB_DBT_USERMEM;
554 d->data = DbstlReAlloc(d->data, sz);
559 strcpy((char*)d->data, t);
561 memset(d->data, '\0', sizeof(char));
564 d->data = ((t == NULL) ? (void *)"" : (void *)t);
567 d->flags = (DB_DBT_USERMEM);
568 d->dlen = (INVALID_DLEN);
572 inline void make_dbt_wchars(const wchar_t *t, bool onstack)
574 DBT *d = (DBT *)&dbt_;
578 (u_int32_t)((wcslen(t) + 1) * sizeof(wchar_t)));
581 d->flags |= DB_DBT_USERMEM;
582 d->data = DbstlReAlloc(d->data, sz);
587 wcscpy((wchar_t*)d->data, t);
589 memset(d->data, L'\0', sizeof(wchar_t));
592 d->data = ((t == NULL) ? (void *)L"" : (void *)t);
595 d->flags = (DB_DBT_USERMEM);
596 d->dlen = (INVALID_DLEN);
600 inline void make_dbt(const char*& t, bool onstack)
602 make_dbt_chars(t, onstack);
605 inline void make_dbt(const char* const& t, bool onstack)
607 make_dbt_chars(t, onstack);
610 inline void make_dbt(char*& t, bool onstack)
612 make_dbt_chars(t, onstack);
615 inline void make_dbt(char* const& t, bool onstack)
617 make_dbt_chars(t, onstack);
620 inline void make_dbt(const string& t, bool onstack)
622 make_dbt_chars(t.c_str(), onstack);
625 inline void make_dbt(const wchar_t*& t, bool onstack)
627 make_dbt_wchars(t, onstack);
630 inline void make_dbt(const wchar_t* const& t, bool onstack)
632 make_dbt_wchars(t, onstack);
635 inline void make_dbt(wchar_t*& t, bool onstack)
637 make_dbt_wchars(t, onstack);
640 inline void make_dbt(wchar_t* const& t, bool onstack)
642 make_dbt_wchars(t, onstack);
646 inline void make_dbt(const wstring& t, bool onstack)
648 make_dbt_wchars(t.c_str(), onstack);
652 template <Typename T>
653 void make_dbt_internal(const T*t, bool onstack)
655 typedef DbstlElemTraits<T> EM;
656 u_int32_t i, sz, totalsz, sql;
657 DBT *pdbt = (DBT *)&dbt_;
658 typename EM::ElemSizeFunct szf = NULL;
659 typename EM::SequenceLenFunct seqlenf = NULL;
660 typename EM::SequenceCopyFunct seqcopyf = NULL;
662 szf = EM::instance()->get_size_function();
663 seqlenf = EM::instance()->get_sequence_len_function();
664 seqcopyf = EM::instance()->get_sequence_copy_function();
666 assert(seqlenf != NULL);
667 sql = sz = (u_int32_t)seqlenf(t);
669 for (i = 0, totalsz = 0; i < sz; i++)
670 totalsz += szf(t[i]);
672 totalsz = sz * sizeof(T);
676 if (onstack && seqcopyf == NULL) {
678 pdbt->data = (void *)t;
681 pdbt->flags = DB_DBT_USERMEM;
682 pdbt->dlen = INVALID_DLEN; // onstack flag;
684 // ulen stores the real length of the pointed memory.
685 if (pdbt->ulen < sz) {
686 pdbt->data = DbstlReAlloc(pdbt->data, sz);
688 pdbt->flags |= DB_DBT_USERMEM;
692 EM::instance()->copy((T *)pdbt->data, t, sql);
696 // Store a sequence of base type T. Need four versions to catch all
697 // possibilities otherwise the most generic one will be called.
698 template <Typename T>
699 inline void make_dbt(const T*const&tt, bool onstack)
701 make_dbt_internal((const T*)tt, onstack);
703 template <Typename T>
704 inline void make_dbt(T*const&tt, bool onstack)
706 make_dbt_internal((const T*)tt, onstack);
708 template <Typename T>
709 inline void make_dbt(T*&tt, bool onstack)
711 make_dbt_internal((const T*)tt, onstack);
713 template <Typename T>
714 inline void make_dbt(const T*&tt, bool onstack)
716 make_dbt_internal((const T*)tt, onstack);
721 inline DataItem(const char*& t, bool onstack)
723 make_dbt_chars(t, onstack);
726 inline DataItem(const char* const& t, bool onstack)
728 make_dbt_chars(t, onstack);
731 inline DataItem(char*& t, bool onstack)
733 make_dbt_chars(t, onstack);
736 inline DataItem(char* const& t, bool onstack)
738 make_dbt_chars(t, onstack);
741 inline DataItem(const string& t, bool onstack)
743 make_dbt_chars(t.c_str(), onstack);
746 inline DataItem(const wchar_t*& t, bool onstack)
748 make_dbt_wchars(t, onstack);
751 inline DataItem(const wchar_t* const& t, bool onstack)
753 make_dbt_wchars(t, onstack);
756 inline DataItem(wchar_t*& t, bool onstack)
758 make_dbt_wchars(t, onstack);
761 inline DataItem(wchar_t* const& t, bool onstack)
763 make_dbt_wchars(t, onstack);
767 inline DataItem(const wstring& t, bool onstack)
769 make_dbt_wchars(t.c_str(), onstack);
773 inline DataItem(T*&tt, bool onstack)
775 make_dbt_internal((const T*)tt, onstack);
779 inline DataItem(const T*&tt, bool onstack)
781 make_dbt_internal((const T*)tt, onstack);
785 inline DataItem(T*const&tt, bool onstack)
787 make_dbt_internal((const T*)tt, onstack);
791 inline DataItem(const T*const&tt, bool onstack)
793 make_dbt_internal((const T*)tt, onstack);
799 bool operator==(const Dbt&d1, const Dbt&d2);
800 bool operator==(const DBT&d1, const DBT&d2);
803 #endif // !_DB_STL_DBT_H