tzwrapper.cc: fixed use of iterator after erase
[barry.git] / src / builder.h
blob002abe6205ea5abc9bd1e5a9e8d66abf328b605c
1 ///
2 /// \file builder.h
3 /// Virtual protocol packet builder wrapper
4 ///
6 /*
7 Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/)
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 See the GNU General Public License in the COPYING file at the
19 root directory of this project for more details.
22 #ifndef __BARRY_BUILDER_H__
23 #define __BARRY_BUILDER_H__
25 #include "dll.h"
26 #include "data.h"
27 #include <stdint.h>
28 #include <string>
31 // This macro can be used to automatically generate code for all known
32 // record types. Just #undef HANDLE_BUILDER, then #define it to whatever
33 // you need, then use ALL_KNOWN_BUILDER_TYPES. See parser.cc for
34 // various examples.
36 // These are sorted so their GetDBName()'s will display in alphabetical order.
38 #define ALL_KNOWN_BUILDER_TYPES \
39 HANDLE_BUILDER(Contact) \
40 HANDLE_BUILDER(Calendar) \
41 HANDLE_BUILDER(CalendarAll) \
42 HANDLE_BUILDER(ContentStore) \
43 HANDLE_BUILDER(Memo) \
44 HANDLE_BUILDER(Task) \
46 namespace Barry {
48 // forward declarations
49 class IConverter;
52 // Builder class
54 /// Base class for the builder functor hierarchy.
55 ///
56 /// This defines the API used by the Controller and Packet classes
57 /// for building a raw device record to write to the device.
58 ///
59 class BXEXPORT Builder
61 public:
62 Builder() {}
63 virtual ~Builder() {}
65 /// Called to build the record field data. Store the raw data
66 /// in data, using offset to know where to write. Be sure to
67 /// update offset, and be sure to adjust the size of the data
68 /// packet (possibly with Data::ReleaseBuffer()).
69 ///
70 /// Returns true if successful, and false if at the end of
71 /// the series. Note that if EndOfFile() is false after
72 /// this function returns false, then there may be another
73 /// series available, which the next call to BuildRecord()
74 /// will determine.
75 ///
76 virtual bool BuildRecord(DBData &data, size_t &offset,
77 const IConverter *ic) = 0;
79 /// Same as BuildRecord, but does not care about any offsets.
80 /// The caller should call DBData::GetOffset() afterward
81 /// to discover if there is an offset to the result.
82 ///
83 /// This is usually the fastest of the two functions, since
84 /// extra copying may be required if a specific offset is
85 /// given. When building records from Record classes, both
86 /// functions are the same speed. But when building records
87 /// from the device, the device decides the offset, so FetchRecord()
88 /// is faster, since BuildRecord requires a copy to adjust
89 /// to the right offset.
90 ///
91 /// The caller should use the function that results in the least
92 /// amount of copying for the caller. If the caller doesn't
93 /// care about where the resulting record is in data, use
94 /// FetchRecord().
95 ///
96 virtual bool FetchRecord(DBData &data, const IConverter *ic) = 0;
98 /// Sometimes a builder can have multiple databases stored
99 /// in it, so when Build/Fetch returns false, check if there
100 /// is more data with this function. This function is
101 /// not used by database-oriented functions, but by pipe-
102 /// oriented functions.
103 virtual bool EndOfFile() const = 0;
108 // DBDataBuilder
110 /// Wrapper class around a DBData object, to make it easy to pass a DBData
111 /// object into a function or API that requires a builder. The main
112 /// advantage to this is that the Builder API allows for movement of
113 /// data, depending on the required offsets.
115 class BXEXPORT DBDataBuilder : public Builder
117 const DBData &m_orig;
119 public:
120 explicit DBDataBuilder(const DBData &orig);
121 virtual ~DBDataBuilder();
123 virtual bool BuildRecord(DBData &data, size_t &offset,
124 const IConverter *ic);
125 virtual bool FetchRecord(DBData &data, const IConverter *ic);
126 virtual bool EndOfFile() const;
130 // SetDBData
132 /// Contains the proper way to convert a record object into a DBData object.
134 template <class RecordT>
135 void SetDBData(const RecordT &rec, DBData &data, size_t &offset,
136 const IConverter *ic)
138 // Make sure record is valid before building it.
139 // This can throw Barry::ValidationError
140 rec.Validate();
142 // Build the DBData object
143 data.SetVersion(DBData::REC_VERSION_1);
144 data.SetOffset(offset);
145 data.SetDBName(RecordT::GetDBName());
146 data.SetIds(rec.GetRecType(), rec.GetUniqueId());
147 rec.BuildHeader(data.UseData(), offset);
148 rec.BuildFields(data.UseData(), offset, ic);
152 // RecordBuilder template class
154 /// Template class for easy creation of specific protocol packet builder
155 /// objects. This template takes the following template arguments:
157 /// - RecordT: One of the record classes in record.h
158 /// - StorageT: A custom storage functor class. An object of this type
159 /// will be called as a function with empty Record as an
160 /// argument. The storage class is expected to fill the
161 /// record object in preparation for building the packet
162 /// out of that data. These calls happen on the fly as the data
163 /// is sent to the device over USB, so it should not block forever.
165 /// Example SaveDatabase() call:
167 /// <pre>
168 /// FIXME
169 /// </pre>
171 template <class RecordT, class StorageT>
172 class RecordBuilder : public Builder
174 StorageT *m_storage;
175 bool m_owned;
176 bool m_record_loaded;
177 bool m_end_of_file;
178 RecordT m_rec;
180 public:
181 /// Constructor that references an externally managed storage object.
182 RecordBuilder(StorageT &storage)
183 : m_storage(&storage)
184 , m_owned(false)
185 , m_record_loaded(false)
186 , m_end_of_file(false)
190 /// Constructor that references a locally managed storage object.
191 /// The pointer passed in will be stored, and freed when this class
192 /// is destroyed. It is safe to call this constructor with
193 /// a 'new'ly created storage object.
194 RecordBuilder(StorageT *storage)
195 : m_storage(storage)
196 , m_owned(true)
197 , m_record_loaded(false)
198 , m_end_of_file(false)
202 ~RecordBuilder()
204 if( this->m_owned )
205 delete m_storage;
208 virtual bool BuildRecord(DBData &data, size_t &offset,
209 const IConverter *ic)
211 if( m_end_of_file )
212 return false;
214 if( !(*m_storage)(m_rec, *this) ) {
215 m_end_of_file = true;
216 return false;
219 SetDBData(m_rec, data, offset, ic);
220 return true;
223 virtual bool FetchRecord(DBData &data, const IConverter *ic)
225 size_t offset = 0;
226 return BuildRecord(data, offset, ic);
229 virtual bool EndOfFile() const
231 return m_end_of_file;
237 // RecordFetch template class
239 /// Generic record fetch class, to help with using records without
240 /// builder classes.
242 template <class RecordT>
243 class RecordFetch
245 const RecordT &m_rec;
246 mutable bool m_done;
248 public:
249 RecordFetch(const RecordT &rec) : m_rec(rec), m_done(false) {}
250 bool operator()(RecordT &rec, Builder &) const
252 if( m_done )
253 return false;
254 rec = m_rec;
255 m_done = true;
256 return true;
261 } // namespace Barry
263 #endif