This is Unofficial EPICS BASE Doxygen Site
FieldCreateFactory.cpp
Go to the documentation of this file.
1 /*FieldCreateFactory.cpp*/
2 /*
3  * Copyright information and license terms for this software can be
4  * found in the file LICENSE that is included with the distribution
5  */
10 #include <cstddef>
11 #include <cstdlib>
12 #include <string>
13 #include <cstdio>
14 #include <stdexcept>
15 #include <sstream>
16 
17 #include <epicsString.h>
18 #include <epicsMutex.h>
19 #include <epicsThread.h>
20 
21 #define epicsExportSharedSymbols
22 #include <pv/reftrack.h>
23 #include <pv/lock.h>
24 #include <pv/pvIntrospect.h>
25 #include <pv/factory.h>
26 #include <pv/serializeHelper.h>
27 #include <pv/thread.h>
28 #include <pv/pvData.h>
29 
31 using std::size_t;
32 using std::string;
33 
34 namespace epics { namespace pvData {
35 
37 
38 
39 struct Field::Helper {
40  static unsigned hash(Field *fld) {
41  std::ostringstream key;
42  // hash the output of operator<<()
43  // not efficient, but stable within this process.
44  key<<(*fld);
45  unsigned H = epicsStrHash(key.str().c_str(), 0xbadc0de1);
46  fld->m_hash = H;
47  return H;
48  }
49 };
50 
52  template<typename FLD>
53  static void cache(const FieldCreate *create, std::tr1::shared_ptr<FLD>& ent) {
54  unsigned hash = Field::Helper::hash(ent.get());
55 
56  Lock G(create->mutex);
57  // we examine raw pointers stored in create->cache, which is safe under create->mutex
58 
59  std::pair<cache_t::iterator, cache_t::iterator> itp(create->cache.equal_range(hash));
60  for(; itp.first!=itp.second; ++itp.first) {
61  Field* cent(itp.first->second);
62  FLD* centx(dynamic_cast<FLD*>(cent));
63  if(centx && compare(*centx, *ent)) {
64  try{
65  ent = std::tr1::static_pointer_cast<FLD>(cent->shared_from_this());
66  return;
67  }catch(std::tr1::bad_weak_ptr&){
68  // we're racing destruction.
69  // add a new entry.
70  // Field::~Field is in the process of removing this old one.
71  continue;
72  }
73  }
74  }
75 
76  create->cache.insert(std::make_pair(hash, ent.get()));
77  // cache cleaned from Field::~Field
78  }
79 };
80 
82  : m_fieldType(type)
83  , m_hash(0)
84 {
85  REFTRACE_INCREMENT(num_instances);
86 }
87 
89  REFTRACE_DECREMENT(num_instances);
90 }
91 
93 {
94  const FieldCreatePtr& create(getFieldCreate());
95 
96  Lock G(create->mutex);
97 
98  std::pair<FieldCreate::cache_t::iterator, FieldCreate::cache_t::iterator> itp(create->cache.equal_range(m_hash));
99  for(; itp.first!=itp.second; ++itp.first) {
100  Field* cent(itp.first->second);
101  if(cent==this) {
102  create->cache.erase(itp.first);
103  return;
104  }
105  }
106 }
107 
108 std::tr1::shared_ptr<PVField> Field::build() const
109 {
110  FieldConstPtr self(shared_from_this());
111  return getPVDataCreate()->createPVField(self);
112 }
113 
114 std::ostream& operator<<(std::ostream& o, const Field& f)
115 {
116  return f.dump(o);
117 };
118 
120  : Field(scalar),scalarType(scalarType)
121 {
122  if(scalarType<0 || scalarType>MAX_SCALAR_TYPE)
123  THROW_EXCEPTION2(std::invalid_argument, "Can't construct Scalar from invalid ScalarType");
124 }
125 
127 {
128  cacheCleanup();
129 }
130 
131 std::ostream& Scalar::dump(std::ostream& o) const
132 {
133  return o << format::indent() << getID();
134 }
135 
136 string Scalar::getID() const
137 {
138  static const string idScalarLUT[] = {
139  "boolean", // pvBoolean
140  "byte", // pvByte
141  "short", // pvShort
142  "int", // pvInt
143  "long", // pvLong
144  "ubyte", // pvUByte
145  "ushort", // pvUShort
146  "uint", // pvUInt
147  "ulong", // pvULong
148  "float", // pvFloat
149  "double", // pvDouble
150  "string" // pvString
151  };
152  return idScalarLUT[scalarType];
153 }
154 
155 int8 Scalar::getTypeCodeLUT(ScalarType scalarType)
156 {
157  static const int8 typeCodeLUT[] = {
158  0x00, // pvBoolean
159  0x20, // pvByte
160  0x21, // pvShort
161  0x22, // pvInt
162  0x23, // pvLong
163  0x24, // pvUByte
164  0x25, // pvUShort
165  0x26, // pvUInt
166  0x27, // pvULong
167  0x42, // pvFloat
168  0x43, // pvDouble
169  0x60 // pvString
170  };
171  return typeCodeLUT[scalarType];
172 }
173 
174 
175 void Scalar::serialize(ByteBuffer *buffer, SerializableControl *control) const {
176  control->ensureBuffer(1);
177  buffer->putByte(getTypeCodeLUT(scalarType));
178 }
179 
180 void Scalar::deserialize(ByteBuffer* /*buffer*/, DeserializableControl* /*control*/) {
181  // must be done via FieldCreate
182  throw std::runtime_error("not valid operation, use FieldCreate::deserialize instead");
183 }
184 
185 
186 std::tr1::shared_ptr<PVScalar> Scalar::build() const
187 {
188  return getPVDataCreate()->createPVScalar(std::tr1::static_pointer_cast<const Scalar>(shared_from_this()));
189 }
190 
191 
192 
193 std::string BoundedString::getID() const
194 {
195  std::ostringstream id;
196  id << Scalar::getID() << '(' << maxLength << ')';
197  return id.str();
198 }
199 
201 {
202  control->ensureBuffer(1);
203  buffer->putByte(0x83);
204  SerializeHelper::writeSize(maxLength, buffer, control);
205 }
206 
208 {
209  return maxLength;
210 }
211 
212 BoundedString::BoundedString(std::size_t maxStringLength) :
213  Scalar(pvString), maxLength(maxStringLength)
214 {
215  if (maxLength == 0)
216  THROW_EXCEPTION2(std::invalid_argument, "maxLength == 0");
217 }
218 
220 {
221  cacheCleanup();
222 }
223 
224 
225 static void serializeStructureField(const Structure* structure, ByteBuffer* buffer, SerializableControl* control)
226 {
227  // to optimize default (non-empty) IDs optimization
228  // empty IDs are not allowed
229  string id = structure->getID();
230  if (id == Structure::DEFAULT_ID) // TODO slow comparison
231  SerializeHelper::serializeString(string(), buffer, control);
232  else
233  SerializeHelper::serializeString(id, buffer, control);
234 
235  FieldConstPtrArray const & fields = structure->getFields();
236  StringArray const & fieldNames = structure->getFieldNames();
237  std::size_t len = fields.size();
238  SerializeHelper::writeSize(len, buffer, control);
239  for (std::size_t i = 0; i < len; i++)
240  {
241  SerializeHelper::serializeString(fieldNames[i], buffer, control);
242  control->cachedSerialize(fields[i], buffer);
243  }
244 }
245 
246 static StructureConstPtr deserializeStructureField(const FieldCreate* fieldCreate, ByteBuffer* buffer, DeserializableControl* control)
247 {
248  string id = SerializeHelper::deserializeString(buffer, control);
249  const std::size_t size = SerializeHelper::readSize(buffer, control);
250  FieldConstPtrArray fields; fields.reserve(size);
251  StringArray fieldNames; fieldNames.reserve(size);
252  for (std::size_t i = 0; i < size; i++)
253  {
254  fieldNames.push_back(SerializeHelper::deserializeString(buffer, control));
255  fields.push_back(control->cachedDeserialize(buffer));
256  }
257 
258  if (id.empty())
259  return fieldCreate->createStructure(fieldNames, fields);
260  else
261  return fieldCreate->createStructure(id, fieldNames, fields);
262 }
263 
264 static void serializeUnionField(const Union* punion, ByteBuffer* buffer, SerializableControl* control)
265 {
266  // to optimize default (non-empty) IDs optimization
267  // empty IDs are not allowed
268  string id = punion->getID();
269  if (id == Union::DEFAULT_ID) // TODO slow comparison
270  SerializeHelper::serializeString(string(), buffer, control);
271  else
272  SerializeHelper::serializeString(id, buffer, control);
273 
274  FieldConstPtrArray const & fields = punion->getFields();
275  StringArray const & fieldNames = punion->getFieldNames();
276  std::size_t len = fields.size();
277  SerializeHelper::writeSize(len, buffer, control);
278  for (std::size_t i = 0; i < len; i++)
279  {
280  SerializeHelper::serializeString(fieldNames[i], buffer, control);
281  control->cachedSerialize(fields[i], buffer);
282  }
283 }
284 
285 static UnionConstPtr deserializeUnionField(const FieldCreate* fieldCreate, ByteBuffer* buffer, DeserializableControl* control)
286 {
287  string id = SerializeHelper::deserializeString(buffer, control);
288  const std::size_t size = SerializeHelper::readSize(buffer, control);
289  FieldConstPtrArray fields; fields.reserve(size);
290  StringArray fieldNames; fieldNames.reserve(size);
291  for (std::size_t i = 0; i < size; i++)
292  {
293  fieldNames.push_back(SerializeHelper::deserializeString(buffer, control));
294  fields.push_back(control->cachedDeserialize(buffer));
295  }
296 
297  if (id.empty())
298  return fieldCreate->createUnion(fieldNames, fields);
299  else
300  return fieldCreate->createUnion(id, fieldNames, fields);
301 }
302 
304  : Field(type)
305 {
306 }
307 
309 
311  : Array(scalarArray),
312  elementType(elementType)
313 {
314  if(elementType<0 || elementType>MAX_SCALAR_TYPE)
315  throw std::invalid_argument("Can't construct ScalarArray from invalid ScalarType");
316 }
317 
319 {
320  cacheCleanup();
321 }
322 
323 const string ScalarArray::getIDScalarArrayLUT() const
324 {
325  static const string idScalarArrayLUT[] = {
326  "boolean[]", // pvBoolean
327  "byte[]", // pvByte
328  "short[]", // pvShort
329  "int[]", // pvInt
330  "long[]", // pvLong
331  "ubyte[]", // pvUByte
332  "ushort[]", // pvUShort
333  "uint[]", // pvUInt
334  "ulong[]", // pvULong
335  "float[]", // pvFloat
336  "double[]", // pvDouble
337  "string[]" // pvString
338  };
339  return idScalarArrayLUT[elementType];
340 }
341 
342 string ScalarArray::getID() const
343 {
344  return getIDScalarArrayLUT();
345 }
346 
347 std::ostream& ScalarArray::dump(std::ostream& o) const
348 {
349  return o << format::indent() << getID();
350 }
351 
353  control->ensureBuffer(1);
354  buffer->putByte((int8)0x08 | Scalar::getTypeCodeLUT(elementType));
355 }
356 
358  throw std::runtime_error("not valid operation, use FieldCreate::deserialize instead");
359 }
360 
361 std::tr1::shared_ptr<PVScalarArray> ScalarArray::build() const
362 {
363  return getPVDataCreate()->createPVScalarArray(std::tr1::static_pointer_cast<const ScalarArray>(shared_from_this()));
364 }
365 
366 
368 {
369  cacheCleanup();
370 }
371 
373  : ScalarArray(elementType),
374  size(size)
375 {
376 }
377 
379 {
380  char buffer[32];
381  sprintf(buffer, "%s<%zu>", ScalarTypeFunc::name(getElementType()), size);
382  return string(buffer);
383 }
384 
386  control->ensureBuffer(1);
387  buffer->putByte((int8)0x10 | Scalar::getTypeCodeLUT(getElementType()));
388  SerializeHelper::writeSize(size, buffer, control);
389 }
390 
391 
393 {
394  cacheCleanup();
395 }
396 
398  : ScalarArray(elementType),
399  size(size)
400 {
401 }
402 
404 {
405  char buffer[32];
406  sprintf(buffer, "%s[%zu]", ScalarTypeFunc::name(getElementType()), size);
407  return string(buffer);
408 }
409 
411  control->ensureBuffer(1);
412  buffer->putByte((int8)0x18 | Scalar::getTypeCodeLUT(getElementType()));
413  SerializeHelper::writeSize(size, buffer, control);
414 }
415 
416 
417 
419 : Array(structureArray),pstructure(structure)
420 {
421 }
422 
424 {
425  cacheCleanup();
426 }
427 
428 string StructureArray::getID() const
429 {
430  return pstructure->getID() + "[]";
431 }
432 
433 std::ostream& StructureArray::dump(std::ostream& o) const
434 {
435  o << format::indent() << getID() << std::endl;
436  {
438  o << *pstructure;
439  }
440  return o;
441 }
442 
444  control->ensureBuffer(1);
445  buffer->putByte((int8)0x88);
446  control->cachedSerialize(pstructure, buffer);
447 }
448 
450  throw std::runtime_error("not valid operation, use FieldCreate::deserialize instead");
451 }
452 
453 std::tr1::shared_ptr<PVValueArray<std::tr1::shared_ptr<PVStructure> > > StructureArray::build() const
454 {
455  return getPVDataCreate()->createPVStructureArray(std::tr1::static_pointer_cast<const StructureArray>(shared_from_this()));
456 }
457 
459 : Array(unionArray),punion(_punion)
460 {
461 }
462 
464 {
465  cacheCleanup();
466 }
467 
468 string UnionArray::getID() const
469 {
470  return punion->getID() + "[]";
471 }
472 
473 std::ostream& UnionArray::dump(std::ostream& o) const
474 {
475  o << format::indent() << getID() << std::endl;
476  {
478  o << *punion;
479  }
480  return o;
481 }
482 
483 void UnionArray::serialize(ByteBuffer *buffer, SerializableControl *control) const {
484  control->ensureBuffer(1);
485  if (punion->isVariant())
486  {
487  // unrestricted/variant union
488  buffer->putByte((int8)0x8A);
489  }
490  else
491  {
492  buffer->putByte((int8)0x89);
493  control->cachedSerialize(punion, buffer);
494  }
495 }
496 
498  throw std::runtime_error("not valid operation, use FieldCreate::deserialize instead");
499 }
500 
501 std::tr1::shared_ptr<PVValueArray<std::tr1::shared_ptr<PVUnion> > > UnionArray::build() const
502 {
503  return getPVDataCreate()->createPVUnionArray(std::tr1::static_pointer_cast<const UnionArray>(shared_from_this()));
504 }
505 
507 
508 const string & Structure::defaultId()
509 {
510  static const string id = "structure";
511  return id;
512 }
513 
515  StringArray const & fieldNames,
516  FieldConstPtrArray const & infields,
517  string const & inid)
518 : Field(structure),
519  fieldNames(fieldNames),
520  fields(infields),
521  id(inid)
522 {
523  if(inid.empty()) {
524  THROW_EXCEPTION2(std::invalid_argument, "Can't construct Structure, id is empty string");
525  }
526  if(fieldNames.size()!=fields.size()) {
527  THROW_EXCEPTION2(std::invalid_argument, "Can't construct Structure, fieldNames.size()!=fields.size()");
528  }
529  size_t number = fields.size();
530  for(size_t i=0; i<number; i++) {
531  const string& name = fieldNames[i];
532  if(name.empty()) {
533  THROW_EXCEPTION2(std::invalid_argument, "Can't construct Structure, empty string in fieldNames");
534  }
535  if(fields[i].get()==NULL)
536  THROW_EXCEPTION2(std::invalid_argument, "Can't construct Structure, NULL in fields");
537  // look for duplicates
538  for(size_t j=i+1; j<number; j++) {
539  string otherName = fieldNames[j];
540  int result = name.compare(otherName);
541  if(result==0) {
542  string message("Can't construct Structure, duplicate fieldName ");
543  message += name;
544  THROW_EXCEPTION2(std::invalid_argument, message);
545  }
546  }
547  }
548 }
549 
551 {
552  cacheCleanup();
553 }
554 
555 
556 string Structure::getID() const
557 {
558  return id;
559 }
560 
561 FieldConstPtr Structure::getField(string const & fieldName) const {
562  for(size_t i=0, N=fields.size(); i<N; i++) {
563  if(fieldName==fieldNames[i]) {
564  return fields[i];
565  }
566  }
567  return FieldConstPtr();
568 }
569 
570 size_t Structure::getFieldIndex(string const &fieldName) const {
571  size_t numberFields = fields.size();
572  for(size_t i=0; i<numberFields; i++) {
573  FieldConstPtr pfield = fields[i];
574  int result = fieldName.compare(fieldNames[i]);
575  if(result==0) return i;
576  }
577  return -1;
578 }
579 
580 FieldConstPtr Structure::getFieldImpl(string const & fieldName, bool throws) const {
581  for(size_t i=0, N=fields.size(); i<N; i++)
582  if(fieldName==fieldNames[i])
583  return fields[i];
584 
585  if (throws) {
586  std::stringstream ss;
587  ss << "Failed to get field: "
588  << fieldName << " (not found)";
589  throw std::runtime_error(ss.str());
590  } else {
591  return FieldConstPtr();
592  }
593 }
594 
595 std::ostream& Structure::dump(std::ostream& o) const
596 {
597  o << format::indent() << getID() << std::endl;
598  {
600  dumpFields(o);
601  }
602  return o;
603 }
604 
605 void Structure::dumpFields(std::ostream& o) const
606 {
607  size_t numberFields = fields.size();
608  for(size_t i=0; i<numberFields; i++) {
609  FieldConstPtr pfield = fields[i];
610  o << format::indent() << pfield->getID() << ' ' << fieldNames[i] << std::endl;
611  switch(pfield->getType()) {
612  case scalar:
613  case scalarArray:
614  break;
615  case structure:
616  {
617  Field const *xxx = pfield.get();
618  Structure const *pstruct = static_cast<Structure const*>(xxx);
620  pstruct->dumpFields(o);
621  break;
622  }
623  case structureArray:
624  {
626  Field const *xxx = pfield.get();
627  StructureArray const *pstructureArray = static_cast<StructureArray const*>(xxx);
628  o << *pstructureArray->getStructure();
629  break;
630  }
631  case union_:
632  {
633  Field const *xxx = pfield.get();
634  Union const *punion = static_cast<Union const*>(xxx);
636  punion->dumpFields(o);
637  break;
638  }
639  case unionArray:
640  {
642  Field const *xxx = pfield.get();
643  UnionArray const *punionArray = static_cast<UnionArray const*>(xxx);
644  o << *punionArray->getUnion();
645  break;
646  }
647  }
648  }
649 }
650 
651 void Structure::serialize(ByteBuffer *buffer, SerializableControl *control) const {
652  control->ensureBuffer(1);
653  buffer->putByte((int8)0x80);
654  serializeStructureField(this, buffer, control);
655 }
656 
657 void Structure::deserialize(ByteBuffer* /*buffer*/, DeserializableControl* /*control*/) {
658  throw std::runtime_error("not valid operation, use FieldCreate::deserialize instead");
659 }
660 
661 std::tr1::shared_ptr<PVStructure> Structure::build() const
662 {
663  return getPVDataCreate()->createPVStructure(std::tr1::static_pointer_cast<const Structure>(shared_from_this()));
664 }
665 
666 const string Union::DEFAULT_ID = Union::defaultId();
667 
668 const string & Union::defaultId()
669 {
670  static const string id = "union";
671  return id;
672 }
673 
674 const string Union::ANY_ID = Union::anyId();
675 
676 const string & Union::anyId()
677 {
678  static const string id = "any";
679  return id;
680 }
681 
683 : Field(union_),
684  fieldNames(),
685  fields(),
686  id(anyId())
687 {
688 }
689 
690 
691 Union::Union (
692  StringArray const & fieldNames,
693  FieldConstPtrArray const & infields,
694  string const & inid)
695 : Field(union_),
696  fieldNames(fieldNames),
697  fields(infields),
698  id(inid)
699 {
700  if(inid.empty()) {
701  THROW_EXCEPTION2(std::invalid_argument, "Can't construct Union, id is empty string");
702  }
703  if(fieldNames.size()!=fields.size()) {
704  THROW_EXCEPTION2(std::invalid_argument, "Can't construct Union, fieldNames.size()!=fields.size()");
705  }
706  if(fields.size()==0 && inid!=ANY_ID) {
707  THROW_EXCEPTION2(std::invalid_argument, "Can't construct Union, no fields only allowed when id = " + ANY_ID);
708  }
709 
710  size_t number = fields.size();
711  for(size_t i=0; i<number; i++) {
712  const string& name = fieldNames[i];
713  if(name.empty()) {
714  THROW_EXCEPTION2(std::invalid_argument, "Can't construct Union, empty string in fieldNames");
715  }
716  if(fields[i].get()==NULL)
717  THROW_EXCEPTION2(std::invalid_argument, "Can't construct Union, NULL in fields");
718  // look for duplicates
719  for(size_t j=i+1; j<number; j++) {
720  string otherName = fieldNames[j];
721  int result = name.compare(otherName);
722  if(result==0) {
723  string message("Can't construct Union, duplicate fieldName ");
724  message += name;
725  THROW_EXCEPTION2(std::invalid_argument, message);
726  }
727  }
728  }
729 }
730 
732 {
733  cacheCleanup();
734 }
735 
737 {
738  if(t!=scalar && t!=scalarArray)
739  THROW_EXCEPTION2(std::logic_error, "PVUnion::guess() only support scalar and scalarArray");
740 
741  int32 ret = -1;
742  for(size_t i=0, N=fields.size(); i<N; i++)
743  {
744  if(fields[i]->getType()!=t)
745  continue;
746 
748  switch(fields[i]->getType()) {
749  case scalar:
750  type = static_cast<const Scalar*>(fields[i].get())->getScalarType();
751  break;
752  case scalarArray:
753  type = static_cast<const ScalarArray*>(fields[i].get())->getElementType();
754  break;
755  default:
756  continue;
757  }
758 
759  if(type==s) {
760  // exact match
761  ret = i;
762  break; // we're done
763 
764  } else if(ret==-1) {
765  // first partial match
766  ret = i;
767  }
768  }
769  return ret;
770 }
771 
772 string Union::getID() const
773 {
774  return id;
775 }
776 
777 FieldConstPtr Union::getField(string const & fieldName) const {
778  size_t numberFields = fields.size();
779  for(size_t i=0; i<numberFields; i++) {
780  FieldConstPtr pfield = fields[i];
781  int result = fieldName.compare(fieldNames[i]);
782  if(result==0) return pfield;
783  }
784  return FieldConstPtr();
785 }
786 
787 size_t Union::getFieldIndex(string const &fieldName) const {
788  size_t numberFields = fields.size();
789  for(size_t i=0; i<numberFields; i++) {
790  FieldConstPtr pfield = fields[i];
791  int result = fieldName.compare(fieldNames[i]);
792  if(result==0) return i;
793  }
794  return -1;
795 }
796 
797 FieldConstPtr Union::getFieldImpl(string const & fieldName, bool throws) const {
798  for(size_t i=0, N=fields.size(); i<N; i++)
799  if(fieldName==fieldNames[i])
800  return fields[i];
801 
802  if (throws) {
803  std::stringstream ss;
804  ss << "Failed to get field: "
805  << fieldName << " (not found)";
806  throw std::runtime_error(ss.str());
807  } else {
808  return FieldConstPtr();
809  }
810 }
811 
812 std::ostream& Union::dump(std::ostream& o) const
813 {
814  o << format::indent() << getID() << std::endl;
815  {
817  dumpFields(o);
818  }
819  return o;
820 }
821 
822 void Union::dumpFields(std::ostream& o) const
823 {
824  size_t numberFields = fields.size();
825  for(size_t i=0; i<numberFields; i++) {
826  FieldConstPtr pfield = fields[i];
827  o << format::indent() << pfield->getID() << ' ' << fieldNames[i] << std::endl;
828  switch(pfield->getType()) {
829  case scalar:
830  case scalarArray:
831  break;
832  case structure:
833  {
834  Field const *xxx = pfield.get();
835  Structure const *pstruct = static_cast<Structure const*>(xxx);
837  pstruct->dumpFields(o);
838  break;
839  }
840  case structureArray:
841  {
843  o << *pfield;
844  break;
845  }
846  case union_:
847  {
848  Field const *xxx = pfield.get();
849  Union const *punion = static_cast<Union const*>(xxx);
851  punion->dumpFields(o);
852  break;
853  }
854  case unionArray:
855  {
857  o << *pfield;
858  break;
859  }
860  }
861  }
862 }
863 
864 void Union::serialize(ByteBuffer *buffer, SerializableControl *control) const {
865  control->ensureBuffer(1);
866  if (fields.size() == 0)
867  {
868  // unrestricted/variant union
869  buffer->putByte((int8)0x82);
870  }
871  else
872  {
873  buffer->putByte((int8)0x81);
874  serializeUnionField(this, buffer, control);
875  }
876 }
877 
878 void Union::deserialize(ByteBuffer* /*buffer*/, DeserializableControl* /*control*/) {
879  throw std::runtime_error("not valid operation, use FieldCreate::deserialize instead");
880 }
881 
882 std::tr1::shared_ptr<PVUnion> Union::build() const
883 {
884  return getPVDataCreate()->createPVUnion(std::tr1::static_pointer_cast<const Union>(shared_from_this()));
885 }
886 
887 FieldBuilder::FieldBuilder()
888  :fieldCreate(getFieldCreate())
889  ,idSet(false)
890  ,nestedClassToBuild(structure)
891  ,nestedArray(false)
892  ,createNested(true)
893 {}
894 
895 FieldBuilder::FieldBuilder(const Structure* S)
896  :fieldCreate(getFieldCreate())
897  ,id(S->getID())
898  ,idSet(!id.empty())
899  ,fieldNames(S->getFieldNames())
900  ,fields(S->getFields())
901  ,parentBuilder()
902  ,nestedClassToBuild(structure)
903  ,nestedName()
904  ,nestedArray(false)
905  ,createNested(false)
906 {}
907 
908 FieldBuilder::FieldBuilder(const FieldBuilderPtr & _parentBuilder,
909  const std::string& name,
910  const Structure* S)
911  :fieldCreate(_parentBuilder->fieldCreate)
912  ,id(S->getID())
913  ,idSet(!id.empty())
914  ,fieldNames(S->getFieldNames())
915  ,fields(S->getFields())
916  ,parentBuilder(_parentBuilder)
917  ,nestedClassToBuild(structure)
918  ,nestedName(name)
919  ,nestedArray(false)
920  ,createNested(false)
921 {}
922 
923 FieldBuilder::FieldBuilder(const FieldBuilderPtr & _parentBuilder,
924  const std::string& name,
925  const StructureArray* S)
926  :fieldCreate(getFieldCreate())
927  ,id(S->getStructure()->getID())
928  ,idSet(!id.empty())
929  ,fieldNames(S->getStructure()->getFieldNames())
930  ,fields(S->getStructure()->getFields())
931  ,parentBuilder(_parentBuilder)
932  ,nestedClassToBuild(structure)
933  ,nestedName(name)
934  ,nestedArray(true)
935  ,createNested(false)
936 {}
937 
938 FieldBuilder::FieldBuilder(const FieldBuilderPtr & _parentBuilder,
939  const std::string& name,
940  const Union* S)
941  :fieldCreate(getFieldCreate())
942  ,id(S->getID())
943  ,idSet(!id.empty())
944  ,fieldNames(S->getFieldNames())
945  ,fields(S->getFields())
946  ,parentBuilder(_parentBuilder)
947  ,nestedClassToBuild(union_)
948  ,nestedName(name)
949  ,nestedArray(false)
950  ,createNested(false)
951 {}
952 
953 FieldBuilder::FieldBuilder(const FieldBuilderPtr & _parentBuilder,
954  const std::string& name,
955  const UnionArray* S)
956  :fieldCreate(getFieldCreate())
957  ,id(S->getUnion()->getID())
958  ,idSet(!id.empty())
959  ,fieldNames(S->getUnion()->getFieldNames())
960  ,fields(S->getUnion()->getFields())
961  ,parentBuilder(_parentBuilder)
962  ,nestedClassToBuild(union_)
963  ,nestedName(name)
964  ,nestedArray(true)
965  ,createNested(false)
966 {}
967 
968 FieldBuilder::FieldBuilder(FieldBuilderPtr const & _parentBuilder,
969  string const & _nestedName,
970  Type _nestedClassToBuild, bool _nestedArray)
971  :fieldCreate(_parentBuilder->fieldCreate)
972  ,idSet(false)
973  ,parentBuilder(_parentBuilder)
974  ,nestedClassToBuild(_nestedClassToBuild)
975  ,nestedName(_nestedName)
976  ,nestedArray(_nestedArray)
977  ,createNested(true)
978 {}
979 
980 void FieldBuilder::reset()
981 {
982  id.erase();
983  idSet = false;
984  fieldNames.clear();
985  fields.clear();
986 }
987 
989 {
990  FieldBuilderPtr ret(new FieldBuilder);
991  return ret;
992 }
993 
995 {
996  FieldBuilderPtr ret(new FieldBuilder(S.get()));
997  return ret;
998 }
999 
1000 
1002 {
1003  this->id = id;
1004  idSet = true;
1005  return shared_from_this();
1006 }
1007 
1008 FieldBuilderPtr FieldBuilder::add(string const & name, ScalarType scalarType)
1009 {
1010  return add(name, fieldCreate->createScalar(scalarType));
1011 }
1012 
1013 FieldBuilderPtr FieldBuilder::addBoundedString(std::string const & name, std::size_t maxLength)
1014 {
1015  return add(name, fieldCreate->createBoundedString(maxLength));
1016 }
1017 
1018 FieldBuilderPtr FieldBuilder::add(string const & name, FieldConstPtr const & field)
1019 {
1020  const Field* cur = findField(name, field->getType());
1021  if(!cur) {
1022  fields.push_back(field); fieldNames.push_back(name);
1023  } else if(*cur!=*field) {
1024  THROW_EXCEPTION2(std::runtime_error, "duplicate field name w/ different type : "+name);
1025  } // else exact duplicate is silently ignored
1026  return shared_from_this();
1027 }
1028 
1029 FieldBuilderPtr FieldBuilder::addArray(string const & name, ScalarType scalarType)
1030 {
1031  return add(name, fieldCreate->createScalarArray(scalarType));
1032 }
1033 
1034 FieldBuilderPtr FieldBuilder::addFixedArray(string const & name, ScalarType scalarType, size_t size)
1035 {
1036  return add(name, fieldCreate->createFixedScalarArray(scalarType, size));
1037 }
1038 
1039 FieldBuilderPtr FieldBuilder::addBoundedArray(string const & name, ScalarType scalarType, size_t size)
1040 {
1041  return add(name, fieldCreate->createBoundedScalarArray(scalarType, size));
1042 }
1043 
1044 FieldBuilderPtr FieldBuilder::addArray(string const & name, FieldConstPtr const & element)
1045 {
1046  FieldConstPtr fld;
1047  switch (element->getType())
1048  {
1049  case structure:
1050  fld = fieldCreate->createStructureArray(static_pointer_cast<const Structure>(element));
1051  break;
1052  case union_:
1053  fld = fieldCreate->createUnionArray(static_pointer_cast<const Union>(element));
1054  break;
1055  case scalar:
1056 
1057  if (std::tr1::dynamic_pointer_cast<const BoundedString>(element).get())
1058  THROW_EXCEPTION2(std::invalid_argument, "bounded string arrays are not supported");
1059 
1060  fld = fieldCreate->createScalarArray(static_pointer_cast<const Scalar>(element)->getScalarType());
1061  break;
1062  // scalarArray?
1063  default:
1064  std::ostringstream msg("unsupported array element type: ");
1065  msg << element->getType();
1066  THROW_EXCEPTION2(std::invalid_argument, msg.str());
1067  }
1068 
1069  return add(name, fld);
1070 }
1071 
1072 FieldConstPtr FieldBuilder::createFieldInternal(Type type)
1073 {
1074  // minor optimization
1075  if (fieldNames.size() == 0 && type == union_)
1076  return fieldCreate->createVariantUnion();
1077 
1078  if (type == structure)
1079  {
1080  return (idSet) ?
1081  fieldCreate->createStructure(id, fieldNames, fields) :
1082  fieldCreate->createStructure(fieldNames, fields);
1083  }
1084  else if (type == union_)
1085  {
1086  return (idSet) ?
1087  fieldCreate->createUnion(id, fieldNames, fields) :
1088  fieldCreate->createUnion(fieldNames, fields);
1089  }
1090  else
1091  {
1092  std::ostringstream msg("unsupported type: ");
1093  msg << type;
1094  THROW_EXCEPTION2(std::invalid_argument, msg.str());
1095  }
1096 }
1097 
1098 
1100 {
1101  if (parentBuilder.get())
1102  THROW_EXCEPTION2(std::runtime_error, "createStructure() called in nested FieldBuilder");
1103 
1104  StructureConstPtr field(static_pointer_cast<const Structure>(createFieldInternal(structure)));
1105  reset();
1106  return field;
1107 }
1108 
1110 {
1111  if (parentBuilder.get())
1112  THROW_EXCEPTION2(std::runtime_error, "createUnion() called in nested FieldBuilder");
1113 
1114  UnionConstPtr field(static_pointer_cast<const Union>(createFieldInternal(union_)));
1115  reset();
1116  return field;
1117 }
1118 
1119 const Field* FieldBuilder::findField(const std::string& name, Type ftype)
1120 {
1121  // linear search on the theory that the number of fields is small
1122  for(size_t i=0; i<fieldNames.size(); i++)
1123  {
1124  if(name!=fieldNames[i])
1125  continue;
1126 
1127  if(fields[i]->getType()!=ftype)
1128  THROW_EXCEPTION2(std::invalid_argument, "nested field not required type: "+name);
1129 
1130  return fields[i].get();
1131  }
1132  return 0;
1133 }
1134 
1136 {
1137  const Field *cur = findField(name, structure);
1138  if(cur) {
1139  return FieldBuilderPtr(new FieldBuilder(shared_from_this(), name,
1140  static_cast<const Structure*>(cur)));
1141  }
1142  return FieldBuilderPtr(new FieldBuilder(shared_from_this(), name, structure, false));
1143 }
1144 
1145 
1147 {
1148  const Field *cur = findField(name, union_);
1149  if(cur) {
1150  return FieldBuilderPtr(new FieldBuilder(shared_from_this(), name,
1151  static_cast<const Union*>(cur)));
1152  }
1153  return FieldBuilderPtr(new FieldBuilder(shared_from_this(), name, union_, false));
1154 }
1155 
1156 
1158 {
1159  const Field *cur = findField(name, structureArray);
1160  if(cur) {
1161  return FieldBuilderPtr(new FieldBuilder(shared_from_this(), name,
1162  static_cast<const StructureArray*>(cur)));
1163  }
1164  return FieldBuilderPtr(new FieldBuilder(shared_from_this(), name, structure, true));
1165 }
1166 
1168 {
1169  const Field *cur = findField(name, unionArray);
1170  if(cur) {
1171  return FieldBuilderPtr(new FieldBuilder(shared_from_this(), name,
1172  static_cast<const UnionArray*>(cur)));
1173  }
1174  return FieldBuilderPtr(new FieldBuilder(shared_from_this(), name, union_, true));
1175 }
1176 
1178 {
1179  if (!parentBuilder)
1180  THROW_EXCEPTION2(std::runtime_error, "FieldBuilder::endNested() can only be called to create nested fields");
1181 
1182  FieldConstPtr nestedField = createFieldInternal(nestedClassToBuild);
1183 
1184  if(createNested) {
1185  if (nestedArray)
1186  parentBuilder->addArray(nestedName, nestedField);
1187  else
1188  parentBuilder->add(nestedName, nestedField);
1189  return parentBuilder;
1190  } else {
1191  for(size_t i=0, N = parentBuilder->fieldNames.size(); i<N; i++)
1192  {
1193  if(nestedName!=parentBuilder->fieldNames[i])
1194  continue;
1195 
1196  if(nestedArray) {
1197  if(nestedClassToBuild==structure)
1198  parentBuilder->fields[i] = fieldCreate->createStructureArray(std::tr1::static_pointer_cast<const Structure>(nestedField));
1199  else if(nestedClassToBuild==union_)
1200  parentBuilder->fields[i] = fieldCreate->createUnionArray(std::tr1::static_pointer_cast<const Union>(nestedField));
1201  else
1202  throw std::logic_error("bad nested class");
1203  } else {
1204  parentBuilder->fields[i] = nestedField;
1205  }
1206  return parentBuilder;
1207  }
1208  // this only reached if bug in ctor
1209  THROW_EXCEPTION2(std::logic_error, "no nested field field?");
1210  }
1211 }
1212 
1214 {
1215  return FieldBuilderPtr(new FieldBuilder());
1216 }
1217 
1219 {
1220  FieldBuilderPtr ret(new FieldBuilder(S.get()));
1221  return ret;
1222 }
1223 
1225 {
1226  if(scalarType<0 || scalarType>MAX_SCALAR_TYPE) {
1227  std::ostringstream strm("Can't construct Scalar from invalid ScalarType ");
1228  strm << scalarType;
1229  THROW_EXCEPTION2(std::invalid_argument, strm.str());
1230  }
1231 
1232  return scalars[scalarType];
1233 }
1234 
1236 {
1237  std::tr1::shared_ptr<BoundedString> s(new BoundedString(maxLength));
1238  Helper::cache(this, s);
1239  return s;
1240 }
1241 
1243 {
1244  if(elementType<0 || elementType>MAX_SCALAR_TYPE) {
1245  std::ostringstream strm("Can't construct ScalarArray from invalid ScalarType ");
1246  strm << elementType;
1247  THROW_EXCEPTION2(std::invalid_argument, strm.str());
1248  }
1249 
1250  return scalarArrays[elementType];
1251 }
1252 
1254 {
1255  if(elementType<0 || elementType>MAX_SCALAR_TYPE) {
1256  std::ostringstream strm("Can't construct fixed ScalarArray from invalid ScalarType ");
1257  strm << elementType;
1258  THROW_EXCEPTION2(std::invalid_argument, strm.str());
1259  }
1260 
1261  std::tr1::shared_ptr<ScalarArray> s(new FixedScalarArray(elementType, size));
1262  Helper::cache(this, s);
1263  return s;
1264 }
1265 
1267 {
1268  if(elementType<0 || elementType>MAX_SCALAR_TYPE) {
1269  std::ostringstream strm("Can't construct bounded ScalarArray from invalid ScalarType ");
1270  strm << elementType;
1271  THROW_EXCEPTION2(std::invalid_argument, strm.str());
1272  }
1273 
1274  std::tr1::shared_ptr<ScalarArray> s(new BoundedScalarArray(elementType, size));
1275  Helper::cache(this, s);
1276  return s;
1277 }
1278 
1280 {
1281  StringArray fieldNames;
1282  FieldConstPtrArray fields;
1283  return createStructure(fieldNames,fields);
1284 }
1285 
1286 namespace {
1287 bool xisalnum(char c)
1288 {
1289  return (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9');
1290 }
1291 
1292 void validateFieldName(const std::string& n)
1293 {
1294  // enforce [A-Za-z_][A-Za-z0-9_]*
1295  if(n.size()==0)
1296  throw std::invalid_argument("zero length field names not allowed");
1297  if(n[0]>='0' && n[0]<='9') {
1298  std::ostringstream msg;
1299  msg<<"Field name \""<<n<<"\" must begin with A-Z, a-z, or '_'";
1300  throw std::invalid_argument(msg.str());
1301  }
1302  for(size_t i=0, N=n.size(); i<N; i++)
1303  {
1304  char c = n[i];
1305  if(xisalnum(c)) {}
1306  else {
1307  switch(c){
1308  case '_':
1309  break;
1310  default:
1311  {
1312  std::ostringstream msg;
1313  msg<<"Invalid charactor '"<<c<<"' ("<<(int)c<<") in field name \""<<n<<"\" "
1314  "must be A-Z, a-z, 0-9, or '_'";
1315  throw std::invalid_argument(msg.str());
1316  }
1317  }
1318  }
1319  }
1320 }
1321 
1322 void validateFieldNames(const StringArray& l)
1323 {
1324  for(StringArray::const_iterator it=l.begin(), end=l.end(); it!=end; ++it)
1325  validateFieldName(*it);
1326 }
1327 }
1328 
1330  StringArray const & fieldNames,FieldConstPtrArray const & fields) const
1331 {
1332  validateFieldNames(fieldNames);
1333  std::tr1::shared_ptr<Structure> sp(new Structure(fieldNames,fields));
1334  Helper::cache(this, sp);
1335  return sp;
1336 }
1337 
1339  string const & id,
1340  StringArray const & fieldNames,
1341  FieldConstPtrArray const & fields) const
1342 {
1343  validateFieldNames(fieldNames);
1344  std::tr1::shared_ptr<Structure> sp(new Structure(fieldNames,fields,id));
1345  Helper::cache(this, sp);
1346  return sp;
1347 }
1348 
1350  StructureConstPtr const & structure) const
1351 {
1352  std::tr1::shared_ptr<StructureArray> sp(new StructureArray(structure));
1353  Helper::cache(this, sp);
1354  return sp;
1355 }
1356 
1358  StringArray const & fieldNames,FieldConstPtrArray const & fields) const
1359 {
1360  validateFieldNames(fieldNames);
1361  std::tr1::shared_ptr<Union> sp(new Union(fieldNames,fields));
1362  Helper::cache(this, sp);
1363  return sp;
1364 }
1365 
1367  string const & id,
1368  StringArray const & fieldNames,
1369  FieldConstPtrArray const & fields) const
1370 {
1371  validateFieldNames(fieldNames);
1372  std::tr1::shared_ptr<Union> sp(new Union(fieldNames,fields,id));
1373  Helper::cache(this, sp);
1374  return sp;
1375 }
1376 
1378 {
1379  return variantUnion;
1380 }
1381 
1383  UnionConstPtr const & punion) const
1384 {
1385  std::tr1::shared_ptr<UnionArray> sp(new UnionArray(punion));
1386  Helper::cache(this, sp);
1387  return sp;
1388 }
1389 
1391 {
1392  return variantUnionArray;
1393 }
1394 
1396  StructureConstPtr const & structure,
1397  string const & fieldName,
1398  FieldConstPtr const & field) const
1399 {
1400  StringArray const & oldNames = structure->getFieldNames();
1401  FieldConstPtrArray const & oldFields = structure->getFields();
1402  size_t oldLen = oldNames.size();
1403  StringArray newNames(oldLen+1);
1404  FieldConstPtrArray newFields(oldLen+1);
1405  for(size_t i = 0; i<oldLen; i++) {
1406  newNames[i] = oldNames[i];
1407  newFields[i] = oldFields[i];
1408  }
1409  newNames[oldLen] = fieldName;
1410  newFields[oldLen] = field;
1411  return createStructure(structure->getID(),newNames,newFields);
1412 }
1413 
1415  StructureConstPtr const & structure,
1416  StringArray const & fieldNames,
1417  FieldConstPtrArray const & fields) const
1418 {
1419  validateFieldNames(fieldNames);
1420  StringArray const & oldNames = structure->getFieldNames();
1421  FieldConstPtrArray const & oldFields = structure->getFields();
1422  size_t oldLen = oldNames.size();
1423  size_t extra = fieldNames.size();
1424  StringArray newNames(oldLen+extra);
1425  FieldConstPtrArray newFields(oldLen+extra);
1426  for(size_t i = 0; i<oldLen; i++) {
1427  newNames[i] = oldNames[i];
1428  newFields[i] = oldFields[i];
1429  }
1430  for(size_t i = 0; i<extra; i++) {
1431  newNames[oldLen +i] = fieldNames[i];
1432  newFields[oldLen +i] = fields[i];
1433  }
1434  return createStructure(structure->getID(),newNames,newFields);
1435 }
1436 
1437 
1438 static int decodeScalar(int8 code)
1439 {
1440  static const int integerLUT[] =
1441  {
1442  pvByte, // 8-bits
1443  pvShort, // 16-bits
1444  pvInt, // 32-bits
1445  pvLong, // 64-bits
1446  pvUByte, // unsigned 8-bits
1447  pvUShort, // unsigned 16-bits
1448  pvUInt, // unsigned 32-bits
1449  pvULong // unsigned 64-bits
1450  };
1451 
1452  static const int floatLUT[] =
1453  {
1454  -1, // reserved
1455  -1, // 16-bits
1456  pvFloat, // 32-bits
1457  pvDouble, // 64-bits
1458  -1,
1459  -1,
1460  -1,
1461  -1
1462  };
1463  // bits 7-5
1464  switch (code >> 5)
1465  {
1466  case 0: return pvBoolean;
1467  case 1: return integerLUT[code & 0x07];
1468  case 2: return floatLUT[code & 0x07];
1469  case 3: return pvString;
1470  default: return -1;
1471  }
1472 }
1473 
1475 {
1476  control->ensureData(1);
1477  int8 code = buffer->getByte();
1478  if (code == -1)
1479  return FieldConstPtr();
1480 
1481  int typeCode = code & 0xE7;
1482  int scalarOrArray = code & 0x18;
1483  bool notArray = (scalarOrArray == 0);
1484  if (notArray)
1485  {
1486  if (typeCode < 0x80)
1487  {
1488  // Type type = Type.scalar;
1489  int scalarType = decodeScalar(code);
1490  if (scalarType == -1)
1491  throw std::invalid_argument("invalid scalar type encoding");
1492  return scalars[scalarType];
1493  }
1494  else if (typeCode == 0x80)
1495  {
1496  // Type type = Type.structure;
1497  return deserializeStructureField(this, buffer, control);
1498  }
1499  else if (typeCode == 0x81)
1500  {
1501  // Type type = Type.union;
1502  return deserializeUnionField(this, buffer, control);
1503  }
1504  else if (typeCode == 0x82)
1505  {
1506  // Type type = Type.union; variant union (aka any type)
1507  return variantUnion;
1508  }
1509  else if (typeCode == 0x83)
1510  {
1511  // TODO cache?
1512  // bounded string
1513 
1514  size_t size = SerializeHelper::readSize(buffer, control);
1515 
1516  std::tr1::shared_ptr<Field> sp(
1517  new BoundedString(size));
1518  Helper::cache(this, sp);
1519  return sp;
1520  }
1521  else
1522  throw std::invalid_argument("invalid type encoding");
1523  }
1524  else // array
1525  {
1526  bool isVariable = (scalarOrArray == 0x08);
1527  // bounded == 0x10;
1528  bool isFixed = (scalarOrArray == 0x18);
1529 
1530  size_t size = (isVariable ? 0 : SerializeHelper::readSize(buffer, control));
1531 
1532  if (typeCode < 0x80)
1533  {
1534  // Type type = Type.scalarArray;
1535  int scalarType = decodeScalar(code);
1536  if (scalarType == -1)
1537  throw std::invalid_argument("invalid scalarArray type encoding");
1538  if (isVariable)
1539  return scalarArrays[scalarType];
1540  else if (isFixed)
1541  {
1542  // TODO use std::make_shared
1543  std::tr1::shared_ptr<Field> sp(
1544  new FixedScalarArray(static_cast<epics::pvData::ScalarType>(scalarType), size));
1545  Helper::cache(this, sp);
1546  return sp;
1547  }
1548  else
1549  {
1550  // TODO use std::make_shared
1551  std::tr1::shared_ptr<Field> sp(
1552  new BoundedScalarArray(static_cast<epics::pvData::ScalarType>(scalarType), size));
1553  Helper::cache(this, sp);
1554  return sp;
1555  }
1556  }
1557  else if (typeCode == 0x80)
1558  {
1559  // TODO fixed and bounded array support
1560  if (!isVariable)
1561  throw std::invalid_argument("fixed and bounded structure array not supported");
1562 
1563  // Type type = Type.structureArray;
1564  StructureConstPtr elementStructure = std::tr1::static_pointer_cast<const Structure>(control->cachedDeserialize(buffer));
1565  // TODO use std::make_shared
1566  std::tr1::shared_ptr<Field> sp(new StructureArray(elementStructure));
1567  Helper::cache(this, sp);
1568  return sp;
1569  }
1570  else if (typeCode == 0x81)
1571  {
1572  // TODO fixed and bounded array support
1573  if (!isVariable)
1574  throw std::invalid_argument("fixed and bounded structure array not supported");
1575 
1576  // Type type = Type.unionArray;
1577  UnionConstPtr elementUnion = std::tr1::static_pointer_cast<const Union>(control->cachedDeserialize(buffer));
1578  // TODO use std::make_shared
1579  std::tr1::shared_ptr<Field> sp(new UnionArray(elementUnion));
1580  Helper::cache(this, sp);
1581  return sp;
1582  }
1583  else if (typeCode == 0x82)
1584  {
1585  // TODO fixed and bounded array support
1586  if (!isVariable)
1587  throw std::invalid_argument("fixed and bounded structure array not supported");
1588 
1589  // Type type = Type.unionArray; variant union (aka any type)
1590  return variantUnionArray;
1591  }
1592  else
1593  throw std::invalid_argument("invalid type encoding");
1594  }
1595 }
1596 
1597 namespace detail {
1600  field_factory() :fieldCreate(new FieldCreate()) {
1601  registerRefCounter("Field", &Field::num_instances);
1603  }
1604 };
1605 }
1606 
1607 static detail::field_factory* field_factory_s;
1608 static epicsThreadOnceId field_factory_once = EPICS_THREAD_ONCE_INIT;
1609 
1610 static void field_factory_init(void*)
1611 {
1612  try {
1613  field_factory_s = new detail::field_factory;
1614  }catch(std::exception& e){
1615  std::cerr<<"Error initializing getFieldCreate() : "<<e.what()<<"\n";
1616  }
1617 }
1618 
1620 {
1621  epicsThreadOnce(&field_factory_once, &field_factory_init, 0);
1622  if(!field_factory_s->fieldCreate)
1623  throw std::logic_error("getFieldCreate() not initialized");
1624  return field_factory_s->fieldCreate;
1625 }
1626 
1627 FieldCreate::FieldCreate()
1628 {
1629  for (int i = 0; i <= MAX_SCALAR_TYPE; i++)
1630  {
1631  std::tr1::shared_ptr<Scalar> sp(new Scalar(static_cast<ScalarType>(i)));
1632  Helper::cache(this, sp);
1633  scalars.push_back(sp);
1634 
1635  std::tr1::shared_ptr<ScalarArray> spa(new ScalarArray(static_cast<ScalarType>(i)));
1636  Helper::cache(this, spa);
1637  scalarArrays.push_back(spa);
1638  }
1639 
1640  std::tr1::shared_ptr<Union> su(new Union());
1641  Helper::cache(this, su);
1642  variantUnion = su;
1643 
1644  std::tr1::shared_ptr<UnionArray> sua(new UnionArray(variantUnion));
1645  Helper::cache(this, sua);
1646  variantUnionArray = sua;
1647 }
1648 
1649 }}
1650 
1651 namespace std{
1652  std::ostream& operator<<(std::ostream& o, const epics::pvData::Field *ptr)
1653  {
1654  if(ptr) return o << *ptr;
1655  return o << "nullptr";
1656  }
1657 }
int8_t int8
Definition: pvType.h:75
virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control) OVERRIDE FINAL
StructureConstPtr createStructure() const
unsigned int epicsStrHash(const char *str, unsigned int seed)
Definition: epicsString.c:356
FieldBuilderPtr addArray(std::string const &name, ScalarType scalarType)
std::tr1::shared_ptr< PVUnion > build() const
epics::pvData::BitSetPtr empty
Definition: pvAccess.cpp:135
This class implements introspection object for Scalar.
Definition: pvIntrospect.h:397
This class implements introspection object for a union.
Definition: pvIntrospect.h:866
const char * name(ScalarType t)
Definition: TypeFunc.cpp:76
pvac::PutEvent result
Definition: clientSync.cpp:117
EPICS_ALWAYS_INLINE int8 getByte()
Definition: byteBuffer.h:617
FixedScalarArray(ScalarType scalarType, std::size_t size)
#define THROW_EXCEPTION2(TYPE, MSG)
static std::string deserializeString(ByteBuffer *buffer, DeserializableControl *control)
virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control) OVERRIDE FINAL
virtual std::ostream & dump(std::ostream &o) const OVERRIDE FINAL
int i
Definition: scan.c:967
virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control) OVERRIDE FINAL
ScalarType getScalarType(const string &pvalue)
Definition: TypeFunc.cpp:69
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const OVERRIDE FINAL
std::size_t getFieldIndex(std::string const &fieldName) const
char * cache
Definition: reader.c:18
ScalarArray(ScalarType scalarType)
static size_t num_instances
Definition: thread.h:192
shared_ptr< T > static_pointer_cast(shared_ptr< U > const &r) BOOST_NOEXCEPT
Definition: shared_ptr.hpp:788
virtual std::string getID() const OVERRIDE FINAL
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const OVERRIDE FINAL
static const std::string & anyId()
StructureArrayConstPtr createStructureArray(StructureConstPtr const &structure) const
virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control) OVERRIDE FINAL
pvd::StructureConstPtr type
const StructureConstPtr & getStructure() const
Definition: pvIntrospect.h:617
Definition: memory.hpp:41
TODO only here because of the Lockable.
Definition: ntaggregate.cpp:16
virtual std::string getID() const OVERRIDE FINAL
FieldBuilderPtr addBoundedArray(std::string const &name, ScalarType scalarType, std::size_t bound) PVD_DEPRECATED_52
std::tr1::shared_ptr< const Structure > StructureConstPtr
Definition: pvIntrospect.h:162
A lock for multithreading.
Definition: lock.h:36
std::tr1::shared_ptr< const StructureArray > StructureArrayConstPtr
Definition: pvIntrospect.h:166
StructureArray(StructureConstPtr const &structure)
#define NULL
Definition: catime.c:38
FieldConstPtrArray const & getFields() const
Definition: pvIntrospect.h:823
static void writeSize(std::size_t s, ByteBuffer *buffer, SerializableControl *flusher)
ScalarType getElementType() const
Definition: pvIntrospect.h:512
static std::size_t readSize(ByteBuffer *buffer, DeserializableControl *control)
Callback class for deserialization.
Definition: serialize.h:89
static const std::string DEFAULT_ID
Definition: pvIntrospect.h:873
virtual std::string getID() const OVERRIDE FINAL
Structure(StringArray const &fieldNames, FieldConstPtrArray const &fields, std::string const &id=defaultId())
std::ostream & operator<<(std::ostream &o, const Field &f)
Interface for in-line creating of introspection interfaces.
std::tr1::shared_ptr< FieldBuilder > FieldBuilderPtr
This class implements introspection object for bounded scalar array.
Definition: pvIntrospect.h:575
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const OVERRIDE
std::tr1::shared_ptr< const Scalar > ScalarConstPtr
Definition: pvIntrospect.h:150
BoundedScalarArray(ScalarType scalarType, std::size_t size)
Scalar(ScalarType scalarType)
UnionConstPtr createUnion(StringArray const &fieldNames, FieldConstPtrArray const &fields) const
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const OVERRIDE FINAL
This class implements introspection object for field.
Definition: pvIntrospect.h:336
virtual std::ostream & dump(std::ostream &o) const OVERRIDE FINAL
FieldConstPtr getField(std::string const &fieldName) const
#define MAX_SCALAR_TYPE
Definition: pvIntrospect.h:280
virtual std::tr1::shared_ptr< const Field > cachedDeserialize(ByteBuffer *buffer)=0
#define EPICS_THREAD_ONCE_INIT
Definition: epicsThread.h:109
virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control) OVERRIDE FINAL
virtual std::string getID() const OVERRIDE FINAL
UnionArray(UnionConstPtr const &_punion)
Type getType() const
Definition: pvIntrospect.h:348
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const OVERRIDE
std::tr1::shared_ptr< const Union > UnionConstPtr
Definition: pvIntrospect.h:170
FieldBuilderPtr addNestedUnionArray(std::string const &name)
std::tr1::shared_ptr< PVScalarArray > build() const
This class implements introspection object for a structure.
Definition: pvIntrospect.h:697
static unsigned hash(Field *fld)
FieldBuilderPtr addNestedStructure(std::string const &name)
StructureConstPtr appendFields(StructureConstPtr const &structure, StringArray const &fieldNames, FieldConstPtrArray const &fields) const
UnionArrayConstPtr createVariantUnionArray() const
APIs for the epicsMutex mutual exclusion semaphore.
LIBCOM_API void epicsStdCall epicsThreadOnce(epicsThreadOnceId *id, EPICSTHREADFUNC, void *arg)
std::size_t getFieldIndex(std::string const &fieldName) const
UnionConstPtr createVariantUnion() const
FieldBuilderPtr addFixedArray(std::string const &name, ScalarType scalarType, std::size_t size) PVD_DEPRECATED_52
bool compare(const Field &a, const Field &b)
Definition: Compare.cpp:26
ScalarConstPtr createScalar(ScalarType scalarType) const
std::tr1::shared_ptr< PVValueArray< std::tr1::shared_ptr< PVStructure > > > build() const
std::tr1::shared_ptr< const BoundedString > BoundedStringConstPtr
Definition: pvIntrospect.h:178
This class implements introspection object for Array.
Definition: pvIntrospect.h:462
FieldBuilderPtr addNestedUnion(std::string const &name)
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const OVERRIDE FINAL
EPICS_ALWAYS_INLINE void putByte(int8 value)
Definition: byteBuffer.h:525
This class implements a Bytebuffer that is like the java.nio.ByteBuffer.
Definition: byteBuffer.h:233
static void cache(const FieldCreate *create, std::tr1::shared_ptr< FLD > &ent)
StringArray const & getFieldNames() const
static const std::string & defaultId()
std::vector< FieldConstPtr > FieldConstPtrArray
Definition: pvIntrospect.h:146
UnionArrayConstPtr createUnionArray(UnionConstPtr const &punion) const
This class implements introspection object for BoundedString.
Definition: pvIntrospect.h:437
static void serializeString(const std::string &value, ByteBuffer *buffer, SerializableControl *flusher)
std::tr1::shared_ptr< PVField > build() const
This class implements introspection object for a unionArray.
Definition: pvIntrospect.h:652
virtual std::string getID() const OVERRIDE
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const OVERRIDE FINAL
std::tr1::shared_ptr< const Field > FieldConstPtr
Definition: pvIntrospect.h:137
BoundedStringConstPtr createBoundedString(std::size_t maxLength) const PVD_DEPRECATED_52
virtual std::string getID() const OVERRIDE FINAL
virtual void cachedSerialize(std::tr1::shared_ptr< const Field > const &field, ByteBuffer *buffer)=0
This is a singleton class for creating introspection interfaces.
FORCE_INLINE const FieldCreatePtr & getFieldCreate()
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const OVERRIDE FINAL
static size_t num_instances
Definition: pvIntrospect.h:340
void registerRefCounter(const char *name, const size_t *counter)
Definition: reftrack.cpp:59
std::tr1::shared_ptr< PVStructure > build() const
std::tr1::shared_ptr< const ScalarArray > ScalarArrayConstPtr
Definition: pvIntrospect.h:158
This class implements introspection object for scalar array.
Definition: pvIntrospect.h:497
virtual std::string getID() const OVERRIDE FINAL
This class implements introspection object for a structureArray.
Definition: pvIntrospect.h:607
ScalarArrayConstPtr createScalarArray(ScalarType elementType) const
FieldConstPtr getField(std::string const &fieldName) const
#define FLD(c, s, f)
UnionConstPtr getUnion() const
Definition: pvIntrospect.h:662
BoundedString(std::size_t maxStringLength)
std::vector< std::string > StringArray
Definition: pvType.h:110
FieldBuilderPtr setId(std::string const &id)
virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control) OVERRIDE FINAL
static const std::string ANY_ID
Definition: pvIntrospect.h:884
std::tr1::shared_ptr< FieldCreate > FieldCreatePtr
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const OVERRIDE FINAL
std::tr1::shared_ptr< PVScalar > build() const
virtual std::string getID() const OVERRIDE FINAL
This class implements introspection object for bounded scalar array.
Definition: pvIntrospect.h:543
std::size_t getMaximumLength() const
virtual void ensureBuffer(std::size_t size)=0
virtual std::ostream & dump(std::ostream &o) const OVERRIDE FINAL
friend class StructureArray
Definition: pvIntrospect.h:381
Callback class for serialization.
Definition: serialize.h:34
std::tr1::shared_ptr< PVValueArray< std::tr1::shared_ptr< PVUnion > > > build() const
friend class Structure
FieldConstPtrArray const & getFields() const
StructureConstPtr appendField(StructureConstPtr const &structure, std::string const &fieldName, FieldConstPtr const &field) const
virtual std::ostream & dump(std::ostream &o) const =0
virtual std::ostream & dump(std::ostream &o) const OVERRIDE FINAL
FieldBuilderPtr addNestedStructureArray(std::string const &name)
virtual void ensureData(std::size_t size)=0
ScalarArrayConstPtr createBoundedScalarArray(ScalarType elementType, std::size_t bound) const PVD_DEPRECATED_52
bool isVariant() const
C++ and C descriptions for a thread.
ScalarArrayConstPtr createFixedScalarArray(ScalarType elementType, std::size_t size) const PVD_DEPRECATED_52
virtual std::string getID() const OVERRIDE
FieldBuilderPtr add(std::string const &name, ScalarType scalarType)
virtual std::ostream & dump(std::ostream &o) const OVERRIDE FINAL
int32 guess(Type t, ScalarType s) const
FieldBuilderPtr createFieldBuilder() const
FieldBuilderPtr addBoundedString(std::string const &name, std::size_t maxLength) PVD_DEPRECATED_52
static const FieldCreatePtr & getFieldCreate()
static FieldBuilderPtr begin()
int32_t int32
Definition: pvType.h:83
FORCE_INLINE const PVDataCreatePtr & getPVDataCreate()
Definition: pvData.h:1648
static const std::string DEFAULT_ID
Definition: pvIntrospect.h:704
static const std::string & defaultId()
virtual std::ostream & dump(std::ostream &o) const OVERRIDE FINAL
FieldConstPtr deserialize(ByteBuffer *buffer, DeserializableControl *control) const
StringArray const & getFieldNames() const
Definition: pvIntrospect.h:828
std::tr1::shared_ptr< const UnionArray > UnionArrayConstPtr
Definition: pvIntrospect.h:174