1// table.cpp --
2// $Id: table.cpp 1230 2007-03-09 15:58:53Z jcw $
3// This is part of Metakit, the homepage is http://www.equi4.com/metakit.html
4
5/** @file
6 * Loose ends, these should be moved
7 */
8
9#include "header.h"
10#include "handler.h"
11#include "store.h"
12#include "field.h"
13#include "format.h"
14#include "persist.h"
15
16/////////////////////////////////////////////////////////////////////////////
17// Implemented in this file
18
19class c4_Bytes;
20class c4_HandlerSeq;
21
22/////////////////////////////////////////////////////////////////////////////
23
24/** @class c4_Bytes
25 *
26 *  Generic data buffer, with optional automatic clean up.
27 *
28 *  These objects are used to pass around untyped data without concern about
29 *  clean-up.  They know whether the bytes need to be de-allocated when these
30 *  objects go out of scope.  Small amounts of data are stored in the object.
31 *
32 *  Objects of this class are used a lot within Metakit to manipulate its own
33 *  data items generically.  The c4_BytesProp class allows storing binary
34 *  data explicitly in a file.  If such data files must be portable, then the
35 *  application itself must define a generic format to deal with byte order.
36 *
37 *  How to store an object in binary form in a row (this is not portable):
38 * @code
39 *    struct MyStruct { ... };
40 *    MyStruct something;
41 *
42 *    c4_BytesProp pData ("Data");
43 *    c4_Row row;
44 *
45 *    pData (row) = c4_Bytes (&something, sizeof something);
46 * @endcode
47 */
48
49/// Construct an object with contents, optionally as a copy
50c4_Bytes::c4_Bytes(const void *buf_, int len_, bool copy_): _size(len_), _copy
51  (copy_) {
52    _contents = (t4_byte*)buf_; // moved out of intializers for DEC CXX 5.7
53    if (_copy)
54      _MakeCopy();
55}
56
57/// Copy constructor
58c4_Bytes::c4_Bytes(const c4_Bytes &src_): _size(src_._size), _copy(src_._copy) {
59  _contents = src_._contents; // moved out of intializers for DEC CXX 5.7
60  if (_copy || _contents == src_._buffer)
61    _MakeCopy();
62}
63
64/// Assignment, this may make a private copy of contents
65c4_Bytes &c4_Bytes::operator = (const c4_Bytes &src_) {
66  if (&src_ != this) {
67    _LoseCopy();
68
69    _contents = src_._contents;
70    _size = src_._size;
71    _copy = src_._copy;
72
73    if (_copy || _contents == src_._buffer)
74      _MakeCopy();
75  }
76
77  return  *this;
78}
79
80/// Swap the contents and ownership of two byte objects
81void c4_Bytes::Swap(c4_Bytes &bytes_) {
82  t4_byte *p = _contents;
83  int s = _size;
84  bool c = _copy;
85
86  _contents = bytes_._contents;
87  _size = bytes_._size;
88  _copy = bytes_._copy;
89
90  bytes_._contents = p;
91  bytes_._size = s;
92  bytes_._copy = c;
93
94  // if either one is using its local buffer, swap those too
95  if (_contents == bytes_._buffer || p == _buffer) {
96    t4_byte t[sizeof _buffer];
97
98    memcpy(t, _buffer, sizeof _buffer);
99    memcpy(_buffer, bytes_._buffer, sizeof _buffer);
100    memcpy(bytes_._buffer, t, sizeof _buffer);
101
102    if (_contents == bytes_._buffer)
103      _contents = _buffer;
104
105    if (bytes_._contents == _buffer)
106      bytes_._contents = bytes_._buffer;
107  }
108}
109
110/// Define contents as a freshly allocated buffer of given size
111t4_byte *c4_Bytes::SetBuffer(int length_) {
112  /* No substantial improvement measured:
113  Perhaps keep a correctly sized c4_Bytes object in each property?
114  It means c4_...Ref objects would need to store a pointer, not an id.
115
116  if (length_ == _size)
117  return _contents; // no work needed, get out fast
118   */
119  _LoseCopy();
120
121  _size = length_;
122  _copy = _size > (int)sizeof _buffer;
123
124  return _contents = _copy ? d4_new t4_byte[_size]: _buffer;
125}
126
127/// Allocate a buffer and fills its contents with zero bytes
128t4_byte *c4_Bytes::SetBufferClear(int length_) {
129  return (t4_byte*)memset(SetBuffer(length_), 0, length_);
130}
131
132void c4_Bytes::_MakeCopy() {
133  d4_assert(_contents != 0);
134
135  _copy = _size > (int)sizeof _buffer;
136
137  if (_size > 0)
138    _contents = (t4_byte*)memcpy(_copy ? d4_new t4_byte[_size]: _buffer,
139      _contents, _size);
140}
141
142/// Return true if the contents of both objects are equal
143bool operator == (const c4_Bytes &a_, const c4_Bytes &b_) {
144  return a_._contents == b_._contents || (a_._size == b_._size && memcmp
145    (a_._contents, b_._contents, a_._size) == 0);
146}
147
148/////////////////////////////////////////////////////////////////////////////
149