1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2009 Oracle. All rights reserved. 5 * 6 * $Id$ 7 */ 8 9#ifndef _DB_STL_DBT_H 10#define _DB_STL_DBT_H 11 12#include <assert.h> 13#include <string> 14 15#include "dbstl_common.h" 16#include "dbstl_exception.h" 17#include "dbstl_utility.h" 18 19////////////////////////////////////////////////////////////////////////// 20////////////////////////////////////////////////////////////////////////// 21// 22// DataItem class template definition 23// 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 28// management. 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 32// DbstlElemTraits. 33// 4. DataItem can not be a class template because inside it, the "member 34// function template override" support is needed. 35// 36START_NS(dbstl) 37 38using std::string; 39#ifdef HAVE_WSTRING 40using std::wstring; 41#endif 42 43class DataItem 44{ 45private: 46 typedef DataItem self; 47 48 //////////////////////////////////////////////////////////////////// 49 //////////////////////////////////////////////////////////////////// 50 // 51 // DataItem memory management 52 // 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. 66 // 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. 70 Dbt dbt_; 71 72 // Free dbt_'s referenced memory if that memory is allocated in heap 73 // and owned by dbt_. 74 inline void freemem() 75 { 76 void *buf = dbt_.get_data(); 77 78 if (buf != NULL && (dbt_.get_flags() & DB_DBT_USERMEM) != 0 79 && dbt_.get_dlen() != INVALID_DLEN) 80 free(buf); 81 memset(&dbt_, 0, sizeof(dbt_)); 82 } 83 84public: 85 86 // Deep copy, because dbt2.data pointed memory may be short lived. 87 inline void set_dbt(const DbstlDbt&dbt2, bool onstack) 88 { 89 void *buf; 90 u_int32_t s1, s2; 91 DBT *pdbt2, *pdbt; 92 93 pdbt2 = (DBT *)&dbt2; 94 pdbt = (DBT *)&dbt_; 95 96 if (!onstack) { 97 buf = pdbt->data; 98 s1 = pdbt->ulen; 99 s2 = pdbt2->size; 100 if(s2 > s1) { 101 buf = DbstlReAlloc(buf, s2); 102 pdbt->size = s2; 103 pdbt->data = buf; 104 pdbt->ulen = s2; 105 pdbt->flags |= DB_DBT_USERMEM; 106 } else 107 pdbt->size = s2; 108 memcpy(buf, pdbt2->data, s2); 109 } else { 110 freemem(); 111 dbt_ = (const Dbt)dbt2; 112 pdbt->dlen = (INVALID_DLEN); 113 } 114 } 115 116 // Deep copy, because dbt2.data pointed memory may be short lived. 117 inline void set_dbt(const Dbt&dbt2, bool onstack) 118 { 119 void *buf; 120 u_int32_t s1, s2; 121 DBT *pdbt2, *pdbt; 122 123 pdbt2 = (DBT *)&dbt2; 124 pdbt = (DBT *)&dbt_; 125 126 if (!onstack) { 127 buf = pdbt->data; 128 s1 = pdbt->ulen; 129 s2 = pdbt2->size; 130 if(s2 > s1) { 131 buf = DbstlReAlloc(buf, s2); 132 pdbt->size = s2; 133 pdbt->data = buf; 134 pdbt->ulen = s2; 135 pdbt->flags |= DB_DBT_USERMEM; 136 } else 137 pdbt->size = s2; 138 memcpy(buf, pdbt2->data, s2); 139 } else { 140 freemem(); 141 dbt_ = dbt2; 142 pdbt->dlen = (INVALID_DLEN); 143 } 144 } 145 146 inline void set_dbt(const DBT&dbt2, bool onstack) 147 { 148 void *buf; 149 u_int32_t s1, s2; 150 DBT *pdbt = (DBT *)&dbt_; 151 152 if (!onstack) { 153 buf = pdbt->data; 154 s1 = pdbt->ulen; 155 s2 = dbt2.size; 156 if(s2 > s1) { 157 buf = DbstlReAlloc(buf, s2); 158 pdbt->size = s2; 159 pdbt->data = buf; 160 pdbt->ulen = s2; 161 pdbt->flags |= DB_DBT_USERMEM; 162 } else 163 pdbt->size = s2; 164 memcpy(buf, dbt2.data, s2); 165 } else { 166 freemem(); 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; 171 } 172 } 173 174 // Return to the initial state. 175 inline void reset() 176 { 177 void *buf = dbt_.get_data(); 178 if (buf) { 179 memset(buf, 0, dbt_.get_ulen()); 180 dbt_.set_size(0); 181 } 182 } 183 184 inline Dbt& get_dbt() 185 { 186 return dbt_; 187 } 188 189 // Return data of this object. If no data return -1, if it has data 190 // return 0. 191 // 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. 200 // 201 template <Typename T> 202 inline int get_data(T& data) const 203 { 204 int ret; 205 typedef DbstlElemTraits<T> EM; 206 typename EM::ElemRstoreFunct restore; 207 void *pdata = NULL; 208 209 if ((pdata = dbt_.get_data()) != NULL) { 210 if ((restore = EM::instance()-> 211 get_restore_function()) != NULL) 212 restore(data, pdata); 213 else 214 data = *((T*)pdata); 215 ret = 0; 216 } else 217 ret = -1; 218 return ret; 219 } 220 221 //////////////////////////////////////////////////////////////////// 222 // 223 // Begin functions supporting direct naked string storage. 224 // 225 // Always store the data, rather than the container object. 226 // 227 // The returned string lives no longer than the next iterator 228 // movement call. 229 // 230 inline int get_data(char*& data) const 231 { 232 data = (char*)dbt_.get_data(); 233 return 0; 234 } 235 236 inline int get_data(string &data) const 237 { 238 data = (string::pointer) dbt_.get_data(); 239 return 0; 240 } 241 242 inline int get_data(wchar_t*& data) const 243 { 244 data = (wchar_t*)dbt_.get_data(); 245 return 0; 246 } 247 248#ifdef HAVE_WSTRING 249 inline int get_data(wstring &data) const 250 { 251 data = (wstring::pointer) dbt_.get_data(); 252 return 0; 253 } 254#endif 255 256 //////////////////////////////////////////////////////////////////// 257 258 // Supporting storing arbitrary type of sequence. 259 template <Typename T> 260 inline int get_data(T*& data) const 261 { 262 data = (T*)dbt_.get_data(); 263 return 0; 264 } 265 266 inline int get_data(DataItem& data) const 267 { 268 int ret; 269 270 if (dbt_.get_data()) { 271 data.set_dbt(dbt_, false); 272 ret = 0; 273 } else 274 ret = -1; 275 return ret; 276 } 277 278 //////////////////////////////////////////////////////////////////// 279 // 280 // Begin functions supporting Dbt storage. 281 // 282 // This member function allows storing a Dbt type, so that user can 283 // store the varying length data into Dbt. 284 // 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. 288 // 289 inline int get_data(Dbt& data) const 290 { 291 int ret; 292 void *addr; 293 u_int32_t sz; 294 DBT *pdbt = (DBT *)&dbt_, *pdata = (DBT *)&data; 295 296 if (pdbt->data) { 297 addr = pdata->data; 298 sz = pdbt->size; 299 if (pdata->ulen < sz) { 300 pdata->data = DbstlReAlloc(addr, sz); 301 pdata->size = sz; 302 pdata->ulen = sz; 303 pdata->flags |= DB_DBT_USERMEM; 304 } else 305 pdata->size = sz; 306 memcpy(pdata->data, pdbt->data, sz); 307 ret = 0; 308 } else 309 ret = -1; 310 return ret; 311 } 312 313 inline int get_data(DBT& data) const 314 { 315 int ret; 316 void*addr; 317 u_int32_t sz; 318 319 if (dbt_.get_data()) { 320 addr = data.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; 325 data.size = sz; 326 data.ulen = sz; 327 } else 328 data.size = sz; 329 memcpy(data.data, dbt_.get_data(), sz); 330 ret = 0; 331 } else 332 ret = -1; 333 return ret; 334 } 335 336 inline int get_data(DbstlDbt& data) const 337 { 338 int ret; 339 void *addr; 340 u_int32_t sz; 341 DBT *pdbt = (DBT *)&dbt_, *pdata = (DBT *)&data; 342 343 if (pdbt->data) { 344 addr = pdata->data; 345 sz = pdbt->size; 346 if (pdata->ulen < sz) { 347 pdata->data = DbstlReAlloc(addr, sz); 348 pdata->size = sz; 349 pdata->ulen = sz; 350 pdata->flags |= DB_DBT_USERMEM; 351 } else 352 pdata->size = sz; 353 memcpy(pdata->data, pdbt->data, sz); 354 ret = 0; 355 } else 356 ret = -1; 357 return ret; 358 } 359 360 //////////////////////////////////////////////////////////////////// 361 362 // Deep copy in assignment and copy constructor. 363 inline const DbstlDbt& operator=(const DbstlDbt& t2) 364 { 365 set_dbt(t2, false); 366 return t2; 367 } 368 369 // Deep copy in assignment and copy constructor. 370 inline const Dbt& operator=(const Dbt& t2) 371 { 372 set_dbt(t2, false); 373 return t2; 374 } 375 376 // Deep copy in assignment and copy constructor. 377 inline const DBT& operator=(const DBT& t2) 378 { 379 set_dbt(t2, false); 380 return t2; 381 } 382 383 // Deep copy in assignment and copy constructor. 384 template <Typename T> 385 inline const T& operator = (const T&dt) 386 { 387 388 make_dbt(dt, false); 389 return dt; 390 } 391 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. 396 // 397 template <Typename T> 398 void make_dbt(const T& dt, bool onstack) 399 { 400 typedef DbstlElemTraits<T> EM; 401 u_int32_t sz; 402 typename EM::ElemSizeFunct sizef; 403 typename EM::ElemCopyFunct copyf; 404 DBT *pdbt = (DBT *)&dbt_; 405 406 if ((sizef = EM::instance()->get_size_function()) != NULL) 407 sz = sizef(dt); 408 else 409 sz = sizeof(dt); 410 411 if (onstack) { 412 freemem(); 413 pdbt->data = ((void*)&dt); 414 // We have to set DB_DBT_USERMEM for DB_THREAD to work. 415 pdbt->flags = (DB_DBT_USERMEM); 416 pdbt->size = (sz); 417 pdbt->ulen = (sz); 418 // This is a flag that this memory can't be freed 419 // because it is on stack. 420 pdbt->dlen = (INVALID_DLEN); 421 return; 422 } 423 424 // Not on stack, allocate enough space and "copy" the object 425 // using shall copy or customized copy. 426 if (pdbt->ulen < sz) { 427 pdbt->data = (DbstlReAlloc(pdbt->data, sz)); 428 assert(pdbt->data != NULL); 429 pdbt->size = (sz); 430 pdbt->ulen = (sz); 431 pdbt->flags = (DB_DBT_USERMEM); 432 } else 433 pdbt->size = (sz); 434 435 if ((copyf = EM::instance()->get_copy_function()) != NULL) 436 copyf(pdbt->data, dt); 437 else 438 memcpy(pdbt->data, &dt, sz); 439 } 440 441 inline const char*&operator = (const char*&dt) 442 { 443 make_dbt(dt, false); 444 return dt; 445 } 446 447 inline const wchar_t*&operator = (const wchar_t*&dt) 448 { 449 make_dbt(dt, false); 450 return dt; 451 } 452 453 inline const string &operator=(const string &dt) 454 { 455 make_dbt(dt, false); 456 return dt; 457 } 458 459#ifdef HAVE_WSTRING 460 inline const wstring &operator=(const wstring &dt) 461 { 462 make_dbt(dt, false); 463 return dt; 464 } 465#endif 466 467 template <Typename T> 468 inline const T*&operator = (const T*&dt) 469 { 470 make_dbt(dt, false); 471 return dt; 472 } 473 474 inline const self& operator=(const self&dbt1) 475 { 476 ASSIGNMENT_PREDCOND(dbt1) 477 this->set_dbt(dbt1.dbt_, false); 478 return dbt1; 479 } 480 481 // Deep copy. 482 inline DataItem(const self&dbt1) 483 { 484 set_dbt(dbt1.dbt_, false); 485 } 486 487 488 inline DataItem(u_int32_t sz) 489 { 490 void *buf; 491 DBT *pdbt = (DBT *)&dbt_; 492 493 buf = NULL; 494 buf = DbstlMalloc(sz); 495 memset(buf, 0, sz); 496 pdbt->size = sz; 497 pdbt->ulen = sz; 498 pdbt->data = buf; 499 pdbt->flags = DB_DBT_USERMEM; 500 } 501 502 // Deep copy. The onstack parameter means whether the object referenced 503 // by this DataItem is on used with a function call where this DataItem 504 // object is used. If so, we don't deep copy the object, simply refer 505 // to its memory location. The meaining is the same for this parameter 506 // in constructors that follow. 507 inline DataItem(const Dbt&dbt2, bool onstack) 508 { 509 set_dbt(dbt2, onstack); 510 } 511 512 inline DataItem(const DbstlDbt&dbt2, bool onstack) 513 { 514 set_dbt(dbt2, onstack); 515 } 516 517 inline DataItem(const DBT&dbt2, bool onstack) 518 { 519 set_dbt(dbt2, onstack); 520 } 521 522 // Deep copy. There is a partial specialization for char*/wchar_t*/ 523 // string/wstring. 524 template<Typename T> 525 inline DataItem(const T& dt, bool onstack) 526 { 527 make_dbt(dt, onstack); 528 } 529 530 inline ~DataItem(void) 531 { 532 freemem(); 533 } 534 535protected: 536 537 // Store a char*/wchar_t* string. Need four versions for char* 538 // and wchar_t* respectively to catch all 539 // possibilities otherwise the most generic one will be called. 540 // Note that the two const decorator matters when doing type 541 // matching. 542 inline void make_dbt_chars(const char *t, bool onstack) 543 { 544 DBT *d = (DBT *)&dbt_; 545 u_int32_t sz; 546 sz = ((t == NULL) ? 547 sizeof(char) : 548 (u_int32_t)((strlen(t) + 1) * sizeof(char))); 549 if (!onstack) { 550 if (d->ulen < sz) { 551 d->flags |= DB_DBT_USERMEM; 552 d->data = DbstlReAlloc(d->data, sz); 553 d->ulen = sz; 554 } 555 d->size = sz; 556 if (t != NULL) 557 strcpy((char*)d->data, t); 558 else 559 memset(d->data, '\0', sizeof(char)); 560 } else { 561 freemem(); 562 d->data = ((t == NULL) ? (void *)"" : (void *)t); 563 d->size = sz; 564 d->ulen = sz; 565 d->flags = (DB_DBT_USERMEM); 566 d->dlen = (INVALID_DLEN); 567 } 568 } 569 570 inline void make_dbt_wchars(const wchar_t *t, bool onstack) 571 { 572 DBT *d = (DBT *)&dbt_; 573 u_int32_t sz; 574 sz = ((t == NULL) ? 575 sizeof(wchar_t) : 576 (u_int32_t)((wcslen(t) + 1) * sizeof(wchar_t))); 577 if (!onstack) { 578 if (d->ulen < sz) { 579 d->flags |= DB_DBT_USERMEM; 580 d->data = DbstlReAlloc(d->data, sz); 581 d->ulen = sz; 582 } 583 d->size = sz; 584 if (t != NULL) 585 wcscpy((wchar_t*)d->data, t); 586 else 587 memset(d->data, L'\0', sizeof(wchar_t)); 588 } else { 589 freemem(); 590 d->data = ((t == NULL) ? (void *)L"" : (void *)t); 591 d->size = sz; 592 d->ulen = sz; 593 d->flags = (DB_DBT_USERMEM); 594 d->dlen = (INVALID_DLEN); 595 } 596 } 597 598 inline void make_dbt(const char*& t, bool onstack) 599 { 600 make_dbt_chars(t, onstack); 601 } 602 603 inline void make_dbt(const char* const& t, bool onstack) 604 { 605 make_dbt_chars(t, onstack); 606 } 607 608 inline void make_dbt(char*& t, bool onstack) 609 { 610 make_dbt_chars(t, onstack); 611 } 612 613 inline void make_dbt(char* const& t, bool onstack) 614 { 615 make_dbt_chars(t, onstack); 616 } 617 618 inline void make_dbt(const string& t, bool onstack) 619 { 620 make_dbt_chars(t.c_str(), onstack); 621 } 622 623 inline void make_dbt(const wchar_t*& t, bool onstack) 624 { 625 make_dbt_wchars(t, onstack); 626 } 627 628 inline void make_dbt(const wchar_t* const& t, bool onstack) 629 { 630 make_dbt_wchars(t, onstack); 631 } 632 633 inline void make_dbt(wchar_t*& t, bool onstack) 634 { 635 make_dbt_wchars(t, onstack); 636 } 637 638 inline void make_dbt(wchar_t* const& t, bool onstack) 639 { 640 make_dbt_wchars(t, onstack); 641 } 642 643#ifdef HAVE_WSTRING 644 inline void make_dbt(const wstring& t, bool onstack) 645 { 646 make_dbt_wchars(t.c_str(), onstack); 647 } 648#endif 649 650 template <Typename T> 651 void make_dbt_internal(const T*t, bool onstack) 652 { 653 u_int32_t i, sz, totalsz, sql; 654 DBT *pdbt = (DBT *)&dbt_; 655 typename DbstlElemTraits<T>::ElemSizeFunct szf = NULL; 656 typename DbstlElemTraits<T>::SequenceLenFunct 657 seqlenf = NULL; 658 659 szf = DbstlElemTraits<T>::instance()-> 660 get_size_function(); 661 seqlenf = DbstlElemTraits<T>::instance()-> 662 get_sequence_len_function(); 663 664 assert(seqlenf != NULL); 665 sql = sz = (u_int32_t)seqlenf(t); 666 if (szf) 667 for (i = 0, totalsz = 0; i < sz; i++) 668 totalsz += szf(t[i]); 669 else 670 totalsz = sz * sizeof(T); 671 672 sz = totalsz; 673 674 if (onstack) { 675 freemem(); 676 pdbt->data = (void *)t; 677 pdbt->size = sz; 678 pdbt->ulen = sz; 679 pdbt->flags = DB_DBT_USERMEM; 680 pdbt->dlen = INVALID_DLEN; // onstack flag; 681 } else { 682 // ulen stores the real length of the pointed memory. 683 if (pdbt->ulen < sz) { 684 pdbt->data = DbstlReAlloc(pdbt->data, sz); 685 pdbt->ulen = sz; 686 pdbt->flags |= DB_DBT_USERMEM; 687 } 688 pdbt->size = sz; 689 690 DbstlElemTraits<T>::instance()-> 691 get_sequence_copy_function() 692 ((T *)pdbt->data, t, sql); 693 } 694 } 695 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) 700 { 701 make_dbt_internal((const T*)tt, onstack); 702 } 703 template <Typename T> 704 inline void make_dbt(T*const&tt, bool onstack) 705 { 706 make_dbt_internal((const T*)tt, onstack); 707 } 708 template <Typename T> 709 inline void make_dbt(T*&tt, bool onstack) 710 { 711 make_dbt_internal((const T*)tt, onstack); 712 } 713 template <Typename T> 714 inline void make_dbt(const T*&tt, bool onstack) 715 { 716 make_dbt_internal((const T*)tt, onstack); 717 } 718 719 720public: 721 inline DataItem(const char*& t, bool onstack) 722 { 723 make_dbt_chars(t, onstack); 724 } 725 726 inline DataItem(const char* const& t, bool onstack) 727 { 728 make_dbt_chars(t, onstack); 729 } 730 731 inline DataItem(char*& t, bool onstack) 732 { 733 make_dbt_chars(t, onstack); 734 } 735 736 inline DataItem(char* const& t, bool onstack) 737 { 738 make_dbt_chars(t, onstack); 739 } 740 741 inline DataItem(const string& t, bool onstack) 742 { 743 make_dbt_chars(t.c_str(), onstack); 744 } 745 746 inline DataItem(const wchar_t*& t, bool onstack) 747 { 748 make_dbt_wchars(t, onstack); 749 } 750 751 inline DataItem(const wchar_t* const& t, bool onstack) 752 { 753 make_dbt_wchars(t, onstack); 754 } 755 756 inline DataItem(wchar_t*& t, bool onstack) 757 { 758 make_dbt_wchars(t, onstack); 759 } 760 761 inline DataItem(wchar_t* const& t, bool onstack) 762 { 763 make_dbt_wchars(t, onstack); 764 } 765 766#ifdef HAVE_WSTRING 767 inline DataItem(const wstring& t, bool onstack) 768 { 769 make_dbt_wchars(t.c_str(), onstack); 770 } 771#endif 772 template<Typename T> 773 inline DataItem(T*&tt, bool onstack) 774 { 775 make_dbt_internal((const T*)tt, onstack); 776 } 777 778 template<Typename T> 779 inline DataItem(const T*&tt, bool onstack) 780 { 781 make_dbt_internal((const T*)tt, onstack); 782 } 783 784 template<Typename T> 785 inline DataItem(T*const&tt, bool onstack) 786 { 787 make_dbt_internal((const T*)tt, onstack); 788 } 789 790 template<Typename T> 791 inline DataItem(const T*const&tt, bool onstack) 792 { 793 make_dbt_internal((const T*)tt, onstack); 794 } 795 796 797}; // DataItem<> 798 799bool operator==(const Dbt&d1, const Dbt&d2); 800bool operator==(const DBT&d1, const DBT&d2); 801END_NS 802 803#endif // !_DB_STL_DBT_H 804