AAO DRAMA/DRAMA2 C++ Interface
DRAMA C++11 and later interface
sds.hh
Go to the documentation of this file.
1#ifndef _DRAMA2_SDS_INC
2#define _DRAMA2_SDS_INC
3
15/*
16 * History:
17 07-Jan-2014 - TJF - Original version
18 14-Sep-2016 - TJF - Start of history after development.
19 14-Sep-2016 - TJF - Add Exists() by index.
20 09-Jan-2023 - TJF - std::iterator is depreciated from C++17.
21
22 * The above ID is for Doxygen, this one has the format ACMM is looking for.
23 * "@(#) $Id$"
24 */
25#include "sds.h"
26#include "arg.h"
27#include <string>
28#include <stdio.h>
29#include <vector>
30#include <memory>
31#include <assert.h>
32
33/*
34 * A bit of a flaw in our include file layout means we need to declare this
35 * here. Its real location is drama.hh, but we don't want to include that
36 * in this file.
37 */
38namespace drama {
39 extern void CheckLockTaken(const std::string func,
40 const std::string &file,
41 const int lineNum) ;
42} // namespace drama.
43
44
45#include "drama/exception.hh"
46#include "drama/sdsarray.hh"
47
48#include <tuple>
49
50namespace drama {
54 namespace sds {
55 using std::begin;
56 using std::end;
57
58 /*
59 * The SdsArgPut() template function is used by the Put() method
60 * of sds::Id and is implementing traditional Arg style Put.
61 *
62 * The idea is that we must instantiate a specific version of this
63 * for each primitive SDS type and for strings.
64 *
65 * The Put() method won't link unless there is a specific version for
66 * the type in question. There are all implemented in parsys.cpp.
67 */
68 template <typename T> void SdsArgPut(
69 SdsIdType id, const std::string &name,
71
72 template <> void SdsArgPut<bool>(
73 SdsIdType id, const std::string &name,
74 bool value, StatusType *status);
75 template <> void SdsArgPut<char>(
76 SdsIdType id, const std::string &name,
77 char value, StatusType *status);
78 template <> void SdsArgPut<short>(
79 SdsIdType id, const std::string &name,
80 short value, StatusType *status);
81 template <> void SdsArgPut<unsigned short>(
82 SdsIdType id, const std::string &name,
83 unsigned short value, StatusType *status);
84 template <> void SdsArgPut<INT32>(
85 SdsIdType id, const std::string &name,
87 template <> void SdsArgPut<UINT32>(
88 SdsIdType id, const std::string &name,
90 template <> void SdsArgPut<INT64>(
91 SdsIdType id, const std::string &name,
93 template <> void SdsArgPut<UINT64>(
94 SdsIdType id, const std::string &name,
96 template <> void SdsArgPut<float>(
97 SdsIdType id, const std::string &name,
98 float value, StatusType *status);
99 template <> void SdsArgPut<double>(
100 SdsIdType id, const std::string &name,
101 double value, StatusType *status);
102
103 template <> void SdsArgPut<const char *>(
104 SdsIdType id, const std::string &name,
105 const char *value, StatusType *status);
106
107 /*
108 * The SdsArgGet() template function is used by the Get() method
109 * of sds::Id and is implementing traditional Arg style Get.
110 *
111 * The idea is that we must instantiate a specific version of this
112 * for each primitive SDS type.
113 *
114 * The Get() method won't link unless there is a specific version for
115 * the type in question.
116 */
117 template <typename T> void SdsArgGet(
118 SdsIdType id, const std::string &name,
119 T *value, StatusType *status);
120
121 template <> void SdsArgGet<bool>(
122 SdsIdType id, const std::string &name,
123 bool *value, StatusType *status);
124 template <> void SdsArgGet<char>(
125 SdsIdType id, const std::string &name,
126 char *value, StatusType *status);
127 template <> void SdsArgGet<short>(
128 SdsIdType id, const std::string &name,
129 short *value, StatusType *status);
130 template <> void SdsArgGet<unsigned short>(
131 SdsIdType id, const std::string &name,
132 unsigned short *value, StatusType *status);
133 template <> void SdsArgGet<INT32>(
134 SdsIdType id, const std::string &name,
136 template <> void SdsArgGet<UINT32>(
137 SdsIdType id, const std::string &name,
139 template <> void SdsArgGet<INT64>(
140 SdsIdType id, const std::string &name,
142 template <> void SdsArgGet<UINT64>(
143 SdsIdType id, const std::string &name,
145 template <> void SdsArgGet<float>(
146 SdsIdType id, const std::string &name,
147 float *value, StatusType *status);
148 template <> void SdsArgGet<double>(
149 SdsIdType id, const std::string &name,
150 double *value, StatusType *status);
151 template <> void SdsArgGet<std::string>(
152 SdsIdType id, const std::string &name,
153 std::string *value, StatusType *status);
154
155
156
157
158
159
160 /*
161 * The PutScalar() template function is used by the Put() method
162 * of sds::Id (no name version) and is implementing something like
163 * the traditional Arg style Put, but directly into the current item.
164 *
165 * The idea is that we must instantiate a specific version of this
166 * for each primitive SDS type and for strings.
167 *
168 * The Put() method won't link unless there is a specific version for
169 * the type in question. There are all implemented in parsys.cpp.
170 */
171 template <typename T> void PutScalar(
172 SdsIdType id,
173 T value, StatusType *status);
174
175 template <> void PutScalar<bool>(
176 SdsIdType id,
177 bool value, StatusType *status);
178 template <> void PutScalar<char>(
179 SdsIdType id,
180 char value, StatusType *status);
181 template <> void PutScalar<short>(
182 SdsIdType id,
183 short value, StatusType *status);
184 template <> void PutScalar<unsigned short>(
185 SdsIdType id,
186 unsigned short value, StatusType *status);
187 template <> void PutScalar<INT32>(
188 SdsIdType id,
190 template <> void PutScalar<UINT32>(
191 SdsIdType id,
193 template <> void PutScalar<INT64>(
194 SdsIdType id,
196 template <> void PutScalar<UINT64>(
197 SdsIdType id,
199 template <> void PutScalar<float>(
200 SdsIdType id,
201 float value, StatusType *status);
202 template <> void PutScalar<double>(
203 SdsIdType id,
204 double value, StatusType *status);
205
206 template <> void PutScalar<const char *>(
207 SdsIdType id,
208 const char *value, StatusType *status);
209
210 template <> void PutScalar<const std::string &>(
211 SdsIdType id,
212 const std::string &value, StatusType *status);
213
214 /*
215 * The GetScalar() template function is used by the Get() method
216 * (no name versions) of sds::Id and is implementing something like
217 * the traditional Arg style Get, but from the current item directly,
218 * hence why no name is supplied.
219 *
220 * The idea is that we must instantiate a specific version of this
221 * for each primitive SDS type.
222 *
223 * The Get() method won't link unless there is a specific version for
224 * the type in question.
225 */
226 template <typename T> void GetScalar(
227 SdsIdType id,
228 T *value, StatusType *status);
229
230 template <> void GetScalar<bool>(
231 SdsIdType id,
232 bool *value, StatusType *status);
233 template <> void GetScalar<char>(
234 SdsIdType id,
235 char *value, StatusType *status);
236 template <> void GetScalar<short>(
237 SdsIdType id,
238 short *value, StatusType *status);
239 template <> void GetScalar<unsigned short>(
240 SdsIdType id,
241 unsigned short *value, StatusType *status);
242 template <> void GetScalar<INT32>(
243 SdsIdType id,
245 template <> void GetScalar<UINT32>(
246 SdsIdType id,
248 template <> void GetScalar<INT64>(
249 SdsIdType id,
251 template <> void GetScalar<UINT64>(
252 SdsIdType id,
254 template <> void GetScalar<float>(
255 SdsIdType id,
256 float *value, StatusType *status);
257 template <> void GetScalar<double>(
258 SdsIdType id,
259 double *value, StatusType *status);
260 template <> void GetScalar<std::string>(
261 SdsIdType id,
262 std::string *value, StatusType *status);
263
264
268 class PrintObjectPnt {
269 public:
278 virtual void Print(const std::string &line) = 0;
279 };
283 class PrintObjectCR {
284 public:
293 virtual void Print(const std::string &line) const = 0;
294 };
401 class Id {
402 private:
403 SdsIdType _id; /* Actual Sds id. 0 (zero) is the null ID */
404 struct {
405 bool free : 1;/* Set true to cause destructor to free the OD*/
406 bool del : 1;/* If free is true, destructor will do SdsDelete*/
407 bool readfree : 1;/* if free , destructor will do SdsReadFree */
408 } _flags;
409
410 /*
411 * Private routine to clean up, will be called by destructor and
412 * Shallow copy operations.
413 *
414 * We defer the work to CleanUpWorker(), but need to indicate to
415 * it if SdsFreeIdAndCheck() should be invoked instead of
416 * just SdsFreeId().
417 *
418 * @param from_where Where have we been invoked form, for message
419 * about SDS ID free failures.
420 */
421 /* no exceptions allowed as may be called from move or destructor */
422 void CleanUp(const std::string &from_where) noexcept {
423#if defined(SDS_CHECK_FREE)||defined(SDS_CHECK_FREE_W)
424 bool check_free = true;
425#else
426 bool check_free = false;
427#endif
428 CleanUpWorker(check_free, from_where);
429 }
430
431 /*
432 * Do the actual clean up.
433 */
434 void CleanUpWorker(bool check, const std::string &from_where) noexcept;
435
436
437
438 /* This method is used by the ArrayAccess methods to check the item
439 is appropiate for the SdsArrayAccessHelper being used
440 */
441 template <class ContainerType>
442 void CheckArrayType(
443 const SdsCodeType code, /* Expected code */
444 const long ndims, /* Expected number of dims */
445 ContainerType * const dims) const { /* Actual dims written here */
446
448 /*
449 * Get details on the object.
450 */
451 GetDims(dims);
452 /*
453 * Check the code and number of dimensions are correct.
454 */
455 if (tcode != code)
456 {
458 "SDS type does not match expected array type");
459 }
460 if (dims->size() == 0)
461 {
463 "Attempt to access an array in an SDS structure which is not an array");
464 }
465 if (dims->size() != static_cast<unsigned>(ndims))
466 {
468 "SDS Array structure has % dimensions instead of the expected %",
469 dims->size(), ndims);
470 }
471
472 }
473 /*
474 * A simplified access to CheckArrayType, for a single
475 * dimensional array.
476 */
477 void CheckArrayTypeSingleDim(
478 const SdsCodeType code,
479 unsigned long * const nitems) const { /* Actual number of items written here*/
480
481 std::vector<unsigned long> dims;
482 CheckArrayType(code, 1, &dims);
483 *nitems = dims[0];
484
485 }
486
487 /*
488 * This is used to set an ArrayAccessHelper item's data
489 * pointer to be the result of SdsPointer() on this item.
490 *
491 */
492 template <class T> void SetArrayHelperDataAddr(
493 T * const data) const {
494
495 unsigned char *dataAddr = 0;
497 data->SetDataToAddr(dataAddr);
498 }
499
500
501 public:
513 /* Whilst we have SdsCloneId() we can't really use it at this
514 * point since we don't know what to do with the flags.
515 */
516 Id& operator=(const Id &rhs) = delete;
528 /* Whilst we have SdsCloneId() we can't really use it at this
529 * point since we don't know what to do with the flags (who
530 * gets to control deletion?)
531 */
532 Id(const Id &source) = delete;
533
534 /*
535 * Note, the "copy elision" rule is an allowed optimization
536 * in C++, implemented in gcc. It means that the following
537 * two methods will not actually be invoked, through they
538 * must exist for the moves to be allowed. In effect, in cases
539 * where a temp would be constructed and its value moved,
540 * the optimization allows the target variable to be constructed
541 * instead of the temp. See
542 *
543 * http://en.cppreference.com/w/cpp/language/copy_elision
544 *
545 */
546
547
555 Id& operator=(Id &&rhs) noexcept {
556 //fprintf(stderr,"drama::sds::Id move assignment triggered\n");
557
558 CleanUp("sds::Id move assignment");
560 _id = rhs._id;
561 _flags = std::move(rhs._flags);
562
563 rhs._id = 0;
564 return *this;
565 }
573 Id(Id &&source) noexcept :
574 _id(source._id), _flags(std::move(source._flags)) {
575 //fprintf(stderr,"drama::sds::Id move constructor triggered\n");
576 source._id = 0;
577 }
578
584 Id() {
585 _id = 0;
586 _flags.free = false;
587 _flags.del = false;
588 _flags.readfree = false;
589 }
590
591 private:
592 /* Construct an sds::Id item from an existing C language SDS id.
593 *
594 * This sds::Id constructor that takes an existing SDS id
595 * (C style) and creates an sds::Id class object which refers
596 * to that SDS id. You must explicitly specify if the item is to be
597 * free-ed and/or deleted when the object's destructor is invoked,
598 * and what you do depends on when what other code may do with
599 * item. The del and readfree are mutually exclusive, through
600 * this is currently not checked in this implementation.
601 *
602 * @param item The SdsIdType of the item. If 0 (the default), the
603 * sds::Id object constructed does not refer to any SDS
604 * item. This is normally only used when we want an
605 * argument to pass (by pointer) to a function which
606 * will use move assignment or sds::Id::ShallowCopy()
607 * to set the ID.
608 *
609 * @param free Set true to invoke DCF(SdsFreeId) on the ID when the
610 * object is destroyed. The default is false.
612 * @param del Set true to invoke DCF(SdsDelete) on the ID when
613 * the object is destroyed. The default is false.
614 *
615 * @param readfree Set true to invoke DCF(SdsReadFree) on the ID
616 * when the object is destroyed. The default is false.
617 *
618 */
619 explicit Id(const SdsIdType item, const bool free=false,
620 const bool del = false, const bool readfree = false) :
621 _id(item) {
622 _flags.free = free;
623 _flags.del = del;
624 _flags.readfree = readfree;
625 }
626 public:
642 static Id CreateNullItem();
643
670 const SdsIdType item, const bool free=false,
671 const bool del = false, const bool readfree = false);
672
684 const SdsIdType item);
685
686
703 static Id CreateFromSdsId(const SdsId &item);
704
722 static Id CreateFromSdsId(SdsId *item);
723
724
752 template <class ContainerType>
754
755 /*
756 * Confirm the container is a container of POD types.
757 * From C++20, std::is_pod<>() is depreciated, we can replace
758 * by std::is_standard_layout<>::value
759 */
760 static_assert(
761 std::is_standard_layout<typename ContainerType::value_type>::value,
762 "The value type in the container must be a standard layout type");
763
764 if (container->empty())
765 {
767 "Attempt to access data in empty container");
768 }
769 Id item(0, true, false, false); /* Must free-ed when done */
771 SdsAccess(&(*container)[0],&item._id,&status);
772 if (status != STATUS__OK)
773 DramaTHROW(status, "Failed to access SDS Item");
774
775 return item;
776 }
800 template <class ContainerType>
802 /*
803 * Confirm the container is a container of POD types.
804 * From C++20, std::is_pod<>() is depreciated, we can replace
805 * by std::is_standard_layout<>::value
806 */
807 static_assert(
808 std::is_standard_layout<typename ContainerType::value_type>::value,
809 "The value type in the container must be a standard layout type");
810
811
812 if (container.empty())
813 {
815 "Attempt to access data in empty container");
816 }
817
818
819 Id item(0, true, true, false); /* Must deleted and free-ed when done */
821 SdsImport(&container[0],&item._id,&status);
822 if (status != STATUS__OK)
823 DramaTHROW(status, "Failed to import SDS Item");
824
825 return item;
826 }
827
843 static Id FromFile(const std::string &filename);
862 virtual Id CreateChildItem(
863 const std::string &name,
864 const SdsCodeType code,
865 const std::string &extra = "") const;
866
880 static Id CreateTopLevel(
881 const std::string &name,
882 const SdsCodeType code,
883 const std::string &extra = "");
884
909 template <class ContainerType>
911 const std::string &name,
912 const SdsCodeType code,
913 const ContainerType& dims,
914 const std::string &extra = "") const {
915
916 Id item(0,true, false, false);
918
919 /*
920 * "dims" can be any container that
921 * 1. Has a size method.
922 * 2. Can be used to initialize a std::vector of unsigned long.
923 * 3. And it is validated for a 0 < size <= 7.
924 */
925 if ((dims.size() < 1)||(dims.size() > SDS__MAXDIMS))
926 {
928 "Failed to create new SDS array - % dimensions, minimum supported 1, maximum supported is %",
929 dims.size(),
931 }
932 /*
933 * We need to pass an array of unsigned long to SdsNew for
934 * the dimensions. The best approach is to create a vector
935 * of unsigned long and initialize it with the contents of
936 * our passed in container.
937 */
938 std::vector<unsigned long> myDims(dims);
939
940 SdsNew(_id,name.c_str(),extra.size(),extra.data(),code,
941 myDims.size(), myDims.data(),&item._id,&status);
942 if (status != STATUS__OK)
943 DramaTHROW_S(status, "Failed to create new SDS array top-level item %",name);
944 return item;
945 }
946
970 const std::string &name,
971 const SdsCodeType code,
972 const unsigned nElem,
973 const std::string &extra = "") const {
974
975 Id item(0,true, false, false);
977
978 /*
979 * This is a simplification of the above multi-dimensional
980 * version.
981 */
982 unsigned long dims[1];
983 dims[0] = nElem;
984 SdsNew(_id,name.c_str(),extra.size(),extra.data(),code,
985 1, dims, &item._id,&status);
986 if (status != STATUS__OK)
987 DramaTHROW_S(status, "Failed to create new SDS array top-level item %",name);
988 return item;
989 }
990
991
992
1012 template <class ContainerType>
1013 static Id CreateTopLevelArray(
1014 const std::string & name,
1015 const SdsCodeType code,
1016 const ContainerType& dims,
1017 const std::string &extra = ""){
1018
1019 Id item(0,true, true, false);
1021
1022 /*
1023 * "dims" can be any container that
1024 * 1. Has a size method.
1025 * 2. Can be used to initialize a std::vector of unsigned long.
1026 * 3. And it is validated for a 0 < size <= 7.
1027 */
1028 if ((dims.size() < 1)||(dims.size() > SDS__MAXDIMS))
1029 {
1031 "Failed to create new SDS array - % dimensions, minimum supported 1, maximum supported is %",
1032 dims.size(),
1034 }
1035 /*
1036 * We need to pass an array of unsigned long to SdsNew for
1037 * the dimensions. The best approach is to create a vector
1038 * of unsigned long and initialize it with the contents of
1039 * our passed in container.
1041 std::vector<unsigned long> myDims(dims);
1042
1043
1044 SdsNew(0,name.c_str(),extra.size(),extra.data(),code,
1045 myDims.size(), myDims.data(),&item._id,&status);
1046 if (status != STATUS__OK)
1047 DramaTHROW_S(status, "Failed to create new SDS array top-level item %",name);
1048
1049 return item;
1050 }
1051
1071 static Id CreateTopLevelArray(
1072 const std::string & name,
1073 const SdsCodeType code,
1074 const unsigned nElem,
1075 const std::string &extra = ""){
1076
1077 Id item(0,true, true, false);
1079
1080 /*
1081 * This is a simplification of the above multi-dimensional
1082 * version.
1083 */
1084 unsigned long dims[1];
1085 dims[0] = nElem;
1086
1087
1088 SdsNew(0,name.c_str(),extra.size(),extra.data(),code,
1089 1, dims,&item._id,&status);
1090 if (status != STATUS__OK)
1091 DramaTHROW_S(status, "Failed to create new SDS array top-level item %",name);
1092
1093 return item;
1094 }
1095
1096
1097
1131 template <class ContainerType>
1133 bool throwOnNotFound=true) const {
1134 Id item(0, true, false, false);
1135
1136 /*
1137 * "dims" can be any container that
1138 * 1. Has a size method.
1139 * 2. Can be used to initialize a std::vector of unsigned long.
1140 * 3. And it is validated for a 0 < size <= 7.
1141 */
1142 if ((indicies.size() < 1)||(indicies.size() > SDS__MAXDIMS))
1143 {
1145 "Failed to access SDS array cell - % dimensions, minimum supported 1, maximum supported is %",
1146 indicies.size(),
1148 }
1149 /*
1150 * We need to pass an array of unsigned long to SdsCell for
1151 * the dimensions. The best approach is to create a vector
1152 * of unsigned long and initialize it with the contents of
1153 * our passed in container.
1154 */
1155 std::vector<unsigned long> myDims(indicies);
1156
1157
1159 SdsCell(_id, myDims.size(), myDims.data(), &item._id, &status);
1160
1161 /* Special case of item not found and don't want to throw, return null id */
1163 {
1164 item._flags.del = false;
1165 return item;
1166 }
1167
1168 if (status != STATUS__OK)
1170 "Failed to access cell of existing SDS array id");
1171 return item;
1172 }
1188 virtual Id Copy() const;
1189
1211 virtual Id Find(const std::string &name,
1212 bool throwOnNotFound=true) const;
1213
1241 virtual Id Index(const long index, bool throwOnNotFound=true) const;
1242
1259 virtual ~Id() {
1260 /*Just invoke the private cleanup routine */
1261 CleanUp("sds::Id destructor");
1262 }
1263 /* Modify flags */
1264
1270 virtual void SetFree() { _flags.free = true; }
1276 virtual void SetDelete() { _flags.del = true; }
1277
1286 virtual void ClearDelete() { _flags.del = false; }
1287
1297 virtual void Outlive() {
1298 _flags.free = false;
1299 _flags.del = false;
1300 _flags.readfree = false;
1301 }
1302
1304 * General operations, as per similar SDS operations.
1305 * Currently only Delete, Get and Put are virtual.
1306 */
1307
1325 virtual void Delete() {
1327 SdsDelete(_id,&status);
1328 if (status == STATUS__OK)
1329 {
1330 _flags.del = false;
1331 if (_flags.free)
1332 {
1333 SdsFreeId(_id, &status);
1334 if (status == STATUS__OK)
1335 {
1336 _id = 0;
1337 _flags.free = false;
1338 }
1339 }
1340 }
1341 else
1342 DramaTHROW(status, "Failed to delete SDS item");
1343 }
1371 template <class ContainerType>
1372 void Export(ContainerType *container) const {
1374
1375 /*
1376 * Confirm the container is a container of POD types.
1377 * From C++20, std::is_pod<>() is depreciated, we can replace
1378 * by std::is_standard_layout<>::value
1379 */
1380 static_assert(
1381 std::is_standard_layout<typename ContainerType::value_type>::value,
1382 "The value type in the container must be a standard layout type");
1383
1384
1385 // Must multiple container size() in units by size of each unit.
1386 SdsExport(_id,
1387 (container->size()*sizeof((*container)[0])),
1388 &(*container)[0],&status);
1389 if (status != STATUS__OK)
1390 DramaTHROW(status, "Failed to export SDS item");
1391
1392 }
1417 template <class ContainerType>
1419 /*
1420 * Confirm the container is a container of POD types.
1421 * From C++20, std::is_pod<>() is depreciated, we can replace
1422 * by std::is_standard_layout<>::value
1423 */
1424 static_assert(
1425 std::is_standard_layout<typename ContainerType::value_type>::value ,
1426 "The value type in the container must be a standard layout type");
1427
1429 SdsExportDefined(_id,container->size(),&(*container)[0],&status);
1430 if (status != STATUS__OK)
1431 DramaTHROW(status, "Failed to export defined SDS item");
1432 }
1451 virtual void Extract() {
1453 SdsExtract(_id,&status);
1454 if (status != STATUS__OK)
1455 DramaTHROW(status, "Failed to extract SDS item");
1456
1457 /*
1458 * We need to modify the flags to those appropriate for
1459 * and indepent toplevel item
1460 */
1461 _flags.free = true;
1462 _flags.del = true;
1463 _flags.readfree = false;
1464 }
1477 virtual void Flush() {
1479
1480 //fprintf(stderr,"FLUSH:ID=%d\n", (int)(_id));
1481
1482
1483 SdsFlush(_id,&status);
1484 if (status != STATUS__OK)
1485 DramaTHROW(status, "Failed to flush SDS item");
1486 }
1514 template <typename T>
1515 void Get(const unsigned long length,
1516 T * const data,
1517 unsigned long *actlen = nullptr,
1518 const unsigned long offset=0) const {
1519
1520 /*
1521 * Confirm the data type is a POD type.
1522 * From C++20, std::is_pod<>() is depreciated, we can replace
1523 * by std::is_standard_layout<>::value.
1524 */
1525 static_assert(
1526 std::is_standard_layout<T>::value,
1527 "The type T must be a standard layout type");
1528
1529 unsigned long myactlen;
1530 if (!actlen) actlen = &myactlen;
1532 SdsGet(_id,length,offset,(void *)data,actlen,&status);
1533
1534 if (status != STATUS__OK)
1535 DramaTHROW(status, "Failed to Get data from SDS item");
1536 }
1549 virtual std::string GetExtra() const {
1550
1551 unsigned long length = 0;
1553 SdsGetExtraLen(_id, &length, &status);
1554 if ((status == STATUS__OK)&&(length == 0))
1555 return "";
1556 /*
1557 * Allocate some space to store the extra data in.
1558 */
1559 std::unique_ptr<char[]> extraData(new char[length+1]);
1560
1561 unsigned long actlen;
1562 /*
1563 * Get the data.
1564 */
1566 if (status != STATUS__OK)
1568 "Failed to Get extra data from SDS item");
1569 extraData[length] = 0; // Ensure null termination.
1570 return &extraData[0];
1571 }
1581 virtual std::string GetName() const {
1582
1583 char tName[SDS_C_NAMELEN];
1585 SdsGetName(_id,tName,&status);
1586
1587 if (status != STATUS__OK)
1589 "Failed to Get Name of SDS item");
1590 return tName;
1591
1592
1593 }
1608 virtual SdsCodeType GetCode() const {
1609 SdsCodeType code;
1611 SdsGetCode(_id,&code,&status);
1612 if (status != STATUS__OK)
1613 DramaTHROW(status, "Failed to Get code of SDS item");
1614
1615 return code;
1616
1617 }
1630 virtual void ValidateCode(SdsCodeType requiredCode) const {
1634 if (status != STATUS__OK)
1636 DramaTHROW(status, "Failed to Get code of SDS item");
1637 }
1638
1639 if (actualCode != requiredCode)
1640 {
1642 "SDS Item % has code %, was expected to have code %",
1643 GetName(),
1646 }
1647
1648 }
1649
1671 template <class ContainerType>
1672 void GetDims(ContainerType *dims) const {
1673
1674 unsigned long tdims[SDS_C_MAXARRAYDIMS];
1675 long ndims;
1678 if (status != STATUS__OK)
1680 "Failed to Get dimensions of SDS item");
1681
1682 /*
1683 * Copy dims to output location.
1684 */
1685 dims->clear();
1686 for (int i = 0; i < (int)(ndims) ; ++i)
1687 {
1688 dims->push_back(tdims[i]);
1689 }
1690
1691 }
1701 unsigned GetNumItems() const {
1702
1703 long numItems = 0;
1705 SdsNumItems(_id, &numItems, &status);
1706 if (status != STATUS__OK)
1708 "Failed to Get number of SDS items");
1709
1710 return numItems;
1711 }
1712
1713
1723 virtual void Insert(Id & to_insert) {
1725 SdsInsert(_id,to_insert._id,&status);
1726 if (status != STATUS__OK)
1727 DramaTHROW(status, "Failed to insert SDS item.");
1729
1730
1731 /*
1732 * If we succeed, the new child should not be deleted when
1733 * it's id is destroyed, so clear the flag. (This is why
1734 * we break Tony's normal rule of not using non-const
1735 * references.
1736 */
1737 to_insert._flags.del = false;
1738 }
1758 template <class ContainerType>
1759 void Insert(Id & to_insert,
1760 const ContainerType& dims) {
1761
1763 /*
1764 * "dims" can be any container that
1765 * 1. Has a size method.
1766 * 2. Can be used to initialize a std::vector of unsigned long.
1767 * 3. And it is validated for a 0 < size <= 7.
1768 */
1769 if ((dims.size() < 1)||(dims.size() > SDS__MAXDIMS))
1770 {
1772 "Failed to create new SDS array - % dimensions, minimum supported 1, maximum supported is %",
1773 dims.size(),
1775 }
1776
1777 /*
1778 * We need to pass an array of unsigned long to SdsNew for
1779 * the dimensions. The best approach is to create a vector
1780 * of unsigned long and initialize it with the contents of
1781 * our passed in container.
1782 */
1783 std::vector<unsigned long> myDims(dims);
1784
1785
1786 SdsInsertCell(_id,myDims.size(),myDims.data(),to_insert._id,&status);
1787
1788 if (status != STATUS__OK)
1789 DramaTHROW(status, "Failed to insert item into array cell");
1790 /*
1791 * If we succeed, the new child should not be deleted when
1792 * it's id is destroyed, so clear the flag
1793 */
1794 to_insert._flags.del = false;
1795 }
1796
1807 virtual void FillArray(const Id &elem) {
1809 SdsFillArray(_id,elem._id,&status);
1810 if (status != STATUS__OK)
1811 DramaTHROW(status, "Failed to fill structure");
1812 }
1813
1852 template <typename T>
1853 void Pointer(T **data, unsigned long * length=0) const {
1854
1855
1856 /*
1857 * Confirm the data type is a POD type.
1858 * From C++20, std::is_pod<>() is depreciated, we can replace
1859 * by std::is_standard_layout<>::value
1860 */
1861 static_assert(
1862 std::is_standard_layout<T>::value,
1863 "The type T must be a standard layout and type");
1864
1865
1866 unsigned long mylength;
1868
1869 if (!length) length = &mylength;
1870
1871 void *tdata;
1872
1874 if (status != STATUS__OK)
1875 DramaTHROW(status, "Failed to get pointer to data.");
1876
1877 *data = static_cast<T *>(tdata);
1878
1879 /* fprintf(stderr,"Pointer:ID=%d, pointer=%p\n",
1880 (int)(_id), (void *)(tdata));
1881 */
1882 }
1883
1908 template <typename T>
1909 void Put(const unsigned long length,
1910 const T * const data,
1911 const unsigned long offset=0) {
1913 /*
1914 * Confirm the data type is a POD type.
1915 * From C++20, std::is_pod<>() is depreciated, we can replace
1916 * by std::is_standard_layout<>::value
1917 */
1918 static_assert(
1919 std::is_standard_layout<T>::value,
1920 "The type T must be a standard layout type");
1921
1922 const void *tdata = static_cast<const void *>(data);
1923
1925 if (status != STATUS__OK)
1926 DramaTHROW(status, "Failed to put data into SDS.");
1927
1928
1929 }
1930
1942 virtual void PutExtra(const std::string &extra) {
1943
1945 SdsPutExtra(_id,extra.size(),extra.data(),&status);
1946 if (status != STATUS__OK)
1947 DramaTHROW(status, "Failed to put extra data into SDS.");
1948 }
1957 virtual void Rename(const std::string &name) {
1959 SdsRename(_id,name.c_str(),&status);
1960 if (status != STATUS__OK)
1961 DramaTHROW(status, "Failed to rename SDS item..");
1962
1963 }
1990 template <class ContainerType>
1991 void Resize(const ContainerType& dims) {
1992
1993
1995 /*
1996 * "dims" can be any container that
1997 * 1. Has a size method.
1998 * 2. Can be used to initialize a std::vector of unsigned long.
1999 * 3. And it is validated for a 0 < size <= 7.
2000 */
2001 if ((dims.size() < 1)||(dims.size() > SDS__MAXDIMS))
2002 {
2004 "Failed to create new SDS array - % dimensions, minimum supported 1, maximum supported is %",
2005 dims.size(),
2007 }
2008
2009 /*
2010 * We need to pass an array of unsigned long to SdsResize for
2011 * the dimensions. The best approach is to create a vector
2012 * of unsigned long and initialize it with the contents of
2013 * our passed in container.
2014 */
2015 std::vector<unsigned long> myDims(dims);
2016
2017 SdsResize(_id,myDims.size(),myDims.data(),&status);
2019 if (status != STATUS__OK)
2020 DramaTHROW(status, "Failed to resize SDS array");
2021
2022 }
2030 virtual unsigned long Size() const {
2031 unsigned long bytes;
2033 SdsSize(_id,&bytes,&status);
2034 if (status != STATUS__OK)
2035 DramaTHROW(status, "Failed to return size of SDS structure");
2036 return bytes;
2037
2038 }
2052 virtual unsigned long SizeDefined() const {
2053 unsigned long bytes;
2056 if (status != STATUS__OK)
2057 DramaTHROW(status, "Failed to return size of SDS structure");
2058 return bytes;
2059
2060 }
2061
2066 virtual void List() const {
2068 SdsList(_id,&status);
2069
2070 if (status != STATUS__OK)
2071 DramaTHROW(status, "Failed to list SDS structure");
2072 }
2078 virtual void List(FILE *to) const {
2080 SdsListTo(to, _id,&status);
2081
2082 if (status != STATUS__OK)
2083 DramaTHROW(status,"Failed to list SDS structure");
2084 }
2096 virtual void List(std::ostream &strm,
2097 int lineMaxLen=100) const;
2098
2121 virtual void List(PrintObjectPnt *printer, int lineMaxLen=100) const;
2122
2145 virtual void List(const PrintObjectCR
2146 &printer, int lineMaxLen=100) const;
2147
2158 virtual void Write(const std::string &filename) const {
2160 SdsWrite(_id,filename.c_str(),&status);
2161 if (status != STATUS__OK)
2163 "Failed to write SDS structure to file \"%\"",
2164 filename);
2165
2166 }
2167
2178 virtual bool IsExternal() const {
2180 int external = 0;
2181 SdsIsExternal(_id, &external, &status);
2182 if (status != STATUS__OK)
2183 DramaTHROW(status, "Failed to determine if SDS is external");
2184
2185 return external;
2186 }
2187 /* Return the address of an external item.
2188 *
2189 * This method is used to determine the address of the buffer
2190 * containing an external item, if this item refers to an external
2191 * item. This is the value given the contructor which accessed this
2192 * item.
2193 *
2194 * @returns The address of the external item data buffer.
2195 */
2196#if 0 // SdsGetExternInfo() does not actually exist - not sure what happened
2197 virtual void *GetExternInfo() const {
2198 void *data;
2200 SdsGetExternInfo(_id, &data, &status);
2201 if (status != STATUS__OK)
2203 "Failed to get SDS external structure address");
2204
2206 return data;
2207 }
2208#endif
2209
2210
2224 virtual bool Exists(const std::string &name) const;
2238 virtual bool Exists(unsigned index) const;
2239
2240
2252 explicit operator SdsIdType() const { return _id; }
2253
2259 explicit operator bool() const {
2260 return (_id != 0);
2261 }
2262
2290 virtual SdsIdType COut(const bool outlives, bool * const free = 0,
2291 bool * const del= 0, bool * const readfree = 0) {
2292 if (free)
2293 *free = _flags.free;
2294 if (del)
2295 *del = _flags.del;
2296 if (readfree)
2297 *readfree = _flags.readfree;
2298 if (outlives)
2299 _flags.free = _flags.del = _flags.readfree = false;
2300 return (_id);
2301 }
2321 virtual void ShallowCopy (const Id & source) {
2322 if (this != &source)
2323 {
2324 CleanUp("sds::Id::ShallowCopy 1"); /* Run destructor on old id */
2325 _id = source._id;
2326 _flags.free = _flags.del = _flags.readfree = false;
2327 }
2328 }
2329
2330
2350 virtual void ShallowCopy (Id * source, const bool outlives) {
2351 if (this != source)
2352 {
2353 CleanUp("sds::Id::ShallowCopy 2"); /* Run destructor on old id */
2354 _id = source->_id;
2355 if (outlives)
2356 {
2357 /* If we will outlive the source, then we copy the source's
2358 * flags and set the sources flags to false.
2359 */
2360
2361 _flags.free = source->_flags.free;
2362 _flags.del = source->_flags.del;
2363 _flags.readfree = source->_flags.readfree;
2364
2365 source->_flags.free = source->_flags.del =
2366 source->_flags.readfree = false;
2367 }
2368 else
2369 {
2370 _flags.free = _flags.del = _flags.readfree = false;
2371 }
2372 }
2373 }
2374
2375
2395 virtual void ShallowCopy (const SdsIdType source, const bool free=false,
2396 const bool del = false, const bool readfree = false) {
2397 CleanUp("sds::Id::ShallowCopy 3"); /* Run destructor on old id */
2398 _flags.free = free;
2399 _flags.del = del;
2400 _flags.readfree = readfree;
2401 _id = source;
2402 }
2403
2415 virtual void ToSdsId(::SdsId *target, const bool outlives= false) {
2416 if (outlives)
2417 {
2418 /*
2419 * If the target outlives the source, then copy the
2420 * flags and then clear the close versions.
2421 */
2422 target->ShallowCopy(_id, _flags.free,
2423 _flags.del, _flags.readfree);
2424 _flags.free = false;
2425 _flags.del = false;
2426 _flags.readfree = false;
2427 }
2428 else
2429 {
2430 /*
2431 * Otherwise the defaults will do.
2432 */
2433 target->ShallowCopy(_id);
2434 }
2435 }
2436
2473 template <typename T> void ArrayAccess(
2474 ArrayAccessHelper<T> * const data) const {
2475
2476 unsigned long dims[SDS_C_MAXARRAYDIMS];
2477 CheckArrayTypeSingleDim(data->Code(), dims);
2478 data->SetNumElements(dims[0]);
2479 SetArrayHelperDataAddr(data);
2480 }
2517 template <typename T> void ArrayAccess(
2518 const unsigned long nitems, /* Expected number of elements in array*/
2519 sds::ArrayAccessHelper<T> * const data) const {
2520
2521 unsigned long dims[SDS_C_MAXARRAYDIMS];
2522 CheckArrayTypeSingleDim(data->Code(), dims);
2523 if (dims[0] != nitems)
2524 {
2526 "ArrayAccess expected % items, found %",
2527 nitems, dims[0]);
2528 }
2529 data->SetNumElements(dims[0]);
2530 SetArrayHelperDataAddr(data);
2531 }
2576 template <typename T, class ContainerType> void ArrayAccess(
2577 ArrayAccessHelper<T> * const data,
2578 long ndims,
2579 ContainerType *dims) const {
2580
2581
2582
2583 if ((ndims < 1)||(ndims > SDS_C_MAXARRAYDIMS))
2584 {
2586 "Failed to access SDS array. Numbers of dimensions % invalid, must be in range 1 to %",
2588
2589 }
2590 CheckArrayType(data->Code(), ndims, dims);
2591
2592 /*
2593 * work out the number of elements
2594 */
2595 unsigned long elements = (*dims)[0];
2596 for (unsigned long i = 1; i < dims->size() ; ++i)
2597 {
2598 elements *= (long)((*dims)[i]);
2599 }
2600 data->SetNumElements(elements);
2601 /*
2602 * Access the data.
2604 SetArrayHelperDataAddr(data);
2605 }
2606
2607
2654 template <typename T, class ContainerType> void ArrayAccess(
2655 ArrayAccessHelper<T> * const data,
2656 ContainerType *dims ) const {
2657
2658 /*
2659 * A bit of a pain, we need to call Dims to get the number
2660 * of dimensions.
2661 */
2662 GetDims(dims);
2663 /*
2664 * The use the above version where we know the number of dimensions
2665 */
2666 ArrayAccess(data, dims->size(), dims);
2667 }
2668
2669
2670 /*** ARG style methods ***/
2671
2686 static Id CreateArgStruct(const std::string &name = "ArgStructure");
2687
2720 template <typename ContainerType>
2721 static Id CreateArgCmdStruct(
2722 const ContainerType &values,
2723 const std::string &name="ArgStructure") {
2724
2725
2726 Id item(CreateArgStruct(name));
2727
2728 std::string itemName = "Argument";
2729
2730 unsigned argNum = 1;
2731 for (auto s: values) {
2732
2733 std::string thisName = itemName + std::to_string(argNum);
2734
2735 item.Put(thisName,s);
2736
2737 ++argNum;
2738
2739 }
2740
2741 return item;
2742
2743 }
2776 template <typename T>
2777 static Id CreateArgCmdStruct(
2778 const std::initializer_list<T> &values,
2779 const std::string &name="ArgStructure") {
2780
2781 return CreateArgCmdStruct(std::vector<T>(values), name);
2782 }
2812 template <typename T>
2814 const T value,
2815 const std::string &name="ArgStructure") {
2816
2817
2818 Id item(CreateArgStruct(name));
2819 item.Put("Argument1",value);
2820 return item;
2821 }
2822
2823
2852 template <typename ContainerType>
2853 void AddToArgCmdStruct(
2854 const ContainerType &values,
2855 const unsigned firstArg = 1) {
2856
2857 std::string itemName = "Argument";
2858
2859 unsigned argNum = firstArg;
2860 if (argNum == 0) argNum = 1;
2861 for (auto s: values) {
2862
2863 std::string thisName = itemName + std::to_string(argNum);
2864
2865 Put(thisName,s);
2866
2867 ++argNum;
2868
2869 }
2870 }
2871
2872
2873
2885 virtual std::string toString(int maxlen = 200) {
2886
2887 /*
2888 * Allocate some space to store the string in.
2889 */
2890 //std::unique_ptr<char[]> string(new char[maxlen]);
2891 char *string = new char[maxlen];
2892 int length=0;
2894 /*
2895 * ArgToString() does the job for us.
2896 */
2897 ArgToString((SdsIdType)(*this),maxlen,&length,&string[0],&status);
2898 if (status != STATUS__OK)
2899 {
2900 delete[] string;
2901 DramaTHROW(status, "Failed to convert SDS to string");
2902 }
2903
2904 std::string result=&string[0];
2905
2906 return result;
2907 }
2935 template <typename T>
2936 void Put (const std::string &name, T value, const std::string &extraData="") {
2937
2938
2940 /* There must be a specialization of SdsArgPut() which
2941 supports type T. Note that conversion of DRAMA status
2942 to DRAMA 2 exceptions is done here so it need only be
2943 done once.
2944 */
2945 SdsArgPut(_id, name, value, &status);
2946 if (status != STATUS__OK)
2948 "ArgPut failed of item \"%\" failed",
2949 name);
2950 if (extraData != "")
2951 {
2952 auto itemId = Find(name);
2953 itemId.PutExtra(extraData);
2954 }
2955
2956 }
2957
2969 void Put (const std::string &name, const std::string &value,
2970 const std::string &extraData="") {
2971
2972
2974 ArgPutString(_id, name.c_str(), value.c_str(), &status);
2975 if (status != STATUS__OK)
2977 "ArgPut failed of item \"%\" failed",
2978 name);
2979 if (extraData != "")
2980 {
2981 auto itemId = Find(name);
2982 itemId.PutExtra(extraData);
2983 }
2984
2985 }
3005 template <typename T>
3006 void Get (const std::string &name, T *value) const {
3007
3008
3010 /* There must be a specialization of SdsArgGet() which
3011 supports type T. Note that conversion of DRAMA status
3012 to DRAMA 2 exceptions is done here so it need only be
3013 done once.
3014 */
3015 SdsArgGet(_id, name, value, &status);
3016 if (status != STATUS__OK)
3018 "ArgGet failed of item \"%\" failed",
3019 name);
3020
3021 }
3022
3023
3041 template <typename T>
3042 void Put (T value) {
3043
3044
3046 /* There must be a specialization of PutScalar() which
3047 supports type T. Note that conversion of DRAMA status
3048 to DRAMA 2 exceptions is done here so it need only be
3049 done once.
3050 */
3051 PutScalar(_id, value, &status);
3052 if (status != STATUS__OK)
3053 DramaTHROW(status, "PutScalar failed of item failed");
3054
3055 }
3056
3064 void Put (const std::string &value) {
3065
3066
3068 ArgCvt(value.c_str(),ARG_STRING,ARG_SDS,&_id,0,&status);
3070 if (status != STATUS__OK)
3071 DramaTHROW(status, "ArgCvt failed of item failed");
3072
3073 }
3085 template <typename T>
3086 void Get (T *value) const {
3087
3088
3090 /* There must be a specialization of GetScalar() which
3091 supports type T. Note that conversion of DRAMA status
3092 to DRAMA 2 exceptions is done here so it need only be
3093 done once.
3094 */
3095 GetScalar(_id, value, &status);
3096 if (status != STATUS__OK)
3097 DramaTHROW(status, "GetScalar failed of item failed");
3098
3099 }
3100
3101
3123 template <class ContainerType>
3124 void CheckItem(SdsCodeType code,
3125 const ContainerType& dims) const {
3126
3127
3129 /*
3130 * "dims" can be any container that
3131 * 1. Has a size method.
3132 * 2. Can be used to initialize a std::vector of unsigned long.
3133 * 3. And it is validated for a 0 <= size <= 7.
3134 * (Note - dims.size() is unsigned)
3135 */
3136 if (dims.size() > SDS__MAXDIMS)
3137 {
3139 "Failed to check SDS array - % dimensions, minimum supported 0, maximum supported is %",
3140 dims.size(),
3142 }
3143
3144 /*
3145 * We need to pass an array of unsigned long to ArgCheckItem for
3146 * the dimensions. The best approach is to create a vector
3147 * of unsigned long and initialize it with the contents of
3148 * our passed in container.
3149 */
3150 std::vector<long> myDims(dims);
3152 ArgCheckItem(_id,code, myDims.size(),myDims.data(),&status);
3153
3154 if (status != STATUS__OK)
3155 DramaTHROW(status, "Check of SDS item failed");
3156
3157 }
3163 virtual int GetInt() const;
3169 virtual unsigned int GetUInt() const;
3175 virtual long GetLong() const;
3176
3182 virtual unsigned long GetULong() const;
3188 virtual double GetDouble() const;
3189
3195 std::string GetString() const;
3197
3198
3199 /* Enable watching of this SDS id.
3200 *
3201 * Output will go to stderr and any older watch details
3202 * are lost
3203 */
3204 void SetWatch() {
3206 SdsSetWatch(_id, nullptr, nullptr,
3207 nullptr, nullptr, nullptr, &status);
3208 if (status != STATUS__OK)
3209 DramaTHROW(status, "SdsSetWatch failed");
3210 }
3211
3212 }; /* class Id */
3213
3223 private:
3224 SdsCheckType _chkData;
3225 int _line;
3226 std::string _file;
3227 std::string _function;
3228 public:
3249 IdChecker(int line, const char *file, const char *function)
3250 : _line(line), _file(file), _function(function) {
3252 SdsCheckInit(&_chkData, &ignore);
3253 }
3260 virtual ~IdChecker() {
3262 SdsCheck(0, &_chkData, &status);
3263 if (status == SDS__CHK_LEAK)
3264 fprintf(stderr,"Warning:sds::IdChecker:Function leaked SDS id's - function %s, file %s, check object at line %d\n", _function.c_str(), _file.c_str(), _line);
3265 else if (status == SDS__CHK_RELEASED)
3266 fprintf(stderr,"Warning:sds::IdChecker:Function released SDS id's - function %s, file %s, check object at line %d\n", _function.c_str(), _file.c_str(), _line);
3267 }
3268 };
3280#define SDS_CHECK_IDS2(function_) drama::sds:IdChecker _sds_id_checker(__LINE__, __FILE__, (function_))
3281
3282
3285 typedef std::shared_ptr<Id> IdPtr;
3286
3288
3289 /*
3290 * This structure is used to specify a deleter to unique_ptr in
3291 * the DataPointer class. It provides a null deleter operation as
3292 * SDS will handle tidying this up.
3293 */
3294 struct _nodel
3295 {
3296 void operator()(void *) const { }
3297 };
3298
3317 template <typename T>
3318 class DataPointer : public std::unique_ptr<T,_nodel> {
3319
3320 private:
3321 unsigned long _lengthBytes; // Length of item in bytes.
3322 drama::sds::Id _refId; // SDS Id.
3323 public:
3332
3333 /*
3334 * Confirm the data type is a POD type.
3335 * From C++20, std::is_pod<>() is depreciated, we can replace
3336 * by std::is_standard_layout<>::value
3337 */
3338 static_assert(
3339 std::is_standard_layout<T>::value,
3340 "The type T must be a standard layout and type");
3341
3342 T *dataPnt = 0;
3343 theId.Pointer(&dataPnt, &_lengthBytes);
3344
3345 if (_lengthBytes != sizeof(T))
3346 {
3348 "SDS Pointer error - expected % bytes, got %",
3349 sizeof(T), _lengthBytes);
3350
3351 }
3352
3353
3354 std::unique_ptr<T, _nodel> p(dataPnt, _nodel());
3355
3356 *((std::unique_ptr<T,_nodel>*)(this)) = std::move(p);
3357
3359
3360 }
3370
3371
3372 /*
3373 * Confirm the data type is a POD type.
3374 * From C++20, std::is_pod<>() is depreciated, we can replace
3375 * by std::is_standard_layout<>::value
3376 */
3377 static_assert(
3378 std::is_standard_layout<T>::value,
3379 "The type T must be a standard layout type");
3380
3381 T *dataPnt = 0;
3382 theId->Pointer(&dataPnt, &_lengthBytes);
3383
3384 if (_lengthBytes != sizeof(T))
3385 {
3387 "SDS Pointer error - expected % bytes, got %",
3388 sizeof(T), _lengthBytes);
3389
3390 }
3391
3392
3393 std::unique_ptr<T, _nodel> p(dataPnt, _nodel());
3394
3395 *((std::unique_ptr<T,_nodel>*)(this)) = std::move(p);
3397 _refId.ShallowCopy(theId, outlives);
3398
3399 }
3400
3401
3406 ~DataPointer() {
3407 try
3408 {
3409 _refId.Flush();
3410 }
3411 catch (...)
3412 {
3413 }
3414 }
3419 unsigned long NumBytes() const {
3420 return _lengthBytes;
3421 }
3422 }; // class DataPointer
3423
3443 template <typename T>
3444 class DataPointer<T[]> : public std::unique_ptr<T[], _nodel> {
3445
3446 private:
3447 unsigned long _numItems;
3448 unsigned long _lengthBytes;
3449 drama::sds::Id _refId;
3450 public:
3452 typedef T * iterator;
3454 typedef const T * const_iterator;
3456 typedef T value_type;
3457
3468
3469
3470 /*
3471 * Confirm the data type is a POD type.
3472 * From C++20, std::is_pod<>() is depreciated, we can replace
3473 * by std::is_standard_layout<>::value
3474 */
3475 static_assert(
3476 std::is_standard_layout<T>::value,
3477 "The type T must be a standard layout type");
3478
3479 T *dataPnt = 0;
3480 theId.Pointer(&dataPnt, &_lengthBytes);
3482 if (_lengthBytes < sizeof(T))
3485 "SDS Array Pointer error - expected at least % bytes, got %",
3486 sizeof(T), _lengthBytes);
3487
3488 }
3489
3490
3491 _numItems = _lengthBytes/sizeof(dataPnt[0]);
3492
3493
3494 std::unique_ptr<T[], _nodel> p(dataPnt, _nodel());
3495
3496 *((std::unique_ptr<T[],_nodel>*)(this)) = std::move(p);
3497
3498 _refId.ShallowCopy(theId);
3499
3500 }
3511
3512
3513 /*
3514 * Confirm the data type is a POD type.
3515 * From C++20, std::is_pod<>() is depreciated, we can replace
3516 * by std::is_standard_layout<>::value
3517 */
3518 static_assert(
3519 std::is_standard_layout<T>::value,
3520 "The type T must be a standard layout type");
3521
3522 T *dataPnt = 0;
3523 theId->Pointer(&dataPnt, &_lengthBytes);
3524
3525 if (_lengthBytes < sizeof(T))
3526 {
3528 "SDS Array Pointer error - expected at least % bytes, got %",
3529 sizeof(T), _lengthBytes);
3530
3531 }
3532
3533
3534 _numItems = _lengthBytes/sizeof(dataPnt[0]);
3535
3536
3537 std::unique_ptr<T[], _nodel> p(dataPnt, _nodel());
3538
3539 *((std::unique_ptr<T[],_nodel>*)(this)) = std::move(p);
3540
3541 _refId.ShallowCopy(theId, outlives);
3542
3543 }
3544
3549 ~DataPointer() {
3550 try
3551 {
3552 _refId.Flush();
3553 }
3554 catch (...)
3555 {
3556 }
3557 }
3562 unsigned long size() const {
3563 return _numItems;
3564 }
3569 unsigned long NumBytes() const {
3570 return _lengthBytes;
3571 }
3576 iterator begin() {
3577 return & (*this)[0];
3578 }
3583 iterator end() {
3584 return (&(*this)[0])+_numItems;
3585 }
3590 const_iterator begin() const {
3591 return & (*this)[0];
3592 }
3597 const_iterator end() const {
3598 return (&(*this)[0])+_numItems;
3599 }
3607 const_iterator cbegin() const {
3608 return & (*this)[0];
3609 }
3617 const_iterator cend() const {
3618 return (&(*this)[0])+_numItems;
3619 }
3631 bool empty() const {
3632 return false;
3633 }
3635 }; // class DataPointer - Array Partial specialization
3636
3664 /*
3665 * We need to implement the std::iterator template to ensure we pick
3666 * up various iterator types etc.
3667 *
3668 * It is unclear if we need to define the third argument to this
3669 * template, if we do, I'm not sure what it should be.
3670 *
3671 * std::iterator was depreciated from C++17, we are supposed
3672 * to now provide each of the relevant types explicitly.
3673 * See https://www.fluentcpp.com/2018/05/08/std-iterator-deprecated/ and
3674 * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0174r2.html#2.1
3675 */
3676 class IdIterator /*: public std::iterator<std::forward_iterator_tag, Id> */ {
3677 public: /* std::iterator equivalents */
3678 using iterator_category = std::forward_iterator_tag;
3679 using value_type = Id;
3680 using difference_type =std::ptrdiff_t;
3681 using pointer = Id*;
3682 using reference = Id&;
3683
3684 private:
3685 /* The item we are iterating through */
3686 const Id &_top;
3687 /* Is the item an array of structures. If false, presumed to
3688 * be a structure (validated by constructor)
3689 */
3690 bool _isArray = false;
3691 /* Index to Current component */
3692 unsigned long _curCell = ULONG_MAX;
3693 /* Index to last component + 1 */
3694 unsigned long _endCell = ULONG_MAX;
3695 public:
3707 explicit IdIterator(const Id & id, const bool setEnd=false) :
3708 _top(id) {
3709 /*
3710 * id must be a structure.
3711 */
3712 if (_top.GetCode() != SDS_STRUCT)
3713 {
3715 "Attempt to construct IdIterator on non-structured SDS item (code %)", _top.GetCode());
3716
3717 }
3718 /*
3719 * Grab the dimensions - can only work with a value of 0 or 1.
3720 */
3721 std::vector<unsigned> dims;
3722 _top.GetDims(&dims);
3723 if (dims.size() > 0)
3724 {
3725 /*
3726 * Array item.
3727 */
3728 _isArray = true;
3729 /*
3730 * Code does not yet handle dimensions greater then 1, as
3731 * that requires determining the order we index the
3732 * array etc.
3733 */
3734 if (dims.size() > 1)
3735 {
3737 "Attempt to construct IdIterator on an array of structures with more then 1 dimension - can't yet do that. ");
3738 }
3739 /*
3740 * Index of arrays starts at 1. dims[0] is one
3741 * past the last element.
3742 */
3743 _endCell = dims[0]+1;
3744 _curCell = 1;
3745 }
3746 else
3747 {
3748 /*
3749 * Indexing of structures starts at 1. GetNumItems() is
3750 * the maximum value.
3751 */
3752 _endCell = id.GetNumItems()+1;
3753 _curCell = 1;
3754 }
3755 /*
3756 * IF we are constructing the end item, set _curCell to _endCell.
3757 */
3758 if (setEnd)
3759 _curCell = _endCell;
3760 }
3761
3769 bool operator!= (const IdIterator& other) const {
3770 /* First ensure we are referring to the same SDS structure */
3771 if (&_top != &other._top)
3772 return false;
3773 return _curCell != other._curCell;
3774 }
3775
3781 Id operator* () const {
3782 if (_curCell >= _endCell)
3783 {
3785 "Attempt to dereference IdIterator past end of structure");
3786
3787
3788 }
3789 if (_isArray) {
3790 std::vector<unsigned long> indicies(1);
3791 indicies[0] = _curCell;
3792 return _top.Cell(indicies);
3793 } else {
3794 return _top.Index(_curCell);
3795 }
3803 const IdIterator & operator++ () {
3804 /*
3805 * Only increment if less then _endCell. This should ensure
3806 * we never advance past _endCell, ensuring that the comparison
3807 * against end() works correctly
3809 if (_curCell < _endCell)
3810 ++_curCell;
3811
3812 // although not strictly necessary for a range-based for loop
3813 // following the normal convention of returning a value from
3814 // operator++ is a good idea.
3815 return *this;
3816 }
3817
3818
3819 private:
3820 }; // class IdIterator
3821
3822
3823
3838 template <typename T>
3839 class ArrayContainer {
3840 public:
3842 typedef T value_type;
3844 typedef value_type& reference;
3846 typedef std::size_t size_type;
3847 private:
3848 T *_address = nullptr;
3849 size_type _size = 0;
3850 public:
3857 ArrayContainer(T *address, size_type size) :
3858 _address(address), _size(size){
3859 static_assert(
3860 std::is_standard_layout<T>::value,
3861 "The type T must be a standard layout and type");
3862 }
3867 bool empty() const {
3868 return (_size <= 0);
3874 size_type size() const {
3875 return _size;
3876 }
3883 return _address[n];
3887 ~ArrayContainer() {}
3888 }; // Class ArrayContainer
3889
3890
3891 inline drama::sds::IdIterator begin(const drama::sds::Id &id) {
3892 return drama::sds::IdIterator(id);
3893 }
3895 return drama::sds::IdIterator(id, true);
3896 }
3897
3898 } // namespace sds
3899
3900} // namespace drama
3902#endif
SdsCodeType Code() const
Return the SDS type code of the item being accessed.
Definition sdsarray.hh:262
Helper class for access to an SDS Scalar Arrays.
Definition sdsarray.hh:180
size_type size() const
Returns the size of the container in items.
Definition sds.hh:3901
reference operator[](size_type n)
Returns an item at a particular address.
Definition sds.hh:3909
bool empty() const
Returns true if the container is empty.
Definition sds.hh:3894
value_type & reference
The type for a reference to the value.
Definition sds.hh:3871
T value_type
The value type.
Definition sds.hh:3869
ArrayContainer(T *address, size_type size)
Create a container to access the array.
Definition sds.hh:3884
std::size_t size_type
The type used for sizes.
Definition sds.hh:3873
~ArrayContainer()
Destroy the container, not the underlying array item.
Definition sds.hh:3914
A container for simple arrays for use with SDS templates.
Definition sds.hh:3866
const_iterator cend() const
Returns a const iterator pointing to the past-the-end element in the array.
Definition sds.hh:3644
iterator begin()
Returns an iterator pointing to the first element in the array.
Definition sds.hh:3603
const_iterator cbegin() const
Returns a const iterator pointing to the first element in the array.
Definition sds.hh:3634
bool empty() const
Returns true if container is empty.
Definition sds.hh:3658
const T * const_iterator
const iterator for this item
Definition sds.hh:3481
iterator end()
Returns an iterator pointing to the past-the-end element in the array.
Definition sds.hh:3610
unsigned long size() const
Return the number of elements in the array.
Definition sds.hh:3589
DataPointer(const drama::sds::Id &theId)
DataPointer Constructor.
Definition sds.hh:3494
const_iterator begin() const
Returns a const iterator pointing to the first element in the array.
Definition sds.hh:3617
unsigned long NumBytes() const
Return the size of the item in bytes.
Definition sds.hh:3596
~DataPointer()
DataPointer destructor.
Definition sds.hh:3576
T * iterator
iterator for this item
Definition sds.hh:3479
T value_type
Returns the type of T
Definition sds.hh:3483
DataPointer(drama::sds::Id *theId, bool outlives=false)
DataPointer Constructor.
Definition sds.hh:3537
const_iterator end() const
Returns a const iterator pointing to the past-the-end element in the array.
Definition sds.hh:3624
unsigned long NumBytes() const
Return the size of the item in bytes.
Definition sds.hh:3446
DataPointer(drama::sds::Id *theId, bool outlives)
DataPointer Constructor.
Definition sds.hh:3396
~DataPointer()
DataPointer destructor.
Definition sds.hh:3433
DataPointer(const drama::sds::Id &theId)
DataPointer Constructor.
Definition sds.hh:3358
A class that provides direct access to the data of an SDS item, via a sub-class of std::unique_ptr<>.
Definition sds.hh:3345
IdChecker(int line, const char *file, const char *function)
Construct an SdsChecker object.
Definition sds.hh:3276
virtual ~IdChecker()
SdsCheck destructor.
Definition sds.hh:3287
A class to check for SDS leaks.
Definition sds.hh:3249
IdIterator(const Id &id, const bool setEnd=false)
Construct a forward iterator for working through an SDS structure or array of structures.
Definition sds.hh:3734
bool operator!=(const IdIterator &other) const
Inequality operator.
Definition sds.hh:3796
Id operator*() const
Dereference operator - return the sds::Id item the iterator is pointing to.
Definition sds.hh:3808
const IdIterator & operator++()
Increment operator (prefix version).
Definition sds.hh:3830
An iterator for working through SDS Structures and SDS arrays of structures.
Definition sds.hh:3703
virtual void SetFree()
Indicate the underlying SDS item should be free-ed when the sds::Id object is destroyed.
Definition sds.hh:1297
virtual unsigned long GetULong() const
If the SDS item refers to a scalar value, convert it to an unsigned long integer.
Id CreateChildArray(const std::string &name, const SdsCodeType code, const unsigned nElem, const std::string &extra="") const
Factory constructor method Constructor which creates a new child item which is a one-dimensional arra...
Definition sds.hh:996
Id & operator=(Id &&rhs) noexcept
Move assignment operator.
Definition sds.hh:582
virtual std::string GetName() const
Return the name of the SDS item.
Definition sds.hh:1608
virtual std::string GetExtra() const
Get extra data from an SDS item.
Definition sds.hh:1576
virtual Id CreateChildItem(const std::string &name, const SdsCodeType code, const std::string &extra="") const
Factory constructor method which creates a new (non-array) child item.
void Resize(const ContainerType &dims)
Change the dimensions of an SDS array.
Definition sds.hh:2018
static Id FromFile(const std::string &filename)
Factory constructor method that reads an SDS structure from a file.
void Get(const std::string &name, T *value) const
Fetch primitive value from a named component of the structure.
Definition sds.hh:3033
virtual void ClearDelete()
Indicate the underlying SDS structure should NOT be deleted when the sds::Id object is destroyed.
Definition sds.hh:1313
virtual bool Exists(unsigned index) const
Determine if a item of a given index exists in a structure.
void CheckItem(SdsCodeType code, const ContainerType &dims) const
Check an item has a required structure.
Definition sds.hh:3151
unsigned GetNumItems() const
Return the number of components in an SDS structure.
Definition sds.hh:1728
virtual long GetLong() const
If the SDS item refers to a scalar value, convert it to long integer.
virtual void Outlive()
Force the actual SDS ID to outlive the sds::Id variable.
Definition sds.hh:1324
void ArrayAccess(const unsigned long nitems, sds::ArrayAccessHelper< T > *const data) const
Access the data of a single dimensional SDS primitive item array of a specified number of elements.
Definition sds.hh:2544
void ArrayAccess(ArrayAccessHelper< T > *const data) const
Access the data of a single dimensional SDS primitive array item of a specified number of elements.
Definition sds.hh:2500
static Id CreateArgCmdStruct(const ContainerType &values, const std::string &name="ArgStructure")
Factory constructor which creates a new "Arg" style SDS structure in the DRAMA Command style.
Definition sds.hh:2748
virtual void List(const PrintObjectCR &printer, int lineMaxLen=100) const
List the contents of the structure via a PrintObjectCR.
virtual void SetDelete()
Indicate the underlying SDS structure should be deleted when the sds::Id object is destroyed.
Definition sds.hh:1303
virtual Id Find(const std::string &name, bool throwOnNotFound=true) const
Factory constructor method Constructor which returns a reference to a named item.
static Id CreateByAccess(ContainerType *container)
Factory constructor method that accesses an exported SDS structure found in a byte stream.
Definition sds.hh:780
virtual unsigned long SizeDefined() const
Return the size of an SDS structure, as required for exporting when fully defined.
Definition sds.hh:2079
virtual void Write(const std::string &filename) const
Write the contents of the structure to a file.
Definition sds.hh:2185
virtual void Rename(const std::string &name)
Rename the SDS item.
Definition sds.hh:1984
virtual void List() const
List the contents of the structure to standard output.
Definition sds.hh:2093
void Put(const std::string &name, const std::string &value, const std::string &extraData="")
Insert a string value into a named component of the structure.
Definition sds.hh:2996
static Id CreateFromSdsId(SdsId *item)
Factory constructor method that constructs an sds::Id item from an existing old C++ interface SdsId i...
virtual unsigned int GetUInt() const
If the SDS item refers to a scalar value, convert it to an unsigned integer.
void Put(T value)
Insert a primitive value into the item.
Definition sds.hh:3069
Id & operator=(const Id &rhs)=delete
Assignment operator - deleted.
virtual double GetDouble() const
If the SDS item refers to a scalar value, convert it to a double item.
void Insert(Id &to_insert, const ContainerType &dims)
Insert an SDS object into this object, which is a structured array.
Definition sds.hh:1786
Id Cell(const ContainerType &indicies, bool throwOnNotFound=true) const
Factory constructor method Constructor that returns a cell of an existing id which must refer to an S...
Definition sds.hh:1159
virtual void ToSdsId(::SdsId *target, const bool outlives=false)
Shallow copy to an SdsId type.
Definition sds.hh:2442
static Id CreateByImport(const ContainerType &container)
Factory constructor method that imports an exported SDS structure found in a byte stream.
Definition sds.hh:828
virtual void List(FILE *to) const
List the contents of the structure to a C file.
Definition sds.hh:2105
virtual void ValidateCode(SdsCodeType requiredCode) const
Validate the code of the SDS item.
Definition sds.hh:1657
void ExportDefined(ContainerType *container) const
Export the SDS structure into a buffer, defining any undefined data.
Definition sds.hh:1445
void Export(ContainerType *container) const
Export the SDS structure into a buffer.
Definition sds.hh:1399
void Pointer(T **data, unsigned long *length=0) const
Obtain a pointer to the data area of a primitive SDS item.
Definition sds.hh:1880
virtual SdsCodeType GetCode() const
Return the code of the SDS item.
Definition sds.hh:1635
void ArrayAccess(ArrayAccessHelper< T > *const data, ContainerType *dims) const
Access the data of an SDS primitive item array.
Definition sds.hh:2681
static Id CreateTopLevelArray(const std::string &name, const SdsCodeType code, const unsigned nElem, const std::string &extra="")
Factory constructor method Constructor which creates a new one-dimensional array top-level item.
Definition sds.hh:1098
virtual void List(std::ostream &strm, int lineMaxLen=100) const
List the contents of the structure to an output stream.
Id(const Id &source)=delete
Copy constructor - deleted.
virtual void ShallowCopy(const SdsIdType source, const bool free=false, const bool del=false, const bool readfree=false)
Shallow copy from SdsIdType.
Definition sds.hh:2422
virtual void Delete()
Delete the SDS item.
Definition sds.hh:1352
static Id CreateFromSdsId(const SdsId &item)
Factory constructor method that constructs an sds::Id item from an existing old C++ interface SdsId i...
void GetDims(ContainerType *dims) const
Return the dimensions of the SDS item.
Definition sds.hh:1699
virtual ~Id()
sds::Id Destructor.
Definition sds.hh:1286
virtual void FillArray(const Id &elem)
Fill out the contents of this object, which is a structured array.
Definition sds.hh:1834
virtual SdsIdType COut(const bool outlives, bool *const free=0, bool *const del=0, bool *const readfree=0)
Return this item as an SdsIdType for return to C code.
Definition sds.hh:2317
void ArrayAccess(ArrayAccessHelper< T > *const data, long ndims, ContainerType *dims) const
Access the data of an SDS primitive item array.
Definition sds.hh:2603
virtual void Insert(Id &to_insert)
Insert an SDS object into this object.
Definition sds.hh:1750
virtual Id Index(const long index, bool throwOnNotFound=true) const
Factory constructor method Constructor which returns an id to a structured item indexed by position...
virtual unsigned long Size() const
Return the size of an SDS structure, as required for exporting.
Definition sds.hh:2057
void Get(const unsigned long length, T *const data, unsigned long *actlen=nullptr, const unsigned long offset=0) const
Get data from an SDS item.
Definition sds.hh:1542
static Id CreateArgCmdStructSingle(const T value, const std::string &name="ArgStructure")
Factory constructor which creates a new "Arg" style SDS structure in the DRAMA Command style.
Definition sds.hh:2840
void Put(const std::string &value)
Insert a string value into the component.
Definition sds.hh:3091
virtual void Extract()
Extract the SDS structure from its parent.
Definition sds.hh:1478
virtual void PutExtra(const std::string &extra)
Put extra data into an SDS item.
Definition sds.hh:1969
virtual void List(PrintObjectPnt *printer, int lineMaxLen=100) const
List the contents of the structure via a PrintObjectPnt object.
static Id CreateTopLevel(const std::string &name, const SdsCodeType code, const std::string &extra="")
Constructor which creates a new (non-array) top-level item.
virtual Id Copy() const
Factory constructor method Id Copy constructor.
void AddToArgCmdStruct(const ContainerType &values, const unsigned firstArg=1)
Insert a set of values from a container into an SDS structure in in the DRAMA Command style.
Definition sds.hh:2880
static Id CreateFromSdsIdType(const SdsIdType item, const bool free=false, const bool del=false, const bool readfree=false)
Factory constructor method that constructs an sds::Id item from an existing C language SDS id.
virtual void ShallowCopy(Id *source, const bool outlives)
Shallow copy from sds::Id.
Definition sds.hh:2377
void Put(const unsigned long length, const T *const data, const unsigned long offset=0)
Put data into an SDS item.
Definition sds.hh:1936
virtual void Flush()
Flush data modified by pointer.
Definition sds.hh:1504
static Id CreateArgStruct(const std::string &name="ArgStructure")
Factory constructor which creates a new "Arg" style SDS structure.
void Get(T *value) const
Fetch primitive value from the component.
Definition sds.hh:3113
static Id CreateArgCmdStruct(const std::initializer_list< T > &values, const std::string &name="ArgStructure")
Factory constructor which creates a new "Arg" style SDS structure in the DRAMA Command style.
Definition sds.hh:2804
virtual int GetInt() const
If the SDS item refers to a scalar value, convert it to an integer.
Id()
Default constructor.
Definition sds.hh:611
Id(Id &&source) noexcept
Move copy constructor.
Definition sds.hh:600
Id CreateChildArray(const std::string &name, const SdsCodeType code, const ContainerType &dims, const std::string &extra="") const
Factory constructor method Constructor which creates a new child item which is an multi-dimensional a...
Definition sds.hh:937
std::string GetString() const
If the SDS item refers to a scalar value or a character string, convert it to a string item.
virtual void ShallowCopy(const Id &source)
Shallow copy from a const sds::Id which will outlive this object.
Definition sds.hh:2348
static Id CreateTopLevelArray(const std::string &name, const SdsCodeType code, const ContainerType &dims, const std::string &extra="")
Factory constructor method Constructor which creates a new array top-level item.
Definition sds.hh:1040
void Put(const std::string &name, T value, const std::string &extraData="")
Insert a primitive value into a named component of the structure.
Definition sds.hh:2963
static Id CreateFromSdsIdTypeCopy(const SdsIdType item)
Factory constructor method that constructs an sds::Id item by coping an existing C language SDS id.
static Id CreateNullItem()
Factory constructor method that constructs an null sds::Id item .
virtual bool IsExternal() const
Determine if the SDS structure is external.
Definition sds.hh:2205
virtual std::string toString(int maxlen=200)
Convert the structure to a string.
Definition sds.hh:2912
virtual bool Exists(const std::string &name) const
Determine if a named item exists in a structure.
A C++ Interface to the handling SDS structures.
Definition sds.hh:428
virtual void Print(const std::string &line) const =0
Method invoked to print one line of an SDS listing.
Abstract class which is sub-classed to print SDS item listings.
Definition sds.hh:310
virtual void Print(const std::string &line)=0
Method invoked to print one line of an SDS listing.
Abstract class which is sub-classed to print SDS item listings.
Definition sds.hh:295
#define DramaTHROW_S(status_, format_,...)
Throw a Drama exception with safe string formatting.
Definition exception.hh:108
#define DramaTHROW(status_, message_)
Throw a Drama exception.
Definition exception.hh:87
DRAMA 2 Exception classes.
std::shared_ptr< Id > IdPtr
A shared pointer for sds::Id items.
Definition sds.hh:3312
void CreateRunDramaTask()
Create and run a DRAMA task, with standard exception handling.
Definition task.hh:1322
void CheckLockTaken(const std::string func, const std::string &file, const int lineNum)
Ensure the current thread has taken the DRAMA task lock.
The drama namespace contains all the classes, types etc of the DRAMA 2 implementation.
Definition drama.hh:93
DRAMA 2 include file - drama::sds::ArrayAccessHelper Sds class definitions.