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