237 Commits

Author SHA1 Message Date
Matej Sekoranja
72bf9f76a3 forgot to remove friend operator<< 2014-06-19 21:56:56 +02:00
Matej Sekoranja
c0c6213c7c Win32: friend incosistent linkage 2014-06-19 21:24:14 +02:00
Matej Sekoranja
652ef4bc82 merge 2014-06-19 14:29:05 +02:00
Matej Sekoranja
c6eed12139 String -> std::string, toString methods removed 2014-06-19 14:27:48 +02:00
Marty Kraimer
1132e25072 fix bug related to stride 2014-06-13 09:52:30 -04:00
Marty Kraimer
879e3a2b67 support UnionArray 2014-06-12 15:26:31 -04:00
Matej Sekoranja
6ec207141f fixed missing dllimport/dllexport on new code 2014-06-11 11:56:04 +02:00
Matej Sekoranja
45c657ce79 added missing src/copy/Makefile 2014-06-10 13:50:04 +02:00
Matej Sekoranja
888dc11c03 Added tag before_merge_changesAfter3_0_2 for changeset 40b681ffc5cd 2014-06-10 13:39:41 +02:00
Matej Sekoranja
5e3159f800 completed merge 2014-06-09 23:15:57 +02:00
Matej Sekoranja
570ec97eda flow: Closed <feature> 'changesAfter3_0_2'. 2014-06-09 22:53:59 +02:00
Matej Sekoranja
09c75823e6 byteBuffer: wrap support 2014-06-09 08:28:00 +02:00
Marty Kraimer
50c8c3b0bd more work on stride 2014-06-06 11:24:12 -04:00
Marty Kraimer
3fb44312c7 add support for stride 2014-06-05 10:20:01 -04:00
Matej Sekoranja
67bdf2ab8b bitSet <<operator(ostream) 2014-06-01 20:54:07 +02:00
Marty Kraimer
a56ed44e74 fix bugs found by tests in pvIOCJava 2014-05-24 06:47:16 -04:00
Marty Kraimer
3c912c3812 put to union field did not call postPut. 2014-05-21 16:18:38 -04:00
Matej Sekoranja
0ceb87eee1 Array IF added 2014-05-13 00:18:30 +02:00
Marty Kraimer
6510c10884 major update to pvDataCPP.html; minor updates while working on documentation 2014-05-01 10:33:01 -04:00
Andrew Johnson
89da38cfa4 Jenkins fixes.
Remove aps_build script, no longer used.
Tests have all been converted to the EPICS harness,
so don't need running separately.
2014-04-29 12:10:35 -05:00
Andrew Johnson
82b5d0e50b flow: Merged <feature> 'housekeeping' to <develop> ('default'). 2014-04-29 10:43:05 -05:00
Andrew Johnson
bb8789a9ad flow: Closed <feature> 'housekeeping'. 2014-04-29 10:43:05 -05:00
Marty Kraimer
20345ab0dd forgot monitor.h 2014-04-23 09:16:28 -04:00
Marty Kraimer
d5dfb3de0c added monitorPlugin; fixed bug in PVField::getFullName(); 2014-04-23 09:10:37 -04:00
Andrew Johnson
88aabb41e7 Replace USAGE_DEPRECATED with EPICS_DEPRECATED
Also make USAGE_ERROR conditional on the GCC version,
to remove warnings from VxWorks 6.8 builds.
2014-04-21 11:11:09 -05:00
Andrew Johnson
897059303d Merged changes from default branch 2014-04-18 16:55:13 -05:00
Andrew Johnson
0b7607cf04 Merged change from default branch. 2014-04-16 16:08:08 -05:00
Matej Sekoranja
4a512f47de merge 2014-04-09 15:19:43 +02:00
Matej Sekoranja
76a54d38e4 byteBuffer: wrapped buffer support 2014-04-09 15:18:40 +02:00
Matej Sekoranja
b9b03940a2 DefaultArray deserialize fix 2014-04-08 13:27:24 +02:00
Andrew Johnson
8370a97866 Unify configure files with the other V4 modules
Move include/pv setting into src/Makefile
2014-04-03 16:57:14 -05:00
Andrew Johnson
b659c77dbb Fix instructions in RELEASE file 2014-04-02 15:19:14 -05:00
Andrew Johnson
e45b842a6c Enable CHECK_RELEASE warnings 2014-04-02 14:43:32 -05:00
Marty Kraimer
c2f22a4ad8 make testPVCopy.cpp a proper epicsUnitTest 2014-04-02 10:15:53 -04:00
Marty Kraimer
cb15a8676b remove PVData methods that change introspection interface
remove deprecated methods
move CreateRequest from pvAccessCPP to pvDataCPP
move pvCopy from pvDatabaseCPP to pvDataCPP
2014-04-01 09:35:29 -04:00
Andrew Johnson
32ba6d444b Cleaned up CONFIG_SITE file.
Introduced WITH_COVERAGE Make variable
to control build options.
2014-03-31 17:25:22 -05:00
Andrew Johnson
95b7a04041 Makefile fixups 2014-03-28 11:53:39 -05:00
Andrew Johnson
d81ef64799 Remove __rtems__, already defined by the compiler 2014-03-28 11:20:03 -05:00
Andrew Johnson
19269735ae Rename pvDataApp to src, adjust Makefiles. 2014-03-28 10:20:24 -05:00
Matej Sekoranja
f7957c8ea5 merge 2014-03-28 00:04:18 +01:00
Andrew Johnson
1e40797bc4 Split pvDataApp/Makefile into fragments. 2014-03-27 17:58:43 -05:00
Andrew Johnson
ad66f8af73 Tidy up top-level Makefile 2014-03-27 17:36:10 -05:00
Andrew Johnson
d436e61bdb sharedPtr.h: Remove trailing ; from macro expansion. 2014-03-27 17:35:05 -05:00
Andrew Johnson
c71e62746d ParseToPOD needs limits.h on some arch's 2014-03-27 17:34:02 -05:00
Andrew Johnson
d5b0ad5d80 flow: Created branch 'feature/housekeeping'. 2014-03-27 17:28:55 -05:00
Marty Kraimer
34f2d7bc9a created feature branch 2014-03-25 07:23:14 -04:00
Marty Kraimer
fb7f1b622b flow: Created branch 'feature/changesAfter3_0_2'. 2014-03-25 07:04:59 -04:00
Marty Kraimer
4a992e6e1c flow initialization: Added configuration file. 2014-03-25 07:04:47 -04:00
Matej Sekoranja
9593de8c0f DefaultPVArray: removed unnecessary flush at the end of serialization 2014-02-17 12:47:07 +01:00
Matej Sekoranja
8205be5220 #63: implemented PVStructure.get<type>Field() using template method, no more messages emitted 2014-02-14 15:10:18 +01:00
Matej Sekoranja
39c43c4c02 rtems build: testProperty _HOST was missing 2014-02-06 11:58:14 +01:00
Matej Sekoranja
8a9fa956e0 vxWorks (vx68 and later): m_data -> m_sdata; m_data is a macro efined by vxWorks 2014-02-05 22:28:54 +01:00
Matej Sekoranja
06e9c533e3 parseToPOD RTEMS 2014-01-31 11:53:51 +01:00
Matej Sekoranja
5bdcaf43db sharedVector: count > capacity bugfix (2) 2013-12-04 10:49:16 +01:00
Matej Sekoranja
df1d13a155 sharedVector: count > capacity bugfix 2013-12-04 10:01:50 +01:00
Matej Sekoranja
6e7b19b090 added current_function.h 2013-12-03 12:16:08 +01:00
Matej Sekoranja
279b73a477 win32 port : warnings removed 2013-11-28 21:31:02 +01:00
Matej Sekoranja
74239303b3 testPVScalarArray: cast to the right type 2013-11-27 01:45:40 +01:00
Matej Sekoranja
134f390a5f fixed SerializeHelper::writeSize back 2013-11-27 01:37:16 +01:00
Matej Sekoranja
8aa26b78bb win32 port: parseToPOD NEED_LONGLONG check, missing monitor.cpp 2013-11-27 01:15:35 +01:00
Matej Sekoranja
301038664e win32 port: visibility, warnings, templates 2013-11-27 01:11:12 +01:00
Matej Sekoranja
ccad38f2db added programmers cookbook raw draft 2013-11-26 14:46:36 +01:00
Matej Sekoranja
29dee42d34 FieldBuilder: typo addNested() -> endNested() 2013-11-26 13:45:30 +01:00
Matej Sekoranja
f9135c81de testSerialization: fixed warnings 2013-11-26 11:08:16 +01:00
Matej Sekoranja
9400635fd9 testBitSet: replaced printf with testDiag 2013-11-25 22:07:28 +01:00
Marty Kraimer
4102deceb3 convert all tests to use epicsUnitTest 2013-11-25 15:46:00 -05:00
Matej Sekoranja
86306740be typeCast.cpp: do not report index in exception message for scalars 2013-11-22 10:31:21 +01:00
Matej Sekoranja
8e63fc8b25 castVtyped: added index in exeption error message 2013-11-22 09:44:21 +01:00
Matej Sekoranja
3219bd0307 Win32 port: import/export headers 2013-11-20 14:49:40 +01:00
Matej Sekoranja
bdb4430bb6 Win32 port: fix and success compile and run using GCC -fvisibility=hidden 2013-11-20 13:40:07 +01:00
Matej Sekoranja
a574dbf89b start of Win32 port 2013-11-20 13:04:28 +01:00
Matej Sekoranja
47178370d5 FieldBuilder: better method names 2013-11-11 22:36:06 +01:00
dhickin
ac67fddbcb Fixed bug in outputting UnionArrays. 2013-11-11 12:02:35 +00:00
dhickin
e97fab3107 Simpler fix for bug in outputting StructureArrays. 2013-11-08 18:49:57 +00:00
dhickin
fee6f03ec2 Fixed bug in outputting StructureArrays. 2013-11-08 18:27:15 +00:00
Matej Sekoranja
1aff2ec112 tempalte helpers; static initialization order 2013-11-08 13:50:54 +01:00
Matej Sekoranja
57b3e9a8b2 run EPICS Harness Tests on CI 2013-11-08 00:01:24 +01:00
Matej Sekoranja
35dad272eb merge 2013-11-07 14:13:37 +01:00
Matej Sekoranja
d40c41048d PVUnion/PVUnionArray support and tests 2013-11-07 14:12:26 +01:00
Marty Kraimer
03f59c94b4 commit after merge 2013-11-06 07:42:03 -05:00
Marty Kraimer
87718f1c82 get rid of warnings 2013-11-06 07:41:16 -05:00
Matej Sekoranja
cbf7b69ef0 Union/UnionArray implemented, PVUnion/PVUnionArray not yet implemented; also implemented reuse of scalar/scalarArray instances in FieldCreate 2013-11-05 16:15:12 +01:00
Matej Sekoranja
c56c976a22 FieldBuilder (incl. tests) 2013-11-04 19:04:28 +01:00
Marty Kraimer
3579d17a05 moved pvSubArrayCopy from pvDatabaseCPP to pvDataCPP 2013-10-31 06:44:54 -04:00
Marty Kraimer
0f17bd23c7 make bitSet more comnpatible with Java implementation. 2013-10-31 06:03:51 -04:00
Marty Kraimer
db10bed951 update documentation; fix bug in executor; add typedefs to thread.h 2013-10-30 08:13:19 -04:00
Michael Davidsaver
071806f12b remove redundancy in print_cast 2013-10-29 18:06:42 -04:00
Michael Davidsaver
9cd7008efe typeCast String <-> boolean 2013-10-29 17:56:36 -04:00
Michael Davidsaver
14dc098761 no deperecated warning on old vxworks 2013-10-29 16:58:09 -04:00
Michael Davidsaver
8c6a895b19 disambiguate a template 2013-10-29 16:54:02 -04:00
Michael Davidsaver
01b8e69e4b remove illegal copy op
Can bypass freeze/thaw
2013-10-28 17:54:59 -04:00
Michael Davidsaver
11e91ac3fa Merge branch 'shared-vector' 2013-10-28 17:42:11 -04:00
Marty Kraimer
70380b9a43 Added tag 3.0.2 for changeset 58092712d092 2013-09-10 16:54:02 -04:00
Marty Kraimer
fa7a44f5b3 update links in .html files 2013-09-10 16:53:21 -04:00
Andrew Johnson
fb0329c0b5 APS Jenkins adjustment 2013-09-05 12:24:38 -05:00
Andrew Johnson
c3d04fdd08 Fix VxWorks builds 2013-09-05 10:26:56 -05:00
Marty Kraimer
ebb0c97c51 Added tag 3.0.1 for changeset 2a289ff41e2e 2013-09-03 08:37:28 -04:00
Marty Kraimer
aabe0f3594 update links on .html files 2013-09-03 08:37:08 -04:00
dhickin
7c21bf7aa1 Added tag 3.0.0 for changeset 4cecd4b200f8 2013-08-21 12:03:42 +01:00
Michael Davidsaver
de70d90603 shared_vector: simplify slice()
Correctly tracks capacity when user
over-slices.
2013-08-06 11:32:34 -04:00
Michael Davidsaver
31be738c10 minor 2013-08-06 10:43:47 -04:00
Michael Davidsaver
759d268af0 update testPVScalarArray 2013-07-29 15:10:04 -04:00
Michael Davidsaver
f21811eb6a Change enum to type in converters 2013-07-29 15:09:47 -04:00
Michael Davidsaver
c643509c7e PVField converters use type
Use type as template parameter instead of ScalarType
enum value.
2013-07-29 15:08:59 -04:00
Michael Davidsaver
0860f8e6f9 don't use deprecated PVValueArray<T>::get() 2013-07-29 11:44:53 -04:00
Michael Davidsaver
e96b447e37 add print_cast()
Cast value to "printable" type.
A no-op except for char types, which are cast to int
so that they are printed as numbers std::ostream operators.
2013-07-29 11:44:52 -04:00
Michael Davidsaver
0eecd3b1fe document freeze/thaw 2013-07-29 11:44:52 -04:00
Michael Davidsaver
b5b6ae100d update pvD array in tests 2013-07-25 17:30:33 -04:00
Michael Davidsaver
8fd9bf10e5 update pvD array implementation 2013-07-25 17:30:18 -04:00
Michael Davidsaver
9ac030169a update pvD array handling
Interface only uses shared_vector<const T>
storage also uses only const.
2013-07-25 17:22:16 -04:00
Michael Davidsaver
569bd3b681 update testSharedVector 2013-07-25 17:02:08 -04:00
Michael Davidsaver
45bb461c32 shared_vector require freeze/thaw
Remove the implicit cast from non-const to const.
Require the use of freeze/thaw when
changing between const and non-const.

Change argument of const_shared_vector_cast
to a non-const shared_vector reference
to allow it to be cleared by freeze/thaw.
2013-07-25 15:26:29 -04:00
Michael Davidsaver
105c3185f7 remove take(), copyIn(), and copyOut(). 2013-07-19 14:20:55 -04:00
Michael Davidsaver
5565e4e30c Convert don't use copyIn or copyOut 2013-07-19 14:18:04 -04:00
Michael Davidsaver
70ae281f45 test freeze/thaw 2013-07-16 18:59:04 -04:00
Marty Kraimer
b518efd196 Added tag 3.0-pre1 for changeset 4cecd4b200f8 2013-07-16 14:47:34 -04:00
Michael Davidsaver
6e3a344caa fix Convert::fromStringArray
destination should grow to fit
2013-07-16 10:48:01 -04:00
Michael Davidsaver
2e3cbed520 restart testConvert
start with fromStringArray
2013-07-16 10:47:11 -04:00
Michael Davidsaver
5e2e7c81a6 Merge remote branch 'md/master' into pvarr
* md/master:
  added
  minor changes
  comparison between implementations
  Proposed pvData.h interface
  added pvArray.html; made queue.h and bitSetUtil.* compatible with pvDataCPP.
2013-07-09 18:37:53 -04:00
Michael Davidsaver
cff59487ae shared_vector freeze and thaw 2013-07-09 18:24:51 -04:00
Michael Davidsaver
cdcbfe7378 update testPVScalarArray 2013-07-09 18:24:51 -04:00
Michael Davidsaver
0c4ef8f079 PV* use shared_vector_convert 2013-07-09 18:24:50 -04:00
Michael Davidsaver
c0e9dcff21 revise static_shared_vector_cast
Move the work into a special ctor
to allow full inline of casting wrapper

Prevent static_shared_vector_cast from
casting const <-> non-const
2013-07-09 18:24:41 -04:00
Michael Davidsaver
79eeb0fa2a update PVScalar and PVScalarValue<T>
hide the void* members for now.

Define PVScalarValue<T>::getAs and putFrom
to give a more efficient implementation.
2013-07-09 18:24:41 -04:00
Michael Davidsaver
46feb86a99 test shared_vector_convert 2013-07-09 18:24:41 -04:00
Michael Davidsaver
74f68c47d3 shared_vector_convert
Allow converting of shared_vector between types

Conversion utilizes castUnsafe<TO,FROM>().

Converting to/from void is supported.  Convert to void
is an alias for static_shared_vector_cast<void>().
Convert from void utilizes shared_vector<void>::original_type()
and throws std::runtime_error if this is not valid.

Casting now handles 'const void'
is most places where 'void' can be used.
2013-07-09 18:24:40 -04:00
Michael Davidsaver
3c7a738ffc shared_vector<void> tracks original type 2013-07-09 18:24:40 -04:00
Michael Davidsaver
22d4a53d65 create templateMeta.h
Home for common C++ template tricks
2013-07-09 18:24:40 -04:00
Michael Davidsaver
d319e2ed7b add ScalarTypeID template
Define a compile time mapping from
type to ScalarType enum value.
2013-07-09 11:19:46 -04:00
Michael Davidsaver
2cb07a8490 move parts of ScalarTypeFunc to sharedVector.h
Move the parts of ScalarTypeFunc which
deal with untyped shared_vector s
to sharedVector.h to allow sharedVector.h
to include pvIntrospect.h w/o creating
an include loop...
2013-07-09 10:36:48 -04:00
Michael Davidsaver
6900d4bbec make boolean type unambiguous
"char", "signed char", and "unsigned char"
are distinct types.  Define "boolean" to
be whichever is not "int8" or "uint8".
2013-07-08 09:58:37 -04:00
Michael Davidsaver
73450bdbc7 combine shared_vector<T> for void and const void 2013-07-03 14:23:17 -04:00
Marty Kraimer
776ff49ed2 added 2013-07-03 12:11:05 -04:00
Michael Davidsaver
00da6c88ae minor 2013-07-03 11:41:53 -04:00
Michael Davidsaver
986f036d20 replace accepts const_svector
Allows

PVValueArray<T> *a, *b;

a->replace(b->view());
2013-07-03 11:34:32 -04:00
Michael Davidsaver
5699c43b74 correct max_size
Take into account sizeof(E).
2013-07-02 17:42:46 -04:00
Marty Kraimer
b58b97a916 minor changes 2013-06-28 14:17:23 -04:00
Marty Kraimer
5f52f14094 comparison between implementations 2013-06-25 12:18:38 -04:00
Ralph Lange
5f8fa26bf3 jenkins: Fix CloudBees hgweb job 2013-06-19 18:11:04 +02:00
Ralph Lange
a5c835cfeb jenkins: add CloudBees hgweb job to sync repo to SF webspace 2013-06-19 10:59:29 +02:00
Marty Kraimer
ec6b67ffad Proposed pvData.h interface 2013-06-18 10:01:52 -04:00
Marty Kraimer
3de28e3cef added pvArray.html; made queue.h and bitSetUtil.* compatible with pvDataCPP. 2013-06-13 14:52:27 -04:00
Andrew Johnson
d2a649f5fa Fixed compiler warning, 2013-06-12 21:21:44 -05:00
Michael Davidsaver
23d5aab1e8 add Doxyfile 2013-06-11 17:42:31 -04:00
Michael Davidsaver
cf8c6718dd test PVStructureArray in testSerialization 2013-06-11 17:42:30 -04:00
Michael Davidsaver
b0c8249562 re-write testPVStructureArray 2013-06-11 17:42:30 -04:00
Michael Davidsaver
8cb0b1a7d6 use new PVStructureArray api 2013-06-11 17:42:30 -04:00
Michael Davidsaver
7f9745c8d1 Implement PVStructureArray with shared_vector
Combine as much as possible with scalar array handling.

PVStructureArray becomes PVValueArray<shared_ptr<PVStructure> >

Bulk of shared implementation moved the PVVectorStorage
which has a parametrized base to avoid using multiple inheritance.
2013-06-11 17:42:30 -04:00
Michael Davidsaver
4e749cc8be Improve shared_vector::push_back
push_back now allocates additional space
in powers of 2 up to 1k elements, then
in blocks of 1k elements.
2013-06-11 17:42:30 -04:00
Michael Davidsaver
70c9a7c18f simplify shared_vector ctors
Casting will be done through the copy constructor.
2013-06-11 14:39:40 -04:00
Michael Davidsaver
11e2ee19ea Fix Printer for structure arrays
Not handling NULL elements correctly.
2013-06-11 14:39:40 -04:00
Michael Davidsaver
a4cfab1242 Fix "optimize shared_vector for storing non-POD types"
Can't move references when the source array is
still referenced by other shared_vectors
2013-06-11 14:39:40 -04:00
Michael Davidsaver
be4738f59c remove weak_vector
It seems that shared_ptr::use_count() does
not include weak_ptr instances.  Therefore
shared_ptr::use_count()==1 (aka unique())
does *not* ensure exclusive ownership!

This breaks the assumption used by
shared_vector::make_unique() to avoid
allocating a new array in some cases.
2013-06-10 15:09:42 -04:00
Michael Davidsaver
b63c3da565 add const_pointer to shared_vector 2013-06-10 12:09:29 -04:00
Michael Davidsaver
0b89f08d09 explicit copy and assignment for shared_vector
Add explicit copy constructor and
assignment operator for shared_vector.
2013-06-10 12:09:29 -04:00
Michael Davidsaver
ac53153bea shared_vector: test reference and const_reference
Ensure that these typedefs are present and work
for 'T' and 'const T'.
2013-06-05 16:15:49 -04:00
Michael Davidsaver
bc3187a3f6 optimize shared_vector for storing non-POD types
pass values by reference where appropriate.
When reallocating arrays of shared_ptr
"move" with swap() instead of operator=
to avoid ref counter inc and dec for each
element.
2013-06-03 19:31:05 -04:00
Michael Davidsaver
4294710d9e make viewUnsafe protected
No longer part of the public API of PVValueArray
2013-06-03 19:31:05 -04:00
Matej Sekoranja
476f18332a valueAlarm for numeric scalar arrays support 2013-05-31 21:15:54 +02:00
Michael Davidsaver
82a33460cf pvData update doc comments 2013-05-31 09:58:52 -04:00
Michael Davidsaver
3b6268a4fc add const_iterator to shared_vector 2013-05-31 09:58:52 -04:00
Michael Davidsaver
41425b3fa1 more testIntrospect 2013-05-31 09:58:52 -04:00
Andrew Johnson
a964e3668d Added jenkins/aps_build script 2013-05-30 17:32:15 -05:00
Michael Davidsaver
57804494ef Misc fixes and error checking
fix argument type for getScalarType
mark getFieldName as const
Argument checking for Field construction
2013-05-24 18:28:54 -04:00
Michael Davidsaver
9039a10c9a update testIntrospect with epicsUnitTest 2013-05-24 18:28:54 -04:00
Michael Davidsaver
9e865bc37d Avoid unnecessary copying in copyIn
Only re-use the existing reference if
it is large enough to hold all the new data.
If it isn't then throw it away to avoid
copying its current contents during
the resize().
2013-05-23 18:19:35 -04:00
Michael Davidsaver
54ee8bf7a0 PVStructureArray: setLength before postPut
Ensure that the correct (new) length is seen.
2013-05-23 17:51:52 -04:00
Michael Davidsaver
629c8346d2 postPut in new array API
Call when appropriate (putFrom(), copyIn(), and replace()).
Not called by swap(), take(), reuse(), or shareData().
Users of the second set of methods are expected to call
one of the methods in the first set, or call postPut() directly.

Document when postPut is (not) called.
2013-05-23 17:51:52 -04:00
Michael Davidsaver
1bf2ff430a array resize respect immutability 2013-05-23 17:51:52 -04:00
Marty Kraimer
69be072a07 added test 2013-05-17 19:33:16 -04:00
Marty Kraimer
a2ca21a1a6 changes to queue and to bitSetUtil. 2013-05-16 09:04:42 -04:00
Michael Davidsaver
572c02bf6e update testOperators 2013-05-08 18:35:51 -04:00
Michael Davidsaver
80777b293f rewrite testPVScalarArray 2013-05-08 18:35:51 -04:00
Michael Davidsaver
3c08834377 update testSerialization 2013-05-08 18:35:51 -04:00
Michael Davidsaver
eeae12e3d4 Convert: remove to/from*Array 2013-05-08 18:35:51 -04:00
Michael Davidsaver
992ac73068 use new API
make copying explicit and replace some
use of PVValueArray<T>::put and get
2013-05-08 18:35:51 -04:00
Michael Davidsaver
e843779555 New array API for PVValueArray using shared_vector<T>
* In PVScalarArray

Add methods assign, getAs/putFrom, and copyOut/copyIn to allow get/put
with implicit convert.

assign() copys on PVScalarArray to another converting as necessary.
If the types do not match then an allocate and convert is done.

getAs/putFrom work with shared_vector<T> and can avoid a allocate
and convert operation if the types match.

copyOut/copyIn use plain C arrays will do either a copy if the types
match, and a convert otherwise.  No allocation is performed.

* In PVValueArray<T>

All array operations re-implemented in terms of
two virtual methods

  virtual const shared_vector<T>& viewUnsafe() const;
  virtual void swap(shared_vector<T>&);

Some convienence methods are also included:

  shared_vector<const T> view() const
  shared_vector<T> take()
  shared_vector<T> reuse()

Deprecate get(...), put(...), and shareData(...)

Remove getVector() and getSharedVector()

Adjust DefaultPVArray accordingly
2013-05-08 18:35:51 -04:00
Michael Davidsaver
5f4ca240b4 add ScalarTypeFunc::elementSize 2013-05-08 18:35:50 -04:00
Michael Davidsaver
79cd374f16 add ScalarTypeFunc::allocArray 2013-05-08 18:35:50 -04:00
Michael Davidsaver
b137b32fc6 test shared_vector<T>
use epicsUnitTest
test handling of void and const void instances
2013-05-08 18:35:50 -04:00
Michael Davidsaver
3cd2bfdef0 shared_vector implementation
Shared ownership of a single C array.

Tracks offset and length for each instance
allowing each owner to "view" a different
piece of the array.

Parts of shared_vector<T> which can work
for T=void are in shared_vector_base<T>.
Specializations shared_vector<void>
and shared_vector<const void> handle
un-typed arrays.

Allow casting to/from typed vector

Offsets and sizes of untyped vectors are tracked in
bytes.  Therefore casting to types where sizeof(T)>1
is undefined if the offset is not a multiple of
sizeof(T).
2013-05-08 18:21:34 -04:00
Michael Davidsaver
461dbdf0f8 remove Convert pointer from PVField
Allow inline construction of Convert
2013-05-08 17:46:31 -04:00
Michael Davidsaver
9e8a6b6304 fix const-ness in PVField compare 2013-05-08 17:46:31 -04:00
Michael Davidsaver
fd5ea89340 typo 2013-05-01 14:27:00 -04:00
Michael Davidsaver
1d1d2b31cd remove remaining state from Convert 2013-05-01 14:20:01 -04:00
Michael Davidsaver
d75656dad7 testTypeCast use epicsUnitTest 2013-05-01 12:41:19 -04:00
Michael Davidsaver
f0aa2fe0e0 fix printer
Don't overflow the stack for deep structures!
2013-05-01 12:18:21 -04:00
Michael Davidsaver
ae847aea2b allow putFrom to implicitly resize 2013-05-01 12:18:21 -04:00
Michael Davidsaver
00ac5bf64f PVStructure::getNumberFields != Structure::getNumberFields
Apparently PVStructure::getNumberFields is one indexed???
2013-05-01 12:18:21 -04:00
Michael Davidsaver
61e8024c65 fix mapping between int* and epicsInt* types 2013-04-30 18:14:05 -04:00
Michael Davidsaver
ee5a370c01 misc 2013-04-30 18:14:05 -04:00
Michael Davidsaver
659ce13e98 replace vector to/from in Convert 2013-04-30 18:14:04 -04:00
Michael Davidsaver
a7fde21300 replace scalar to/from in Convert 2013-04-30 18:14:04 -04:00
Michael Davidsaver
a6bfab2d74 replace copyScalarArray with PVScalarArray::assign 2013-04-30 18:14:04 -04:00
Michael Davidsaver
e948af1851 PVScalar::assign and PVScalarArray::assign 2013-04-30 18:14:04 -04:00
Michael Davidsaver
2062cc5d10 Convert::toStringArray with castUnsafe 2013-04-30 18:14:02 -04:00
Michael Davidsaver
e85d10c6d9 Convert::fromStringArray with castUnsafe 2013-04-30 18:14:02 -04:00
Michael Davidsaver
0e0ab66d45 add PVScalarArray::getAs and PVScalarArray::putFrom 2013-04-30 18:14:02 -04:00
Michael Davidsaver
f2635c7fdc Convert::fromString with castUnsafe 2013-04-30 18:14:02 -04:00
Michael Davidsaver
4d92bbe541 Use PrinterPlain in Convert 2013-04-30 18:14:01 -04:00
Michael Davidsaver
e6e1434fc1 Add PrinterPlain 2013-04-30 18:13:32 -04:00
Michael Davidsaver
5e689f94f4 add PVScalar::getAs and PVScalar::putFrom
Allow get/put to a scalar without knowledge of ScalarType

Currently won't work correctly for PVBoolean
2013-04-26 15:44:05 -04:00
Michael Davidsaver
c1b6d26b8e Convert::equals: move to operator==(PVField&,PVField&) 2013-04-22 16:12:03 -04:00
Michael Davidsaver
f72c5dba84 PVStructure compare typo 2013-04-22 15:47:51 -04:00
Michael Davidsaver
704007092c Convert::getFullName becomes PVField::getFullName
Compatibility wrapper using current Convert API
Allow PVField::getFieldName to be inline'd
Avoid multiple resize and copy operations
on result String.
2013-04-22 14:48:59 -04:00
Michael Davidsaver
2f8c434429 add castUnsafeV
non-template version of castUnsafe<TO>(FROM v)).
2013-04-22 11:59:20 -04:00
Michael Davidsaver
b0c57e7ae3 test castUnsafe w/ transform() 2013-04-22 11:59:20 -04:00
Michael Davidsaver
0e57391b4d vxWorks compatibility 2013-04-22 11:59:20 -04:00
Michael Davidsaver
7ff1a93e72 parseToPOD: fix 64-bit
Try again to detect if uint16_t is long or long long.
2013-04-18 13:54:04 -04:00
Michael Davidsaver
d7eada7216 type casting with castUnsafe<TO>(FROM val) 2013-04-15 14:39:42 -04:00
Michael Davidsaver
c435f71592 testOperators: avoid warning 2013-04-15 14:34:45 -04:00
Matej Sekoranja
0dd6f01ef6 direct, i.e. no-copy, de/serialization support 2013-04-12 21:54:11 +02:00
Matej Sekoranja
cd95b75563 gcc 4.7+ compiler warnings removed 2013-02-27 11:44:00 +01:00
Ralph Lange
4122e772c1 merge SF changes 2013-02-26 17:22:16 +01:00
Ralph Lange
2fbe99909c documentation: update Doxyfile 2013-02-26 17:21:28 +01:00
Ralph Lange
d4f3d6209c jenkins: fix URLs for dependencies 2013-02-26 17:20:52 +01:00
Ralph Lange
641a51aa4f Fix .hgignore to use patterns 2013-02-26 17:20:28 +01:00
Matej Sekoranja
67afe84593 mb moved to pvCommonCPP 2013-02-25 10:29:34 +01:00
Matej Sekoranja
66f7c90c51 merge 2013-02-22 21:30:01 +01:00
Matej Sekoranja
959117c391 mb portability, still to be ported to boost atomic 2013-02-22 21:27:26 +01:00
5e810c704f Missing library reference in Makefile 2013-02-21 15:50:57 +01:00
Matej Sekoranja
675243061d -Wextra compiler warnings fixed 2013-02-16 12:50:36 +01:00
Matej Sekoranja
246825d672 base 3.14 fix 2013-02-13 14:29:38 +01:00
Matej Sekoranja
aa1a67d6c1 added micro-benchmark 2013-02-13 14:18:42 +01:00
Matej Sekoranja
97b1848ba3 added array_at manip test 2013-02-11 10:30:30 +01:00
Matej Sekoranja
c4f6132aca added simple operators 'test', added <<= >>= operators to PVScalar 2013-02-08 22:45:04 +01:00
Matej Sekoranja
a0de4f126f operator<< for all PVField, indent and array_at manipulator 2013-02-07 22:52:16 +01:00
Ralph Lange
a8a96def97 jenkins: Publish documentation to .../tip in CloudBees build 2013-01-18 15:19:37 +01:00
Ralph Lange
eaddc30def Add doxygen to Cloudbees build (as local dependency) 2013-01-14 12:22:15 +01:00
Ralph Lange
aa17639e20 Comment out doxygen (which does not work on CloudBees) 2013-01-13 18:32:09 +01:00
Ralph Lange
58d7ad494b Add doxygen run to jenkins build job 2013-01-13 18:20:43 +01:00
Ralph Lange
2895f48bd6 Add build script for Jenkins on Cloudbees 2013-01-13 18:11:55 +01:00
Ralph Lange
8f6ea47501 configure: improved generic RELEASE file 2013-01-11 19:12:50 +01:00
Marty Kraimer
3eb6237343 missing '.' in "This version" and "Previous version" 2012-12-12 15:25:18 -05:00
Marty Kraimer
cb19940fa7 I forget to do an hg add on documentation/pvDataCPP_20121212.html 2012-12-12 15:17:44 -05:00
Marty Kraimer
4bc7e9c8fe several minor problems found while developing pvDatabaseCPP 2012-12-12 14:59:33 -05:00
dhickin
18ba24156c Added tag 2.0-BETA for changeset d70c5ad29163 2012-11-22 15:23:15 +00:00
179 changed files with 38872 additions and 13921 deletions

8
.hgflow Normal file
View File

@@ -0,0 +1,8 @@
[branchname]
master = master
develop = default
feature = feature/
release = release/
hotfix = hotfix/
support = support/

View File

@@ -1,9 +1,12 @@
QtC-pvData.creator.user
bin
lib
doc
include
QtC-
bin/
lib/
doc/
include/
db/
dbd/
documentation/html
./O.*
configure/RELEASE.local
configure/CONFIG_SITE.local
documentation/*.tag
envPaths
configure/.*\.local
/O\..*

View File

@@ -4,3 +4,9 @@ d29d84f4c3f389f2accd497185b106c8541f95c9 1.1-SNAPSHOT
a29729ca0ecd60b66f2d997031d97911377e44a7 marchtest
9c59737f56e71aef641b70d0f72aa768fd7f8414 1.0.1-BETA
4559c3de0cb4e3420e26272817f58bab005063ec 1.1-BETA
d70c5ad29163306f50979a95b5aebbe9a93cfe76 2.0-BETA
4cecd4b200f88ab57bbb81978c45df2a67bbece1 3.0-pre1
4cecd4b200f88ab57bbb81978c45df2a67bbece1 3.0.0
2a289ff41e2ed3a0247877306c2db7b266f3b6b8 3.0.1
58092712d092ee521d1e1c8fa596a67f7d113ee9 3.0.2
40b681ffc5cd609320e3f8ffc8eb6aa3bfdfbf19 before_merge_changesAfter3_0_2

1694
Doxyfile

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,14 @@
#Makefile at top of application tree
# Makefile for the EPICS V4 pvData module
TOP = .
include $(TOP)/configure/CONFIG
DIRS += configure
DIRS += pvDataApp
pvDataApp_DEPEND_DIRS = configure
DIRS += src
src_DEPEND_DIRS = configure
DIRS += testApp
testApp_DEPEND_DIRS = pvDataApp
testApp_DEPEND_DIRS = src
include $(TOP)/configure/RULES_TOP

View File

@@ -1,30 +1,29 @@
# CONFIG
# CONFIG - Load build configuration data
#
# Do not make changes to this file!
# You might want to change this to some shared set of rules, e.g.
# RULES=/path/to/epics/support/modules/rules/x-y
RULES=$(EPICS_BASE)
# Allow user to override where the build rules come from
RULES = $(EPICS_BASE)
# RELEASE files point to other application tops
include $(TOP)/configure/RELEASE
-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH)
-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).Common
ifdef T_A
-include $(TOP)/configure/RELEASE.Common.$(T_A)
-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).$(T_A)
endif
CONFIG=$(RULES)/configure
CONFIG = $(RULES)/configure
include $(CONFIG)/CONFIG
# Override for definition in base
# Override the Base definition:
INSTALL_LOCATION = $(TOP)
include $(TOP)/configure/CONFIG_SITE
-include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH)
-include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).Common
# CONFIG_SITE files contain other build configuration settings
include $(TOP)/configure/CONFIG_SITE
-include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).Common
ifdef T_A
-include $(TOP)/configure/CONFIG_SITE.Common.$(T_A)
-include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A)
-include $(TOP)/configure/O.$(T_A)/CONFIG_APP_INCLUDE
endif

View File

@@ -1,36 +1,30 @@
# CONFIG_SITE
# Make any application-specific changes to the EPICS build
# configuration variables in this file.
# configuration variables in this file.
#
# Host/target specific settings can be specified in files named
# CONFIG_SITE.$(EPICS_HOST_ARCH).Common
# CONFIG_SITE.Common.$(T_A)
# CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A)
# CONFIG_SITE.$(EPICS_HOST_ARCH).Common
# CONFIG_SITE.Common.$(T_A)
# CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A)
# Set this when you only want to compile this application
# for a subset of the cross-compiled target architectures
# that Base is built for.
#CROSS_COMPILER_TARGET_ARCHS = vxWorks-68040
# CHECK_RELEASE controls the consistency checking of the support
# applications pointed to by the RELEASE* files.
# Normally CHECK_RELEASE should be set to YES.
# Set CHECK_RELEASE to NO to disable checking completely.
# Set CHECK_RELEASE to WARN to perform consistency checking but
# continue building anyway if conflicts are found.
CHECK_RELEASE = YES
# Set this when your IOC and the host use different paths
# to access the application. This will be needed to boot
# from a Microsoft FTP server or with some NFS mounts.
# You must rebuild in the iocBoot directory for this to
# take effect.
#IOCS_APPL_TOP = <path to application top as seen by IOC>
# To install files into a location other than $(TOP) define
# INSTALL_LOCATION here.
#INSTALL_LOCATION=</path/name/to/install/top>
# If you don't want to install into $(TOP) then
# define INSTALL_LOCATION here
#INSTALL_LOCATION=<fullpathname>
-include $(TOP)/configure/CONFIG_SITE.local
-include $(TOP)/../CONFIG.local
ifeq ($(EPICS_TEST_COVERAGE),1)
ifdef WITH_COVERAGE
USR_CPPFLAGS += --coverage
USR_LDFLAGS += --coverage
endif
INSTALL_INCLUDE = $(INSTALL_LOCATION)/include/pv
USR_INCLUDES += -I $(INSTALL_LOCATION)/include
-include $(TOP)/configure/CONFIG_SITE.local
-include $(TOP)/../CONFIG.local

View File

@@ -2,14 +2,6 @@ TOP=..
include $(TOP)/configure/CONFIG
# CHECK_RELEASE controls the consistency checking of the support
# applications defined in the $(TOP)/configure/RELEASE* files.
# Normally CHECK_RELEASE should be set to YES.
# Set CHECK_RELEASE to NO to disable checking completely.
# Set CHECK_RELEASE to WARN to perform consistency checking,
# but continue the build even if conflicts are found.
CHECK_RELEASE = YES
TARGETS = $(CONFIG_TARGETS)
CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS)))

View File

@@ -1,27 +1,25 @@
#RELEASE Location of external products
# pvDataCPP RELEASE - Location of external support modules
#
# IF YOU MAKE ANY CHANGES to this file you MUST at least run
# "gnumake" in this directory afterwards; you usually need
# to run "gnumake rebuild" in the application's top level
# directory each time this file is changed.
# IF YOU CHANGE this file or any file it includes you must
# subsequently do a "gnumake rebuild" in the application's
# top level directory.
#
# NOTE: The build does not check dependencies against files
# that are outside this application, thus you should run
# "gnumake distclean install" in the top directory each time
# EPICS_BASE, SNCSEQ, or any other external module defined
# in the RELEASE file is rebuilt.
# The build process does not check dependencies against files
# that are outside this application, thus you should also do a
# "gnumake rebuild" in the top level directory after EPICS_BASE
# or any other external module pointed to below is rebuilt.
#
# Host/target specific settings can be specified in files named
# Host- or target-specific settings can be given in files named
# RELEASE.$(EPICS_HOST_ARCH).Common
# RELEASE.Common.$(T_A)
# RELEASE.$(EPICS_HOST_ARCH).$(T_A)
TEMPLATE_TOP=$(EPICS_BASE)/templates/makeBaseApp/top
EPICS_BASE=/home/install/epics/base
# Create a file RELEASE.local containing the
# location of your EPICS_BASE, e.g.
# EPICS_BASE=/home/install/epics/base
# EPICS V4 Developers: Do not edit the locations in this file!
#
# Create a file RELEASE.local pointing to your PVCOMMON
# and EPICS_BASE build directories, e.g.
# PVCOMMON = /home/install/epicsV4/pvCommonCPP
# EPICS_BASE = /home/install/epics/base
-include $(TOP)/configure/RELEASE.local
-include $(TOP)/../RELEASE.local

1621
documentation/Doxyfile Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,47 @@
Release release/3.1 IN DEVELOPMENT
===========
The main changes since release 3.0.2 are:
* array semantics now enforce Copy On Write.
* union is new type.
* copy is new.
* monitorPlugin is new.
New Semantics for Arrays
--------
PVScalarArray, PVStructureArray, and PVUnionArray all enforce COW (Copy On Write) Semantics.
In order to limit memory usage the storage for raw data is managed via a new shared_vector facility.
This allows multiple instances of array data to use the shared raw data.
COW is implemented via shared_vectors of const data, i. e. data that can not be modified.
union is a new basic type.
------------
There are two new basic types: union_t and unionArray.
A union is like a structure that has a single subfield.
There are two flavors:
* <b>varient union</b> The field can have any type.
* <b>union</b> The field can any of specified set of types.
The field type can be dynamically changed.
copy
----
This consists of createRequest and pvCopy.
createRequest was moved from pvAccess to here.
pvCopy is moved from pvDatabaseCPP and now depends
only on pvData, i. e. it no longer has any knowledge of PVRecord.
monitorPlugin
-------------
This is for is for use by code that implements pvAccess monitors.
Release 3.0.2
==========
This was the starting point for RELEASE_NOTES

54
documentation/TODO.md Normal file
View File

@@ -0,0 +1,54 @@
TODO
===========
toString, dumpValue, printer, and streams
------------
The way to print introspection and data instances is not consistent.
This needs work.
Some items that need work are:
* Introspection has no support for streams. Only for toString.
* data has problems. toString is implemented by calling Convert::getString.
It look like this was intended to use printer but that did nor properly indent fields of structures.
The current implementation is:
void Convert::getString(StringBuilder buf,PVField const *pvField,int /*indentLevel*/)
{
// TODO indextLevel ignored
std::ostringstream strm;
strm << pvField->dumpValue(strm) << std::endl;
// PrinterPlain p;
// p.setStream(strm);
// p.print(*pvField);
strm.str().swap(*buf);
}
Thus it just uses dumpValue.
What should it do?
If printer is used it must do proper indentation.
doxygen
-------
There is a lot of public code that does not have doxygen tags.
monitorPlugin
-------------
A debate is on-going about what semantics should be.
PVFieldConstPtr etc
-------------------
In pvDataCPP.html look at the monoitorPlugin example.
It has a discussion of a possible need for shared pointers that can not be used to modify data.
This in addition to PVFieldPtr should PVFieldConstPtr exist.
But this means that all methods defined in pvDataCPP must be checked.
This is a BIG job.
Release 3.0.2
==========
This was the starting point for RELEASE_NOTES

View File

@@ -0,0 +1,679 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
<title>EPICS pvDataCPP: copy and monitor</title>
<link rel="stylesheet" type="text/css"
href="http://epics-pvdata.sourceforge.net/base.css" />
<link rel="stylesheet" type="text/css"
href="http://epics-pvdata.sourceforge.net/epicsv4.css" />
<style type="text/css">
/*<![CDATA[*/
.about { margin-left: 3em; margin-right: 3em; font-size: .83em}
table { margin-left: auto; margin-right: auto }
.diagram { text-align: center; margin: 2.5em 0 }
span.opt { color: grey }
span.nterm { font-style:italic }
span.term { font-family:courier }
span.user { font-family:courier }
span.user:before { content:"<" }
span.user:after { content:">" }
.nonnorm { font-style:italic }
p.ed { color: #AA0000 }
span.ed { color: #AA0000 }
p.ed.priv { display: inline; }
span.ed.priv { display: inline; }
/*]]>*/</style>
<!-- Script that generates the Table of Contents -->
<script type="text/javascript"
src="http://epics-pvdata.sourceforge.net/script/tocgen.js">
</script>
</head>
<body>
<div id="toc">
<h2 class="nocount" style="page-break-before: always">Table of Contents</h2>
</div>
<div id="contents" class="contents">
<h2>support for copy and monitor</h2>
<p><b>copy</b> and <b>monitor</b> are not used in this project.
They are intended for use by pvAccess and by pvAccess servers.
They are provided with this project because the code depends only on
pvData itself.
</p>
<p>This document describes C++ specific code.
<a href="http://epics-pvdata.sourceforge.net/informative/pvRequest.html">
pvRequest.html</a>
provides a language independent overview of <b>copy</b> and <b>monitor</b>.
</p>
<p>
<b>NOTE:pvRequest.html</b> must be updated since it is based on an earlier version of pvCopy that
had knowlege of PVRecord. The C++ version was implemented in pvDatabaseCPP
and the Java version on pvIOCJava.
At present only the C++ version of the new API for pvCopy is implemented.
</p>
<p>Copy provides:
<dl>
<dt>createRequest</dt>
<dd>
The Channel create methods in pvAccess all have an argument
<b>PVStructure pvRequest</b>.<br />
Given an ascii string createRequest creates a PVStructure that provides
a pvData representation of the information from the ascii string.
It is this structure that can be passed to the channel create methods.<br />
The information in a pvRequest selects an arbitrarary subset of the
fields in a top level structure that resides in the server.
In addition options can be specified. Both global and field specific
options can be specified.
</dd>
<dt>pvCopy</dt>
<dd>This is a faculity used by channel providers.
It provides client specific code that manages a copy of an arbitrary
subset of the fields in a top level structure that resides in the
provider. It also allows provider access to options specified
by the client.
</dd>
</dl>
Monitor provides:
<dl>
<dt>monitor</dt>
<dd>This is support code for channel providers that implement channel
monitor. It, together with the queue facility, provides support for
monitor queues.
</dd>
<dt>monitorPlugin</dt>
<dd>This is support for implementing monitor plugins.
A monitor plugin can be developed that has no knowledge
of pvAccess but only pvData.
</dd>
</dl>
</p>
<h2>support for copy</h2>
<p><b>copy</b> provides the ability to create a structure that has
a copy of an arbitrary subset of the fields in an existing top level
structure. In addition it allows global options and field specific options.
It has two main components: <b>createRequest</b> and <b>pvCopy</b>.
Given a string createRequest creates a pvRequest, which is a PVStructure
that has the format expected by <b>pvCopy</b>.
</p>
<h3>createRequest</h3>
<p>This is mainly used by pvAccess clients. Given a request string it creates
a pvRequest structure that can be passed to the pvAccess create methods.
In turn pvAccess passes the pvRequest to a local channel provider which
then passes it to pvCopy.
</p>
<p>The definition of the public members is:</p>
<pre>
class CreateRequest {
...
static CreateRequestPtr create();
virtual PVStructurePtr createRequest(std::string const &amp;request);
std::string getMessage();
};
</pre>
<p>An example of how it is used is:</p>
<pre>
CreateRequestPtr createRequest = CreateRequest::create();
PVStructurePtr pvRequest = createRequest-&gt;createRequest(request);
if(pvRequest==NULL) {
std::string error = createRequest-&gt;getMessage();
// take some action
} else {
//success do something
}
</pre>
<h3>pvCopy</h3>
<p>The definition of the public members is:</p>
<pre>
class epicsShareClass PVCopyTraverseMasterCallback
{
...
virtual void nextMasterPVField(PVFieldPtr const &amp;pvField);
};
class class epicsShareClass PVCopy
{
...
static PVCopyPtr create(
PVStructurePtr const &amp;pvMaster,
PVStructurePtr const &amp;pvRequest,
std::string const &amp; structureName);
PVStructurePtr getPVMaster();
void traverseMaster(PVCopyTraverseMasterCallbackPtr const &amp; callback);
StructureConstPtr getStructure();
PVStructurePtr createPVStructure();
size_t getCopyOffset(PVFieldPtr const &amp;masterPVField);
size_t getCopyOffset(
PVStructurePtr const &amp;masterPVStructure,
PVFieldPtr const &amp;masterPVField);
PVFieldPtr getMasterPVField(std::size_t structureOffset);
void initCopy(
PVStructurePtr const &amp;copyPVStructure,
BitSetPtr const &amp;bitSet);
void updateCopySetBitSet(
PVStructurePtr const &amp;copyPVStructure,
BitSetPtr const &amp;bitSet);
void updateCopyFromBitSet(
PVStructurePtr const &amp;copyPVStructure,
BitSetPtr const &amp;bitSet);
void updateMaster(
PVStructurePtr const &amp;copyPVStructure,
BitSetPtr const &amp;bitSet);
PVStructurePtr getOptions(std::size_t fieldOffset);
...
};
</pre>
where
<dl>
<dt>PVCopyTraverseMasterCallback::nextMasterPVField</dt>
<dd>
<b>PVCopyTraverseMasterCallback</b> is a callback which must
be implemented by the code that uses pvCopy, normally
the channel provider. It has the single method <b>nextMasterPVField</b>
<br />
<b>nextMasterPVField</b> is called for each field in the master
as a result of a call to <b>traverseMaster</b>.
</dd>
<dt>create</dt>
<dd>
This is the method for creating a PVCopy instance.<br/>
<dl>
<dt>pvMaster</dt>
<dd>the top level sructure managed by the server.</dd>
<dt>pvRequest</dt>
<dd>selects the set of subfields desired
and options for each field.</dd>
<dt>structureName</dt>
<dd>the name for the top level of any PVStructure created.
</dd>
</dl>
</dd>
<dt>getPVMaster</dt>
<dd>
Gets the top level structure from pvMaster.
</dd>
<dt>traverseMaster</dt>
<dd>
Traverse all fields of the top level structure of pvMaster.
For each field the callback is called.
</dd>
<dt>getStructure</dt>
<dd>
Get the introspection interface for a PVStructure for e copy.
</dd>
<dt>createPVStructure</dt>
<dd>Create a copy instance.
Monitors keep a queue of monitor elements.
Since each element needs a PVStructure, multiple top level structures
will be created.
</dd>
<dt>getCopyOffset</dt>
<dd>Given a field in pvMaster.
return the offset in copy for the same field.
A value of std::string::npos means that the copy does not have this field.
Two overloaded methods are provided. The first is called if
the field of master is not a structure. The second is for
subfields of a structure.
</dd>
<dt>getMasterPVField</dt>
<dd>
Given a offset in the copy get the corresponding field in pvMaster.
</dd>
<dt>initCopy</dt>
<dd>
Initialize the fields in copyPVStructure
by giving each field the value from the corresponding field in pvMaster.
bitSet will be set to show that all fields are changed.
This means that bit set will have the value <b>{0}</b>.
</dd>
<dt>updateCopySetBitSet</dt>
<dd>
Set all fields in copyPVStructure to the value of the corresponding field
in pvMaster. Each field that is changed has it's corresponding
bit set in bitSet.
</dd>
<dt>updateCopyFromBitSet</dt>
<dd>
For each set bit in bitSet set the field in copyPVStructure to the value
of the corrseponding field in pvMaster.
</dd>
<dt>updateMaster</dt>
<dd>
For each set bit in bitSet set the field in pvMaster to the value
of the corrseponding field in copyPVStructure.
</dd>
<dt>getOptions</dt>
<dd>
Get the options for the field at the specified offset.
A NULL is returned if no options were specified for the field.
If options were specified,PVStructurePtr is
a structure with a set of PVString subfields that specify name,value
pairs. name is the subField name and value is the subField value.
</dd>
</dl>
<h2>support for monitor</h2>
<p>This consists of two components:
<dl>
<dt>monitor</dt>
<dd>Used by code that implements pvAccess montors.</dd>
<dt>monitorPlugin</dt>
<dd>Code that provides special semantics for monitors.</dd>
</dl>
</p>
<h3>monitor</h3>
<pre>
class MonitorElement {
MonitorElement(PVStructurePtr const &amp; pvStructurePtr);
PVStructurePtr pvStructurePtr;
BitSetPtr changedBitSet;
BitSetPtr overrunBitSet;
};
class Monitor {
virtual Status start() = 0;
virtual Status stop() = 0;
virtual MonitorElementPtr poll() = 0;
virtual void release(MonitorElementPtr const &amp; monitorElement) = 0;
};
class MonitorRequester : public virtual Requester {
virtual void monitorConnect(Status const &amp; status,
MonitorPtr const &amp; monitor, StructureConstPtr const &amp; structure) = 0;
virtual void monitorEvent(MonitorPtr const &amp; monitor) = 0;
virtual void unlisten(MonitorPtr const &amp; monitor) = 0;
};
</pre>
<h4>monitorElement</h4>
<p><b>MonitorElement</b> holds the data for one element of a monitor queue.
It has the fields:
<dl>
<dt>pvStructurePtr</dt>
<dd>A top level structure with data values at the time the monitors occurs.</dd>
<dt>changedBitSet</dt>
<dd>Shows which fields have changed since the previous monitor.</dd>
<dt>overrunBitSet</dt>
<dd>Shows which fields have changed more han once since the previous monitor.</dd>
</dl>
</p>
<h4>monitorElement queue</h4>
<p>
A queue of monitor elements must be implemented by any channel provider that implements
<b>Channel::createMonitor</b>.
For an example implementation look at pvDatabaseCPP.
It has the following:
<pre>
typedef Queue&lt;MonitorElement&gt; MonitorElementQueue;
typedef std::tr1::shared_ptr&lt;MonitorElementQueue&gt; MonitorElementQueuePtr;
class MultipleElementQueue :
public ElementQueue
{
public:
POINTER_DEFINITIONS(MultipleElementQueue);
virtual ~MultipleElementQueue(){}
MultipleElementQueue(
MonitorLocalPtr const &amp;monitorLocal,
MonitorElementQueuePtr const &amp;queue,
size_t nfields);
virtual void destroy(){}
virtual Status start();
virtual Status stop();
virtual bool dataChanged();
virtual MonitorElementPtr poll();
virtual void release(MonitorElementPtr const &amp;monitorElement);
...
};
</pre>
<h4>Monitor</h4>
<p><b>Monitor</b> must be implemented by any channel provider that implements
<b>Channel::createMonitor</b>.
Remote PVAccess also implements Monitor on the client side.
Note that each client has it's own queue that is not shared with other client.
</p>
<p>Monitor has the following methods:</p>
<dl>
<dt>start</dt>
<dd>
Start monitoring.
This will result in a an inital monitor that has the current value
of all fields.
</dd>
<dt>stop</dt>
<dd>
Stop monitoring.
</dd>
<dt>poll</dt>
<dd>
Called to get a monitor element.
If no new elemants are available then a null pointer is returned.
</dd>
<dt>release</dt>
<dd>
Release the monotor element.
The caller owns the monitor element between the calls to poll and release.
</dd>
<dl>
</dl>
<h4>MonitorRequester</h4>
<p>This must be implemented by a pvAccess client.
It has the methods:</p>
<dl>
<dt>monitorConnect</dt>
<dd>
A monitor has either connected of disconnected.
</dd>
<dt>monitorEvent</dt>
<dd>
A new monitor element is available.
</dd>
<dt>unlisten</dt>
<dd>
The channel is going away. The client cam no longer access the monitor.
</dd>
</dl>
<h3>monitorPlugin</h3>
<pre>
class MonitorPlugin
{
virtual std::string const &amp; getName() = 0;
virtual bool causeMonitor(
PVFieldPtr const &amp;pvField,
PVStructurePtr const &amp;pvTop,
MonitorElementPtr const &amp;monitorElement) = 0;
virtual void monitorDone(
MonitorElementPtr const &amp;monitorElement);
virtual void startMonitoring();
virtual void stopMonitoring();
virtual void beginGroupPut();
virtual void endGroupPut();
};
class MonitorPluginCreator
{
virtual MonitorPluginPtr create(
FieldConstPtr const &amp;field,
StructureConstPtr const &amp;top,
PVStructurePtr const &amp;pvFieldOptions) = 0;
virtual std::string const &amp; getName() = 0;
}
class MonitorPluginManager
{
static MonitorPluginManagerPtr get();
bool addPlugin(
std::string const &amp;pluginName,
MonitorPluginCreatorPtr const &amp;creator);
MonitorPluginCreatorPtr findPlugin(std::string const &amp;pluginName);
void showNames();
};
</pre>
<h4>MonitorPlugin</h4>
<p><b>MonitorPlugin</b> must be implemented by the plugin implementation.
It has methods:</p>
<dl>
<dt>getName</dt>
<dd>Get the name of the plugin.</dd>
<dt>causeMonitor</dt>
<dd>
Should the value of pvField cause a monitor to be raised.
pvField and pvTop are fields in the top level structure
being monitored. monitorElement has the top level structure
for the copy</b>.
The implementation should <b>not</b> modify the fields in the structure
being monitored.
Called with pvTop locked.
</dd>
<dt>monitorDone</dt>
<dd>
Called just before monitorElement will be given to client.
The plugin can change the data values and bitSets in monitorElement.
Called with pvTop unlocked.
</dd>
<dt>startMonitoring</dt>
<dd>
Monitoring is starting.
</dd>
<dt>stopMonitoring</dt>
<dd>
Monitoring is being stopped.
</dd>
<dt>beginGroupPut</dt>
<dd>
A set of puts is starting.
Called with pvTop locked.
</dd>
<dt>endGroupPut</dt>
<dd>
The set of puts is complete.
Called with pvTop locked.
</dd>
</dl>
<h4>MonitorPluginCreator</h4>
<p><b>MonitorPluginCreator</b> must also be implemented by the plugin implementation.
It is called for each field instance that has options of the from
<b>[plugin=name...]</b> where <b>name</b> is the name of the plugin.
Note that a plugin instance will belong to a single client.
It has methods:</p>
<dl>
<dt>getName</dt>
<dd>Get the name of the plugin.</dd>
<dt>create</dt>
<dd>
Create a new plugin instance.
If the arguments are not compatible with the plugin a NULL shared pointer is
returned.<br/>
pvFieldOptions is
a structure with a set of PVString subfields that specify <b>name,value</b>
pairs. name is the subField name and value is the subField value.<br/>
Note that a plugin will below to a single client.
</dd>
<dl>
<h4>MonitorPluginManager</h4>
<p><b>MonitorPluginManager</b> has the methods:</p>
<dl>
<dt>get</dt>
<dd>
MonitorPluginManager is a singleton.
The first call to get will create the single instance.
Further calls will rerurn the single instance.
</dd>
<dt>addPlugin</dt>
<dd>
Add a new plugin.
</dd>
<dt>findPlugin</dt>
<dd>
Find a plugin. A NULL shared pointer is reurned if it has not been added.
</dd>
<dt>showNames</dt>
<dd>
Show the names of all puugins that have been added.
</dd>
</dl>
<p><b>NOTE:</b>
Should the method <b>causeMonitor</b>
have arguments <b>pvField</b> and <b>pvTop</b>
be defined so that they can not be modfied.
This would be posssible if the following was defined:
<pre>
typedef std::tr1::shared_ptr&lt;const PVField&gt; PVFieldConstPtr;
typedef std::tr1::shared_ptr&lt;const PVStructure&gt; PVStructureConstPtr;
</pre>
then the definition for causeMonitor could be:
<pre>
virtual bool causeMonitor(
PVFieldConstPtr const &amp;pvField,
PVStructureConstPtr const &amp;pvTop,
MonitorElementPtr const &amp;monitorElement) = 0;
</pre>
But just adding these definitions is not sufficent.
In addition all methods defined in pvDataCPP must be checked.
In particular many of the methods in <b>Convert</b> must have
their arguments modified.
Big job.
</p>
<h2>monitorPlugin example</h2>
<h3>Example Plugin Overview</h3>
<p>This section describes an example plugin that:</p>
<ul>
<li>Only raises monitors when a field changes value.<br />
If no plugin is provided
the default is to raise a monitor when a put is issued to a field.</li>
<li>Optionally a change will not raise a monitor.<br />
The change will, however,
appear if a put to another field raise a monitor.</li>
</ul>
<p>As an example assume that a channel provided by pvAccess has a top level structure
that represents a power supply.</p>
<pre>
structure powerSupply
structure alarm
structure timeStamp
structure power
double value
structure alarm
struvture display
structure voltage
double value
structure alarm
struvture display
structure current
double value
structure alarm
struvture display
</pre>
<p>A pvAccess client wants to create a monitor on the powerSupply as follows:
The client wants a top level structure that looks like:
<pre>
structure powerSupply
structure alarm
structure timeStamp
structure power
double value
structure voltage
double value
structure current
double value
</pre>
In addition the client wants monitors to occur only when one of the monitored
fields changes value but not just because a put occured.
Also if only the timeStamp changes value then that should not cause a monitor.
</p>
<p>The example monitor plugin implements the semantics the
client wants. It can be attached to any field via the following options:
<pre>
[plugin=onChange,raiseMonitor=value]
</pre>
This plugin will trigger a monitor for the field only if the field changes
value. In addition <b>value</b> equals <b>false</b> means do not raise a monotor
for changes to this field.
But if a change to another field does cause a monitor the change to this field
will be passed to the client.
</p>
<p>
Assume that the client has already connected to the channel.
The client can then issue the commands:</p>
<pre>
std::string request("field(alarm[plugin=onChange]");
request += ",timeStamp[plugin=onChange,raiseMonitor=false]";
request += ",power.value[plugin=onChange";
request += ",voltage.value[plugin=onChange";
request += ",current.value[plugin=onChange";
PVStructurePtr pvRequest = createRequest-&gt;createRequest(request);
MonitorPtr monitor = channel-&gt;createMonitor(monitorRequester,pvRequest);
</pre>
<h3>Example Plugin Code</h3>
<p>The header file to create the example has the definition:</p>
<pre>
class ExampleMonitorPlugin{
public:
static void create();
};
</pre>
<p>The implementation is:</p>
<pre>
class OnChangePlugin : public MonitorPlugin
{
public:
virtual ~OnChangePlugin(){}
OnChangePlugin() {}
bool init(
FieldConstPtr const &amp;field,
StructureConstPtr const &amp;top,
PVStructurePtr const &amp;pvFieldOptions)
{
pvField = getPVDataCreate()-&gt;createPVField(field);
raiseMonitor = true;
if(pvFieldOptions!=NULL) {
PVStringPtr pvString =
pvFieldOptions-&gt;getSubField&lt;PVString&gt;("raiseMonitor");
if(pvString!=NULL) {
std::string value = pvString-&gt;get();
if(value.compare("false")==0) raiseMonitor = false;
}
}
return true;
}
virtual std::string &amp;getName(){return pluginName;}
virtual bool causeMonitor(
PVFieldPtr const &amp;pvNew,
PVStructurePtr const &amp;pvTop,
MonitorElementPtr const &amp;monitorElement)
{
bool isSame = convert-&gt;equals(pvNew,pvField);
if(isSame) return false;
convert-&gt;copy(pvNew,pvField);
return raiseMonitor;
}
private:
PVFieldPtr pvField;
bool raiseMonitor;
};
class OnChangePluginCreator : public MonitorPluginCreator
{
public:
virtual std::string &amp;getName(){return pluginName;}
virtual MonitorPluginPtr create(
FieldConstPtr const &amp;field,
StructureConstPtr const &amp;top,
PVStructurePtr const &amp;pvFieldOptions)
{
OnChangePluginPtr plugin(new OnChangePlugin());
bool result = plugin-&gt;init(field,top,pvFieldOptions);
if(!result) return MonitorPluginPtr();
return plugin;
}
};
void ExampleMonitorPlugin::create()
{
static OnChangePluginCreatorPtr plugin;
static Mutex mutex;
Lock xx(mutex);
if(plugin==NULL) {
plugin = OnChangePluginCreatorPtr(new OnChangePluginCreator());
MonitorPluginManager::get()-&gt;addPlugin(pluginName,plugin);
}
}
</pre>
</div>
</body>
</html>

BIN
documentation/examples.zip Normal file

Binary file not shown.

1842
documentation/pvArray.html Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,179 @@
pvDataCPP cookbook
------------------
Creating introspection data interfaces
// create a scalar
getFieldCreate()->createScalar(pvDouble);
// create a scalar array
getFieldCreate()->createScalarArray(pvDouble);
// create a structure
getFieldCreate()->createFieldBuilder()->
setId("enum_t")->
add("index", pvDouble)->
addArray("choices", pvString)->
createStructure();
// create a structure (cntd.)
StructureConstPtr enum_t =
getFieldCreate()->createFieldBuilder()->
setId("enum_t")->
add("index", pvInt)->
addArray("choices", pvString)->
createStructure();
// create a structure (cntd.)
StructureConstPtr ntEnum =
getFieldCreate()->createFieldBuilder()->
setId("uri:ev4:nt/2012/pwd/NTEnum")->
add("value", enum_t)->
addNestedStructure("timeStamp")->
setId("time_t")->
add("secsPastEpoch", pvLong)->
add("nanoseconds", pvInt)->
add("userTag", pvInt)->
endNested()->
createStructure();
// create an union == same as structure
---
Creating data containers
// create a scalar
PVDouble::shared_pointer doubleValue = getPVDataCreate()->createPVScalar<PVDouble>();
// create a scalar array
PVDoubleArray::shared_pointer doubleArrayValue = getPVDataCreate()->createPVScalarArray<PVDouble>();
// create a structure
PVStructure::shared_pointer struct = getPVDataCreate()->createPVStructure(ntEnum);
// create an union
PVUnion::shared_pointer pvUnion = getPVDataCreate()->createPVUnion(unionIF);
// create a structure array
PVStructureArray::shared_pointer structArray = getPVDataCreate()->createPVStructureArray(ntEnum);
// scalar usage
PVInt::shared_pointer index = struct->getSubField<PVInt>("value.index");
int32 ix = index->get();
index->put(3);
std::cout << *index << std::endl;
// using <<=, >>= operators to get/set
*doubleValue <<= 12.3;
double val;
*doubleValue >>= val;
// array usage
PVStringArray::shared_pointer choices = struct->getSubField<PVStringArray>("value.choices");
// use view() to access read-only data
PVStringArray::const_svector data(choices->view());
for (std::size_t i = 0; i < data.size(); i++)
std::cout << data[i] << std::endl;
// use replace() to put new data
PVStringArray::svector newdata;
newdata.push_back("zero");
newdata.push_back("one");
newdata.push_back("two");
choices->replace(freeze(newdata));
// (add more use-cases) here
// print entire array
std::cout << *choices << std::endl;
// print elmenet at index == 1
std::cout << format::array_at(1) << *choices << std::endl;
----
Union handling
Union::const_shared_pointer punion =
getFieldCreate()->createFieldBuilder()->
add("doubleValue", pvDouble)->
add("intValue", pvInt)->
createUnion();
PVUnion::shared_pointer u = getPVDataCreate()->createPVUnion(punion);
// select and put
// this create a new instance of PVDouble (everytime select() is called)
PVDouble::shared_pointer doubleValue = u->select<PVDouble>("doubleValue");
doubeValue->put(12);
// select using index (and direct put)
u->select<PVDouble>(0)->put(12);
// select using existing PVField (PVUnion stores by-reference)
u->set("doubleValue", doubleValue);
// get selected field name or index
std::string selectedFN = u->getSelectedFieldName();
int32 selectedIndex = u->getSelectedIndex();
// get currently selected (knowing it's PVDouble)
PVDouble value = u->get<PVDouble>();
Variant Union handling
PVUnion::shared_pointer any = getPVDataCreate()->createPVVariantUnion();
PVDouble::shared_pointer doubleValue = getPVDataCreate()->createPVScalar<PVDouble>();
doubleValue->put(12.8);
any->set(doubleValue);
PVDouble::shared_pointer doubleValue2 = any->get<PVDouble>();
// variant union work by-reference (pointers match also)
// doubleValue.get() == doubleValue2.get()
------
Convert
// convert to int
int32 i = doubleValue->getAs<int32>();
// from int
doubleValue->putFrom<int32>(i);
// from string
doubleValue->putFrom<std::string>("12.3");
// from scalar field
doubleValue->assign(pvScalar);
// convert to int array
PVIntArray::const_svector intData;
doubleArrayValue->getAs<int32>(intData);
// from string array
PVStringArray::svector labels;
labels.push_back("zero");
labels.push_back("one");
labels.push_back("two");
doubleArrayValue->putFrom<std::string>(labels);
// from scalar array
doubleArrayValue->assign(pvScalarArray);

View File

@@ -42,11 +42,11 @@
<dl>
<dt>Latest version:</dt>
<dd><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDataCPP/raw-file/tip/documentation/pvDataCPP.html">pvDataCPP.html</a>
href="pvDataCPP.html">pvDataCPP.html</a>
</dd>
<dt>This version:</dt>
<dd><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDataCPP/raw-file/tip/documentation/pvDataCPP_20120927.html">pvDataCPP_20120927.html</a>
href="pvDataCPP_20120927.html">pvDataCPP_20120927.html</a>
</dd>
<dt>Previous version:</dt>
<dd>None.</dd>
@@ -65,33 +65,9 @@ license.</a></p>
<p>pvDataCPP is a computer software package for the efficient
storage, access, and communication, of structured data. It is specifically the
C++ implementation of pvData, which is one part of the set of related products in the EPICS
V4 control system programming environment:</p>
<dl>
<dt><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDataCPP/raw-file/tip/documentation/pvDataCPP.html">pvData</a></dt>
<dd>pvData (Process Variable Data) defines and implements an efficent way
to store, access, and communicate memory resident structured data</dd>
<dt><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvAccessCPP/raw-file/tip/documentation/pvAccessCPP.html">pvAccess</a></dt>
<dd>pvAccess is a software library for high speed controls network communications,
optimized for pvData</dd>
<dt><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvIOCCPP/raw-file/tip/documentation/pvIOCCPP.html">pvIOC</a></dt>
<dd>pvIOC is a software framework for building network accessable "smart" real time
databases, suitable for interfacing devices in a distributed control system,
that can exchange pvData over pvAccess.
</dd>
<dt><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvServiceCPP/raw-file/tip/documentation/pvAccessCPP.html">pvService</a></dt>
<dd>A middle layer for implementing efficient data services.</dd>
</dl>
<p>Each of these products has a Java and a C++ implementation.</p>
<p>The products are all part of the <a
href="http://epics-pvdata.sourceforge.net/">V4</a> implementation of <a
href="http://www.aps.anl.gov/epics/">Experimental Physics and Industrial
Control System (EPICS).</a></p>
V4 control system programming environment:<br />
<a href="http://epics-pvdata.sourceforge.net/relatedDocumentsV4.html">relatedDocumentsV4.html</a>
</p>
<h2 class="nocount">Status of this Document</h2>

View File

@@ -42,15 +42,15 @@
<dl>
<dt>Latest version:</dt>
<dd><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDataCPP/raw-file/tip/documentation/pvDataCPP.html">pvDataCPP.html</a>
href="pvDataCPP.html">pvDataCPP.html</a>
</dd>
<dt>This version:</dt>
<dd><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDataCPP/raw-file/tip/documentation/pvDataCPP_20121001.html">pvDataCPP_20121001.html</a>
href="pvDataCPP_20121001.html">pvDataCPP_20121001.html</a>
</dd>
<dt>Previous version:</dt>
<dd><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDataCPP/raw-file/tip/documentation/pvDataCPP_20120927.html">pvDataCPP_20120927.html</a>
href="pvDataCPP_20120927.html">pvDataCPP_20120927.html</a>
</dd>
<dt>Editors:</dt>
<dd>Marty Kraimer, BNL</dd>
@@ -67,33 +67,9 @@ license.</a></p>
<p>pvDataCPP is a computer software package for the efficient
storage, access, and communication, of structured data. It is specifically the
C++ implementation of pvData, which is one part of the set of related products in the EPICS
V4 control system programming environment:</p>
<dl>
<dt><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDataCPP/raw-file/tip/documentation/pvDataCPP.html">pvData</a></dt>
<dd>pvData (Process Variable Data) defines and implements an efficent way
to store, access, and communicate memory resident structured data</dd>
<dt><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvAccessCPP/raw-file/tip/documentation/pvAccessCPP.html">pvAccess</a></dt>
<dd>pvAccess is a software library for high speed controls network communications,
optimized for pvData</dd>
<dt><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvIOCCPP/raw-file/tip/documentation/pvIOCCPP.html">pvIOC</a></dt>
<dd>pvIOC is a software framework for building network accessable "smart" real time
databases, suitable for interfacing devices in a distributed control system,
that can exchange pvData over pvAccess.
</dd>
<dt><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvServiceCPP/raw-file/tip/documentation/pvAccessCPP.html">pvService</a></dt>
<dd>A middle layer for implementing efficient data services.</dd>
</dl>
<p>Each of these products has a Java and a C++ implementation.</p>
<p>The products are all part of the <a
href="http://epics-pvdata.sourceforge.net/">V4</a> implementation of <a
href="http://www.aps.anl.gov/epics/">Experimental Physics and Industrial
Control System (EPICS).</a></p>
V4 control system programming environment:<br />
<a href="http://epics-pvdata.sourceforge.net/relatedDocumentsV4.html">relatedDocumentsV4.html</a>
</p>
<h2 class="nocount">Status of this Document</h2>

View File

@@ -42,15 +42,15 @@
<dl>
<dt>Latest version:</dt>
<dd><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDataCPP/raw-file/tip/documentation/pvDataCPP.html">pvDataCPP.html</a>
href="pvDataCPP.html">pvDataCPP.html</a>
</dd>
<dt>This version:</dt>
<dd><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDataCPP/raw-file/tip/documentation/pvDataCPP_20121026html">pvDataCPP_20121026html</a>
href="pvDataCPP_20121026html">pvDataCPP_20121026html</a>
</dd>
<dt>Previous version:</dt>
<dd><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDataCPP/raw-file/tip/documentation/pvDataCPP_20121001.html">pvDataCPP_20121001.html</a>
href="pvDataCPP_20121001.html">pvDataCPP_20121001.html</a>
</dd>
<dt>Editors:</dt>
<dd>Marty Kraimer, BNL</dd>
@@ -67,33 +67,9 @@ license.</a></p>
<p>pvDataCPP is a computer software package for the efficient
storage, access, and communication, of structured data. It is specifically the
C++ implementation of pvData, which is one part of the set of related products in the EPICS
V4 control system programming environment:</p>
<dl>
<dt><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDataCPP/raw-file/tip/documentation/pvDataCPP.html">pvData</a></dt>
<dd>pvData (Process Variable Data) defines and implements an efficent way
to store, access, and communicate memory resident structured data</dd>
<dt><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvAccessCPP/raw-file/tip/documentation/pvAccessCPP.html">pvAccess</a></dt>
<dd>pvAccess is a software library for high speed controls network communications,
optimized for pvData</dd>
<dt><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvIOCCPP/raw-file/tip/documentation/pvIOCCPP.html">pvIOC</a></dt>
<dd>pvIOC is a software framework for building network accessable "smart" real time
databases, suitable for interfacing devices in a distributed control system,
that can exchange pvData over pvAccess.
</dd>
<dt><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvServiceCPP/raw-file/tip/documentation/pvAccessCPP.html">pvService</a></dt>
<dd>A middle layer for implementing efficient data services.</dd>
</dl>
<p>Each of these products has a Java and a C++ implementation.</p>
<p>The products are all part of the <a
href="http://epics-pvdata.sourceforge.net/">V4</a> implementation of <a
href="http://www.aps.anl.gov/epics/">Experimental Physics and Industrial
Control System (EPICS).</a></p>
V4 control system programming environment:<br />
<a href="http://epics-pvdata.sourceforge.net/relatedDocumentsV4.html">relatedDocumentsV4.html</a>
</p>
<h2 class="nocount">Status of this Document</h2>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,792 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
<title>EPICS pvDataDiscussion</title>
<link rel="stylesheet" type="text/css"
href="http://epics-pvdata.sourceforge.net/base.css" />
<link rel="stylesheet" type="text/css"
href="http://epics-pvdata.sourceforge.net/epicsv4.css" />
<style type="text/css">
/*<![CDATA[*/
.about { margin-left: 3em; margin-right: 3em; font-size: .83em}
table { margin-left: auto; margin-right: auto }
.diagram { text-align: center; margin: 2.5em 0 }
span.opt { color: grey }
span.nterm { font-style:italic }
span.term { font-family:courier }
span.user { font-family:courier }
span.user:before { content:"<" }
span.user:after { content:">" }
.nonnorm { font-style:italic }
p.ed { color: #AA0000 }
span.ed { color: #AA0000 }
p.ed.priv { display: inline; }
span.ed.priv { display: inline; }
/*]]>*/</style>
<!-- Script that generates the Table of Contents -->
<script type="text/javascript"
src="http://epics-pvdata.sourceforge.net/script/tocgen.js">
</script>
</head>
<body>
<div class="head">
<h1>EPICS pvDataDiscussion</h1>
<!-- Maturity: Working Draft or Request for Comments, or Recommendation, and date. -->
<h2 class="nocount">EPICS v4 Working Group, Working Draft, 03-Jul-2013</h2>
<dl>
<dt>Latest version:</dt>
<dd><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDataCPP/raw-file/tip/documentation/pvDataDiscussion.html">pvDataDiscussion.html</a>
</dd>
<dt>This version:</dt>
<dd>none</dd>
<dt>Previous version:</dt>
<dd>None</dd>
<dt>Editors:</dt>
<dd>Marty Kraimer, BNL<dd />
</dl>
<p class="copyright">This product is made available subject to acceptance of the <a
href="http://epics-pvdata.sourceforge.net/LICENSE.html">EPICS open source
license.</a></p>
<hr />
</div>
<div id="toc">
<h2 class="nocount" style="page-break-before: always">Table of Contents</h2>
</div>
<div id="contents" class="contents">
<h2>Introduction</h2>
<p>As pvDataCPP progressed PVField and derived classes accumulated
more and more member functions.
These member functions have nothing to do with the primary primary
purpose for pvData:
<blockquote>pvData (Process Variable Data) defines and implements an efficent
way to store, access, and communicate memory resident data structures.</blockquote>
This statement appears as the first sentence of pvDataJava.html.
A few sentances later the document makes it clear that communication
includes efficent network communication.
Thus pvData provides an interface for network accessible structured data.
The problem of adding member functions that have nothing to do with the primary purpose
started with the Java API.
It already had extra methods that solved problems that should have had a different solution.
This document removes the extra methods so that when new problems arise in the future
the solution will not involve adding new member functions to the introspection and data API.
</p>
<p>The introspection and data API for pvData should only encapuslate methods that support the primary purpose
stated above.
The interfaces for C++ and Java should be similar so that
someone who understands the interface in one of the languages
and knows both languages will quickly understand the interface of the other language.</p>
<p>There is another problem with the existing API. There are methods that allow the "structure"
to change after an pvData object is created. An example is PVField::renameField(std::string newName).
Such methods should not exist.</p>
<p>There are methods regarding immutability: setImmutable, isImmutablei, setCapacityMutable, and isCapacityMutable.
Should they exists? For now lets assume no.
</p>
<p>One last issue is the interface for array data. This document proposes a simplified
version of what currently exists. It requires that the implementation always provides storage for
the complete raw array. The existing APIs allow the implementation to provide the data in
"chunks". Giving up this requirement simplifies the array interfaces.
The existing C++ implementation of PVValueArray has serious problems.
The shared_vector that is implemented in pvDataCP-md provides the solution to fixing
the problems. This document describes an API that is very similar to the new Java API
except that raw arrays are replaced by shared_vector.</p>
<p>This document will first describe changes to the existing Java interfaces
and then the corresponding C++ API.</p>
<h2>Java API</h2>
<p>The following shows which methods will be removed from the existing interfaces
and what will be added.
The methods to be removed are in <font color = "red">red</font>
and methods to add are in <font color = "blue">blue</font>
Also the removed methods are at the end with a comment above.
The new methods also have a comment.
</p>
<h3>Introspection Interfaces</h3>
<pre>interface Field extends Serializable {
std::string getId();
Type getType();
// following will be removed
<font color = "red">void toString(StringBuilder buf);</font>
<font color = "red">void toString(StringBuilder buf,int indentLevel);</font>
<font color = "red">std::string toString();</font>
}
<font color = "blue">
// new interface
interface FieldTostd::string {
std::string toString(Field field);
}</font>
interface Scalar extends Field {
ScalarType getScalarType();
}
interface ScalarArray extends Field {
ScalarType getElementType();
}
interface Structure extends Field {
Field getField(std::string fieldName);
int getFieldIndex(std::string fieldName);
Field[] getFields();
Field getField(int fieldIndex);
std::string[] getFieldNames();
std::string getFieldName(int fieldIndex)
}
interface StructureArray extends Field {
Structure getStructure();
}
interface FieldCreate {
Scalar createScalar(ScalarType scalarType);
ScalarArray createScalarArray(ScalarType elementType);
StructureArray createStructureArray(Structure elementStructure);
Structure createStructure(std::string[] fieldNames, Field[] field);
Structure createStructure(std::string id,std::string[] fieldNames, Field[] field);
Structure createStructure(Structure structToClone);
Field deserialize(ByteBuffer buffer, DeserializableControl control);
// following will be removed
<font color = "red">Structure appendField(Structure structure,std::string fieldName, Field field);</font>
<font color = "red">Structure appendFields(Structure structure,std::string[] fieldNames, Field[] fields);</font>
}
</pre>
<h3>Data Interfaces</h3>
<pre>
interface PVField extends Requester, Serializable {
std::string getFieldName();
void setRequester(Requester requester);
int getFieldOffset();
int getNextFieldOffset();
int getNumberFields();
Field getField();
PVStructure getParent();
void postPut();
void setPostHandler(PostHandler postHandler);
// following will be removed
<font color = "red">PVAuxInfo getPVAuxInfo();</font>
<font color = "red">boolean isImmutable();</font>
<font color = "red">void setImmutable();</font>
<font color = "red">void renameField(std::string newName);</font>
<font color = "red">void toString(StringBuilder buf);</font>
<font color = "red">void toString(StringBuilder buf,int indentLevel);</font>
<font color = "red">std::string toString();</font>
}
<font color = "blue">
// The following is a new interface
interface PVFieldTostd::string {
std::string toString(PVField pvField);
void setMaxInitialArrayElements(int num);
void setMaxFinalArrayElements(int num);
int getMaxInitialArrayElements();
int getMaxFinalArrayElements();
}</font>
interface PVScalar extends PVField{
Scalar getScalar();
}
interface PVDouble extends PVScalar{
double get();
void put(double value);
}
// also PVBoolean, PVByte, PVShort, PVInt, PVLong, PVFloat, and PVString
interface PVArray extends PVField, SerializableArray {
int getLength();
void setLength(int length);
int getCapacity();
void setCapacity(int length);
// following will be removed
<font color = "red">boolean isCapacityMutable();</font>
<font color = "red">void setCapacityMutable(boolean isMutable);</font>
}
interface PVScalarArray extends PVArray {
ScalarArray getScalarArray();
}
<font color = "red">
//following will be removed
public class DoubleArrayData {
public double[] data;
public int offset;
}</font>
interface PVDoubleArray extends PVArray {
// following are new
<font color = "blue"> double[] get();</font>
<font color = "blue"> void swap(double[] value);</font>
//following will be removed
<font color = "red"> int get(int offset, int len, DoubleArrayData data);</font>
<font color = "red"> int put(int offset,int len, double[] from, int fromOffset)</font>;
<font color = "red"> void shareData(double[] from);</font>
}
// also PVBooleanArray, ..., PVStringArray
interface PVStructure extends PVField , BitSetSerializable{
Structure getStructure();
PVField[] getPVFields();
PVField getSubField(std::string fieldName);
PVField getSubField(int fieldOffset);
// The following are convenience methods
PVBoolean getBooleanField(std::string fieldName);
PVByte getByteField(std::string fieldName);
PVShort getShortField(std::string fieldName);
PVInt getIntField(std::string fieldName);
PVLong getLongField(std::string fieldName);
PVFloat getFloatField(std::string fieldName);
PVDouble getDoubleField(std::string fieldName);
PVString getStringField(std::string fieldName);
PVScalarArray getScalarArrayField(std::string fieldName);
PVStructureArray getStructureArrayField(std::string fieldName);
PVStructure getStructureField(std::string fieldName);
PVArray getArrayField(std::string fieldName,ScalarType elementType);
// following will be removed
<font color = "red"> void appendPVField(std::string fieldName,PVField pvField);</font>
<font color = "red"> void appendPVFields(std::string[] fieldNames,PVField[] pvFields);</font>
<font color = "red"> void removePVField(std::string fieldName);</font>
<font color = "red"> void replacePVField(PVField oldPVField,PVField newPVField);</font>
<font color = "red"> std::string getExtendsStructureName();</font>
<font color = "red"> boolean putExtendsStructureName(std::string extendsStructureName);</font>
<font color = "red"> public boolean checkValid();</font>
}
<font color = "red">
//following will be removed
public class StructureArrayData {
public PVStructure[] data;
public int offset;
}
</font>
interface PVStructureArray extends PVArray{
StructureArray getStructureArray();
// following are new
<font color = "blue"> PVStructure[] get();</font>
<font color = "blue"> void swap(PVStructure[] value);</font>
// following will be removed
<font color = "red"> int get(int offset, int length, StructureArrayData data);</font>
<font color = "red"> int put(int offset,int length, PVStructure[] from, int fromOffset);</font>
<font color = "red"> void shareData(PVStructure[] from);</font>
}
public interface PVDataCreate {
PVField createPVField(Field field);
PVField createPVField(PVField fieldToClone);
PVScalar createPVScalar(Scalar scalar);
PVScalar createPVScalar(ScalarType fieldType);
PVScalar createPVScalar(PVScalar scalarToClone);
PVScalarArray createPVScalarArray(ScalarArray array);
PVScalarArray createPVScalarArray(ScalarType elementType);
PVScalarArray createPVScalarArray(PVScalarArray arrayToClone;
PVStructureArray createPVStructureArray(StructureArray structureArray);
PVStructure createPVStructure(Structure structure);
PVStructure createPVStructure(std::string[] fieldNames,Field[] fields);
PVStructure createPVStructure(PVStructure structToClone);
// following will be removed
<font color = "red">PVField[] flattenPVStructure(PVStructure pvStructure);</font>
}
</pre>
<h3>PVFieldTostd::string</h3>
<p>In addition to toString this has methods to limit the number of array element to display.
The existing Java implementation of toString displayed all elements.
For large arrays this is not desirable.
The new methods provide a way for the client to limit the number of elements.
The default might be set to something like display up to 10 elements with 5 fron the beginning and 5 from the end.</p>
<p>For C++ this can be a replacement for dumpValue.</p>
<h3>PVBooleanArray, ..., PVStructureArray</h3>
<p>The old get and put are replaced by two new and simpler methods:
<dl>
<dt>get</dt>
<dd>Returns the raw array. If the client code modifies the elements in the array then
the client must call postPut. The client also has to realize that if the raw array held by the PVXXXArray changes
then the client is no longer sharing data
<dt>swap</dt>
<dd>This exchanges the old raw data with the new raw data.</dd>
</dl>
</p>
<p>
The method <b>setCapacity</b> will always create a new raw array and copy old data from the old to the new array.
This is not true now since the implementation does not create a new array if the old capacity is equal to the requested capacity.
</p>
<h2>C++ API</h2>
<p>The C++ class definitions are similar to the Java definitions with two main exceptions:
<dl>
<dt>toString</dt>
<dd>In c++ this is replaced by std::ostream.</dd>
<dt>raw array data</dt>
<dd>Java supports array data like <b>double[]</b>
The C++ replacement is shared_vector&lt;double&gt;, which is implemented
in pvDataCPP-md.</dd
</dl>
<h3>Introspection Interfaces</h3>
<pre>
class Field :
virtual public Serializable,
public std::tr1::enable_shared_from_this&lt;Field&gt;
{
public:
POINTER_DEFINITIONS(Field);
virtual ~Field();
Type getType() const{return m_type;}
virtual std::string getID() const = 0;
<font color = "red">
// following will be removed
virtual void toString(StringBuilder buf) const{toString(buf,0);}
virtual void toString(StringBuilder buf,int indentLevel) const;
</font>
...
};
<font color = "blue">
// new function
std::ostream &amp;toString(Field::const_reference field, std::ostream&amp; o);
</font>
class Scalar : public Field{
public:
POINTER_DEFINITIONS(Scalar);
virtual ~Scalar();
typedef Scalar&amp; reference;
typedef const Scalar&amp; const_reference;
ScalarType getScalarType() const {return scalarType;}
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
virtual void deserialize(ByteBuffer *buffer, DeserializableContol *control);
<font color = "red">
// following will be removed
virtual void toString(StringBuilder buf) const{toString(buf,0);}
virtual void toString(StringBuilder buf,int indentLevel) const;
virtual std::string getID() const;
</font>
...
};
class ScalarArray : public Field{
public:
POINTER_DEFINITIONS(ScalarArray);
typedef ScalarArray&amp; reference;
typedef const ScalarArray&amp; const_reference;
ScalarArray(ScalarType scalarType);
ScalarType getElementType() const {return elementType;}
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
<font color = "red">
// following will be removed
virtual void toString(StringBuilder buf) const{toString(buf,0);}
virtual void toString(StringBuilder buf,int indentLevel) const;
virtual std::string getID() const;
</font>
...
};
class Structure : public Field {
public:
POINTER_DEFINITIONS(Structure);
typedef Structure&amp; reference;
typedef const Structure&amp; const_reference;
std::size_t getNumberFields() const {return numberFields;}
FieldConstPtr getField(std::string const &amp; fieldName) const;
FieldConstPtr getField(std::size_t index) const;
std::size_t getFieldIndex(std::string const &amp;fieldName) const;
FieldConstPtrArray const &amp; getFields() const {return fields;}
StringArray const &amp; getFieldNames() const;
std::string getFieldName(std::size_t fieldIndex);
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
<font color = "red">
// following will be removed
void renameField(std::size_t fieldIndex,std::string const &amp;newName);
virtual void toString(StringBuilder buf,int indentLevel) const;
virtual std::string getID() const;
</font>
...
};
class StructureArray : public Field{
public:
POINTER_DEFINITIONS(StructureArray);
typedef StructureArray&amp; reference;
typedef const StructureArray&amp; const_reference;
StructureConstPtr getStructure() const {return pstructure;}
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
<font color = "red">
// following will be removed
virtual void toString(StringBuilder buf,int indentLevel=0) const;
virtual std::string getID() const;
</font>
...
};
class FieldCreate {
public:
static FieldCreatePtr getFieldCreate();
ScalarConstPtr createScalar(ScalarType scalarType) const
ScalarArrayConstPtr createScalarArray(ScalarType elementType) const;
StructureArrayConstPtr createStructureArray(StructureConstPtr const &amp; structure) const;
StructureConstPtr createStructure (
StringArray const &amp; fieldNames,
FieldConstPtrArray const &amp; fields) const;
StructureConstPtr createStructure (
std::string const &amp;id,
StringArray const &amp; fieldNames,
FieldConstPtrArray const &amp; fields) const;
FieldConstPtr deserialize(ByteBuffer* buffer, DeserializableControl* control) const;
<font color = "red">
// following will be removed
StructureConstPtr appendField(
StructureConstPtr const &amp; structure,
std::string const &amp;fieldName, FieldConstPtr const &amp; field) const;
StructureConstPtr appendFields(
StructureConstPtr const &amp; structure,
StringArray const &amp; fieldNames,
FieldConstPtrArray const &amp; fields) const;
</font>
...
};
extern FieldCreatePtr getFieldCreate();
</pre>
<h3>Data Interfaces</h3>
<pre>
class PVField
: virtual public Serializable,
public std::tr1::enable_shared_from_this&lt;PVField&gt;
{
public:
POINTER_DEFINITIONS(PVField);
virtual ~PVField();
inline const std::string &amp;getFieldName() const ;
virtual void setRequester(RequesterPtr const &amp;prequester);
std::size_t getFieldOffset() const;
std::size_t getNextFieldOffset() const;
std::size_t getNumberFields() const;
const FieldConstPtr &amp; getField() const ;
PVStructure * getParent() const
void postPut() ;
void setPostHandler(PostHandlerPtr const &amp;postHandler);
// following will be removed
<font color = "red">
virtual void message(std::string message,MessageType messageType);
void replacePVField(const PVFieldPtr&amp; newPVField);
std::string getFullName() const;
virtual bool equals(PVField &amp;pv);
PVAuxInfoPtr &amp; getPVAuxInfo()
bool isImmutable() const;
virtual void setImmutable();
void replacePVField(const PVFieldPtr&amp; newPVField);
void renameField(std::string const &amp;newName);
virtual void toString(StringBuilder buf) ;
virtual void toString(StringBuilder buf,int indentLevel);
std::ostream&amp; dumpValue(std::ostream&amp; o) const;
</font>
...
};
<font color = "blue">
// The following is a new class
class PVFieldTostd::string {
std::string toString(const PVFieldPtr &amp;pvField);
void setMaxInitialArrayElements(size_t num);
void setMaxFinalArrayElements(size_t num);
size_t getMaxInitialArrayElements();
size_t getMaxFinalArrayElements();
...
}</font>
class PVScalar : public PVField {
public:
POINTER_DEFINITIONS(PVScalar);
virtual ~PVScalar();
typedef PVScalar &amp;reference;
typedef const PVScalar&amp; const_reference;
const ScalarConstPtr getScalar() const ;
...
}
template&lt;typename T&gt;
class PVScalarValue : public PVScalar {
public:
POINTER_DEFINITIONS(PVScalarValue);
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
virtual ~PVScalarValue() {}
virtual T get() const = 0;
virtual void put(T value) = 0;
<font color = "red">
// following will be removed
std::ostream&amp; dumpValue(std::ostream&amp; o)
void operator&gt;&gt;=(T&amp; value) const;
void operator&lt;&lt;=(T value);
</font>
...
}
// PVString is special case, since it implements SerializableArray
class PVString : public PVScalarValue&lt;std::string&gt;, SerializableArray {
public:
virtual ~PVString() {}
...
}
class PVArray : public PVField, public SerializableArray {
public:
POINTER_DEFINITIONS(PVArray);
virtual ~PVArray();
std::size_t getLength() const;
virtual void setLength(std::size_t length);
std::size_t getCapacity() const;
virtual void setCapacity(std::size_t capacity) = 0;
<font color = "red">
// following will be removed
virtual void setImmutable();
bool isCapacityMutable() const;
void setCapacityMutable(bool isMutable);
virtual std::ostream&amp; dumpValue(std::ostream&amp; o, std::size_t index) const = 0;
</font>
...
};
class PVScalarArray : public PVArray {
public:
POINTER_DEFINITIONS(PVScalarArray);
virtual ~PVScalarArray();
typedef PVScalarArray &amp;reference;
typedef const PVScalarArray&amp; const_reference;
const ScalarArrayConstPtr getScalarArray() const ;
<font color = "red">
// following will be removed
virtual std::ostream&amp; dumpValue(std::ostream&amp; o, size_t index) const = 0;
</font>
...
}
<font color = "red">
// following will be removed
template&lt;typename T&gt;
class PVArrayData {
private:
std::vector&lt;T&gt; init;
public:
POINTER_DEFINITIONS(PVArrayData);
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
std::vector&lt;T&gt; &amp; data;
std::size_t offset;
PVArrayData()
: data(init)
{}
};
</font>
template&lt;typename T&gt;
class PVValueArray : public PVScalarArray {
public:
POINTER_DEFINITIONS(PVValueArray);
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
// following are new typeDefs
<font color = "blue">typedef shared_vector&lt;T&gt; svector;</font>
<font color = "blue">typedef shared_vector&lt;const T&gt; const_svector; </font>
virtual ~PVValueArray() {}
// following are added
<font color = "blue">svector get();</font>
<font color = "blue">void swap(svector&amp; value);</font>
<font color = "red">
// following are removed
typedef PVValueArray &amp; reference;
typedef const PVValueArray &amp; const_reference;
typedef PVArrayData&lt;T&gt; ArrayDataType;
typedef std::vector&lt;T&gt; vector;
typedef const std::vector&lt;T&gt; const_vector;
typedef std::tr1::shared_ptr&lt;vector&gt; shared_vector;
virtual std::size_t get(
std::size_t offset, std::size_t length, ArrayDataType &amp;data) = 0;
virtual std::size_t put(std::size_t offset,
std::size_t length, const_pointer from, std::size_t fromOffset) = 0;
virtual std::size_t put(std::size_t offset,
std::size_t length, const_vector &amp;from, std::size_t fromOffset);
virtual void shareData(
shared_vector const &amp; value,
std::size_t capacity,
std::size_t length) = 0;
virtual pointer get() = 0;
virtual pointer get() const = 0;
virtual vector const &amp; getVector() = 0;
virtual shared_vector const &amp; getSharedVector() = 0;
std::ostream&amp; dumpValue(std::ostream&amp; o) const;
std::ostream&amp; dumpValue(std::ostream&amp; o, size_t index) const;
</font>
...
};
typedef PVValueArray&lt;uint8&gt; PVBooleanArray;
typedef std::tr1::shared_ptr&lt;PVBooleanArray&gt; PVBooleanArrayPtr;
...
typedef PVValueArray&lt;std::string&gt; PVStringArray;
typedef std::tr1::shared_ptr&lt;PVStringArray&gt; PVStringArrayPtr;
class PVStructure : public PVField,public BitSetSerializable {
public:
POINTER_DEFINITIONS(PVStructure);
virtual ~PVStructure();
typedef PVStructure &amp; reference;
typedef const PVStructure &amp; const_reference;
StructureConstPtr getStructure() const;
const PVFieldPtrArray &amp; getPVFields() const;
PVFieldPtr getSubField(std::string const &amp;fieldName) const;
PVFieldPtr getSubField(std::size_t fieldOffset) const;
PVBooleanPtr getBooleanField(std::string const &amp;fieldName) ;
PVBytePtr getByteField(std::string const &amp;fieldName) ;
PVShortPtr getShortField(std::string const &amp;fieldName) ;
PVIntPtr getIntField(std::string const &amp;fieldName) ;
PVLongPtr getLongField(std::string const &amp;fieldName) ;
PVUBytePtr getUByteField(std::string const &amp;fieldName) ;
PVUShortPtr getUShortField(std::string const &amp;fieldName) ;
PVUIntPtr getUIntField(std::string const &amp;fieldName) ;
PVULongPtr getULongField(std::string const &amp;fieldName) ;
PVFloatPtr getFloatField(std::string const &amp;fieldName) ;
PVDoublePtr getDoubleField(std::string const &amp;fieldName) ;
PVStringPtr getStringField(std::string const &amp;fieldName) ;
PVStructurePtr getStructureField(std::string const &amp;fieldName) ;
PVScalarArrayPtr getScalarArrayField(
std::string const &amp;fieldName,ScalarType elementType) ;
PVStructureArrayPtr getStructureArrayField(std::string const &amp;fieldName) ;
virtual void serialize(
ByteBuffer *pbuffer,SerializableControl *pflusher) const ;
virtual void deserialize(
ByteBuffer *pbuffer,DeserializableControl *pflusher);
virtual void serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher,BitSet *pbitSet) const;
virtual void deserialize(ByteBuffer *pbuffer,
DeserializableControl*pflusher,BitSet *pbitSet);
PVStructure(StructureConstPtr const &amp; structure);
PVStructure(StructureConstPtr const &amp; structure,PVFieldPtrArray const &amp; pvFields);
<font color = "red">
// following are removed
void appendPVField(
std::string const &amp;fieldName,
PVFieldPtr const &amp; pvField);
void appendPVFields(
StringArray const &amp; fieldNames,
PVFieldPtrArray const &amp; pvFields);
void removePVField(std::string const &amp;fieldName);
virtual void setImmutable();
std::string getExtendsStructureName() const;
bool putExtendsStructureName(
std::string const &amp;extendsStructureName);
</font>
};
<font color = "red">
// following will be removed
typedef PVArrayData&lt;PVStructurePtr&gt; StructureArrayData;
</font>
class PVStructureArray : public PVArray
{
public:
POINTER_DEFINITIONS(PVStructureArray);
typedef PVStructurePtr value_type;
typedef PVStructurePtr* pointer;
typedef const PVStructurePtr* const_pointer;
<font color = "blue">
// following are new typeDefs
typedef shared_vector&lt;PVStructurePtr&gt; svector;
typedef shared_vector&lt;const PVStructurePtr&gt; const_svector;
</font>
virtual ~PVStructureArray() {}
virtual void setCapacity(size_t capacity);
virtual void setLength(std::size_t length);
virtual StructureArrayConstPtr getStructureArray() const ;
virtual void serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher) const;
virtual void deserialize(ByteBuffer *buffer,
virtual void serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher, std::size_t offset, std::size_t count) const ;
// following are new
<font color = "blue"> svector get();</font>
<font color = "blue"> void swap(svector &amp; value);</font>
<font color = "red">
// following are removed
typedef PVArrayData&lt;PVStructurePtr&gt; ArrayDataType;
typedef std::vector&lt;PVStructurePtr&gt; vector;
typedef const std::vector&lt;PVStructurePtr&gt; const_vector;
typedef std::tr1::shared_ptr&lt;vector&gt; shared_vector;
typedef PVStructureArray &amp;reference;
typedef const PVStructureArray&amp; const_reference;
virtual std::size_t append(std::size_t number);
virtual bool remove(std::size_t offset,std::size_t number);
virtual void compress();
virtual std::size_t get(std::size_t offset, std::size_t length,
StructureArrayData &amp;data);
virtual std::size_t put(std::size_t offset,std::size_t length,
const_vector const &amp; from, std::size_t fromOffset);
virtual void shareData(
shared_vector const &amp; value,
std::size_t capacity,
std::size_t length);
virtual pointer get() { return &amp;((*value.get())[0]); }
virtual pointer get() const { return &amp;((*value.get())[0]); }
virtual vector const &amp; getVector() {return *value;}
virtual shared_vector const &amp; getSharedVector() {return value;}
</font>
...
};
class PVDataCreate {
public:
static PVDataCreatePtr getPVDataCreate();
PVFieldPtr createPVField(FieldConstPtr const &amp; field);
PVFieldPtr createPVField(PVFieldPtr const &amp; fieldToClone);
PVScalarPtr createPVScalar(ScalarConstPtr const &amp; scalar);
PVScalarPtr createPVScalar(ScalarType scalarType);
PVScalarPtr createPVScalar(PVScalarPtr const &amp; scalarToClone);
PVScalarArrayPtr createPVScalarArray(ScalarArrayConstPtr const &amp; scalarArray);
PVScalarArrayPtr createPVScalarArray(ScalarType elementType);
PVScalarArrayPtr createPVScalarArray(PVScalarArrayPtr const &amp; scalarArrayToClone);
PVStructureArrayPtr createPVStructureArray(StructureArrayConstPtr const &amp; structureArray);
PVStructurePtr createPVStructure(StructureConstPtr const &amp; structure);
PVStructurePtr createPVStructure(
StringArray const &amp; fieldNames,PVFieldPtrArray const &amp; pvFields);
PVStructurePtr createPVStructure(PVStructurePtr const &amp; structToClone);
...
};
extern PVDataCreatePtr getPVDataCreate();
</pre>
</div>
</body>
</html>

56
jenkins/cloudbees_build Normal file
View File

@@ -0,0 +1,56 @@
# pvData C++ implementation
# Jenkins @ Cloudbees build script
#
# Jenkins invokes scripts with the "-ex" option. So the build is considered a failure
# if any of the commands exits with a non-zero exit code.
#
# Author: Ralph Lange <Ralph.Lange@gmx.de>
# Copyright (C) 2013 Helmholtz-Zentrum Berlin für Materialien und Energie GmbH
# All rights reserved. Use is subject to license terms.
###########################################
# Fetch and unpack dependencies
export STUFF=/tmp/stuff
rm -fr ${STUFF}
mkdir -p ${STUFF}
cd ${STUFF}
wget -nv https://openepics.ci.cloudbees.com/job/Base-3.14.12.3_Build/lastSuccessfulBuild/artifact/baseR3.14.12.3.CB-dist.tar.gz
wget -nv https://openepics.ci.cloudbees.com/job/Doxygen-1.8.3_Build/lastSuccessfulBuild/artifact/doxygen-1.8.3.CB-dist.tar.gz
tar -xzf baseR3.14.12.3.CB-dist.tar.gz
tar -xzf doxygen-1.8.3.CB-dist.tar.gz
###########################################
# Build
cd ${WORKSPACE}
export EPICS_BASE=${STUFF}
export EPICS_HOST_ARCH=$(${EPICS_BASE}/startup/EpicsHostArch)
export LD_LIBRARY_PATH=${EPICS_BASE}/lib/${EPICS_HOST_ARCH}
export PATH=${STUFF}/bin:${PATH}
cat > configure/RELEASE.local << EOF
EPICS_BASE=${EPICS_BASE}
EOF
make distclean all
doxygen
###########################################
# Test
# EPICS Test Harness tests
make runtests
###########################################
# Create distribution
tar czf pvData.CB-dist.tar.gz lib include COPYRIGHT LICENSE
###########################################
# Publish documentation
rsync -aP --delete -e ssh documentation epics-jenkins@web.sourceforge.net:/home/project-web/epics-pvdata/htdocs/docbuild/pvDataCPP/tip

20
jenkins/cloudbees_hgweb Normal file
View File

@@ -0,0 +1,20 @@
# pvData C++ implementation
# Jenkins @ Cloudbees hgweb sync script
#
# Jenkins invokes scripts with the "-ex" option. So the build is considered a failure
# if any of the commands exits with a non-zero exit code.
#
# Author: Ralph Lange <Ralph.Lange@gmx.de>
# Copyright (C) 2013 Helmholtz-Zentrum Berlin für Materialien und Energie GmbH
# All rights reserved. Use is subject to license terms.
###########################################
# Fetch complete repo
rm -fr hgweb
hg clone -U http://hg.code.sf.net/p/epics-pvdata/pvDataCPP hgweb
###########################################
# Sync into SF webspace
rsync -aqP --delete --exclude=\.hg/hgrc -e ssh hgweb/.hg epics-jenkins@web.sourceforge.net:/home/project-web/epics-pvdata/repos/pvDataCPP

View File

@@ -1,101 +0,0 @@
TOP = ..
include $(TOP)/configure/CONFIG
PVDATA = $(TOP)/pvDataApp/
SRC_DIRS += $(PVDATA)/misc
INC += noDefaultMethods.h
INC += lock.h
INC += requester.h
INC += serialize.h
INC += bitSet.h
INC += byteBuffer.h
INC += epicsException.h
INC += serializeHelper.h
INC += event.h
INC += thread.h
INC += executor.h
INC += timeFunction.h
INC += timer.h
INC += queue.h
INC += messageQueue.h
INC += destroyable.h
INC += status.h
INC += sharedPtr.h
INC += localStaticLock.h
LIBSRCS += byteBuffer.cpp
LIBSRCS += bitSet.cpp
LIBSRCS += epicsException.cpp
LIBSRCS += requester.cpp
LIBSRCS += serializeHelper.cpp
LIBSRCS += event.cpp
LIBSRCS += executor.cpp
LIBSRCS += timeFunction.cpp
LIBSRCS += timer.cpp
LIBSRCS += status.cpp
LIBSRCS += messageQueue.cpp
LIBSRCS += localStaticLock.cpp
SRC_DIRS += $(PVDATA)/pv
INC += pvType.h
INC += pvIntrospect.h
INC += pvData.h
INC += convert.h
INC += standardField.h
INC += standardPVField.h
SRC_DIRS += $(PVDATA)/factory
INC += factory.h
LIBSRCS += TypeFunc.cpp
LIBSRCS += FieldCreateFactory.cpp
LIBSRCS += PVAuxInfoImpl.cpp
LIBSRCS += PVField.cpp
LIBSRCS += PVScalar.cpp
LIBSRCS += PVArray.cpp
LIBSRCS += PVScalarArray.cpp
LIBSRCS += PVStructure.cpp
LIBSRCS += PVStructureArray.cpp
LIBSRCS += PVDataCreateFactory.cpp
LIBSRCS += Convert.cpp
LIBSRCS += Compare.cpp
LIBSRCS += StandardField.cpp
LIBSRCS += StandardPVField.cpp
SRC_DIRS += $(PVDATA)/property
INC += alarm.h
INC += pvAlarm.h
INC += control.h
INC += pvControl.h
INC += display.h
INC += pvDisplay.h
INC += pvEnumerated.h
INC += timeStamp.h
INC += pvTimeStamp.h
LIBSRCS += alarm.cpp
LIBSRCS += pvAlarm.cpp
LIBSRCS += pvControl.cpp
LIBSRCS += pvDisplay.cpp
LIBSRCS += pvEnumerated.cpp
LIBSRCS += timeStamp.cpp
LIBSRCS += pvTimeStamp.cpp
SRC_DIRS += $(PVDATA)/pvMisc
INC += bitSetUtil.h
LIBSRCS += bitSetUtil.cpp
SRC_DIRS += $(PVDATA)/monitor
INC += monitor.h
LIBRARY=pvData
pvData_LIBS += Com
include $(TOP)/configure/RULES

View File

@@ -1,108 +0,0 @@
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mes
*/
#include <pv/convert.h>
#include <algorithm>
#include <iterator>
#include <sstream>
namespace epics { namespace pvData {
// PVXXX object comparison
bool operator==(PVField& left, PVField& right)
{
return getConvert()->equals(left,right);
}
// Introspection object comparision
/** Field equality conditions:
* 1) same instance
* 2) same type (field and scalar/element), same name, same subfields (if any)
*/
bool operator==(const Field& a, const Field& b)
{
if(&a==&b)
return true;
if(a.getType()!=b.getType())
return false;
switch(a.getType()) {
case scalar: {
const Scalar &A=static_cast<const Scalar&>(a);
const Scalar &B=static_cast<const Scalar&>(b);
return A==B;
}
case scalarArray: {
const ScalarArray &A=static_cast<const ScalarArray&>(a);
const ScalarArray &B=static_cast<const ScalarArray&>(b);
return A==B;
}
case structure: {
const Structure &A=static_cast<const Structure&>(a);
const Structure &B=static_cast<const Structure&>(b);
return A==B;
}
case structureArray: {
const StructureArray &A=static_cast<const StructureArray&>(a);
const StructureArray &B=static_cast<const StructureArray&>(b);
return A==B;
}
default:
throw std::logic_error("Invalid Field type in comparision");
}
}
bool operator==(const Scalar& a, const Scalar& b)
{
if(&a==&b)
return true;
return a.getScalarType()==b.getScalarType();
}
bool operator==(const ScalarArray& a, const ScalarArray& b)
{
if(&a==&b)
return true;
return a.getElementType()==b.getElementType();
}
bool operator==(const Structure& a, const Structure& b)
{
if(&a==&b)
return true;
if (a.getID()!=b.getID())
return false;
size_t nflds=a.getNumberFields();
if (b.getNumberFields()!=nflds)
return false;
// std::equals does not work, since FieldConstPtrArray is an array of shared_pointers
FieldConstPtrArray af = a.getFields();
FieldConstPtrArray bf = b.getFields();
for (size_t i = 0; i < nflds; i++)
if (*(af[i].get()) != *(bf[i].get()))
return false;
StringArray an = a.getFieldNames();
StringArray bn = b.getFieldNames();
return std::equal( an.begin(), an.end(), bn.begin() );
}
bool operator==(const StructureArray& a, const StructureArray& b)
{
return *(a.getStructure().get())==*(b.getStructure().get());
}
namespace nconvert {
} // namespace nconvert
}} // namespace epics::pvData

File diff suppressed because it is too large Load Diff

View File

@@ -1,563 +0,0 @@
/*FieldCreateFactory.cpp*/
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
*/
#include <cstddef>
#include <cstdlib>
#include <string>
#include <cstdio>
#include <pv/lock.h>
#include <pv/pvIntrospect.h>
#include <pv/convert.h>
#include <pv/factory.h>
#include <pv/serializeHelper.h>
using std::tr1::static_pointer_cast;
using std::size_t;
namespace epics { namespace pvData {
static DebugLevel debugLevel = lowDebug;
static void newLine(StringBuilder buffer, int indentLevel)
{
*buffer += "\n";
for(int i=0; i<indentLevel; i++) *buffer += " ";
}
Field::Field(Type type)
: m_fieldType(type)
{
}
Field::~Field() {
}
void Field::toString(StringBuilder buffer,int indentLevel) const{
}
// TODO move all these to a header file
struct ScalarHashFunction {
size_t operator() (const Scalar& scalar) const { return scalar.getScalarType(); }
};
struct ScalarArrayHashFunction {
size_t operator() (const ScalarArray& scalarArray) const { return 0x10 | scalarArray.getElementType(); }
};
struct StructureHashFunction {
size_t operator() (const Structure& structure) const { return 0; }
// TODO
// final int PRIME = 31;
// return PRIME * Arrays.hashCode(fieldNames) + Arrays.hashCode(fields);
};
struct StructureArrayHashFunction {
size_t operator() (const StructureArray& structureArray) const { StructureHashFunction shf; return (0x10 | shf(*(structureArray.getStructure()))); }
};
Scalar::Scalar(ScalarType scalarType)
: Field(scalar),scalarType(scalarType){}
Scalar::~Scalar(){}
void Scalar::toString(StringBuilder buffer,int indentLevel) const{
*buffer += getID();
}
String Scalar::getID() const
{
static const String idScalarLUT[] = {
"boolean", // pvBoolean
"byte", // pvByte
"short", // pvShort
"int", // pvInt
"long", // pvLong
"ubyte", // pvUByte
"ushort", // pvUShort
"uint", // pvUInt
"ulong", // pvULong
"float", // pvFloat
"double", // pvDouble
"string" // pvString
};
return idScalarLUT[scalarType];
}
const int8 Scalar::getTypeCodeLUT() const
{
static const int8 typeCodeLUT[] = {
0x00, // pvBoolean
0x20, // pvByte
0x21, // pvShort
0x22, // pvInt
0x23, // pvLong
0x28, // pvUByte
0x29, // pvUShort
0x2A, // pvUInt
0x2B, // pvULong
0x42, // pvFloat
0x43, // pvDouble
0x60 // pvString
};
return typeCodeLUT[scalarType];
}
void Scalar::serialize(ByteBuffer *buffer, SerializableControl *control) const {
control->ensureBuffer(1);
buffer->putByte(getTypeCodeLUT());
}
void Scalar::deserialize(ByteBuffer *buffer, DeserializableControl *control) {
// must be done via FieldCreate
throw std::runtime_error("not valid operation, use FieldCreate::deserialize instead");
}
static String emptyString;
static void serializeStructureField(const Structure* structure, ByteBuffer* buffer, SerializableControl* control)
{
// to optimize default (non-empty) IDs optimization
// empty IDs are not allowed
String id = structure->getID();
if (id == Structure::DEFAULT_ID) // TODO slow comparison
SerializeHelper::serializeString(emptyString, buffer, control);
else
SerializeHelper::serializeString(id, buffer, control);
FieldConstPtrArray const & fields = structure->getFields();
StringArray const & fieldNames = structure->getFieldNames();
std::size_t len = fields.size();
SerializeHelper::writeSize(len, buffer, control);
for (std::size_t i = 0; i < len; i++)
{
SerializeHelper::serializeString(fieldNames[i], buffer, control);
control->cachedSerialize(fields[i], buffer);
}
}
static StructureConstPtr deserializeStructureField(const FieldCreate* fieldCreate, ByteBuffer* buffer, DeserializableControl* control)
{
String id = SerializeHelper::deserializeString(buffer, control);
const std::size_t size = SerializeHelper::readSize(buffer, control);
FieldConstPtrArray fields; fields.reserve(size);
StringArray fieldNames; fieldNames.reserve(size);
for (std::size_t i = 0; i < size; i++)
{
fieldNames.push_back(SerializeHelper::deserializeString(buffer, control));
fields.push_back(control->cachedDeserialize(buffer));
}
if (id.empty())
return fieldCreate->createStructure(fieldNames, fields);
else
return fieldCreate->createStructure(id, fieldNames, fields);
}
ScalarArray::ScalarArray(ScalarType elementType)
: Field(scalarArray),elementType(elementType){}
ScalarArray::~ScalarArray() {}
const int8 ScalarArray::getTypeCodeLUT() const
{
static const int8 typeCodeLUT[] = {
0x00, // pvBoolean
0x20, // pvByte
0x21, // pvShort
0x22, // pvInt
0x23, // pvLong
0x28, // pvUByte
0x29, // pvUShort
0x2A, // pvUInt
0x2B, // pvULong
0x42, // pvFloat
0x43, // pvDouble
0x60 // pvString
};
return typeCodeLUT[elementType];
}
const String ScalarArray::getIDScalarArrayLUT() const
{
static const String idScalarArrayLUT[] = {
"boolean[]", // pvBoolean
"byte[]", // pvByte
"short[]", // pvShort
"int[]", // pvInt
"long[]", // pvLong
"ubyte[]", // pvUByte
"ushort[]", // pvUShort
"uint[]", // pvUInt
"ulong[]", // pvULong
"float[]", // pvFloat
"double[]", // pvDouble
"string[]" // pvString
};
return idScalarArrayLUT[elementType];
}
String ScalarArray::getID() const
{
return getIDScalarArrayLUT();
}
void ScalarArray::toString(StringBuilder buffer,int indentLevel) const{
*buffer += getID();
}
void ScalarArray::serialize(ByteBuffer *buffer, SerializableControl *control) const {
control->ensureBuffer(1);
buffer->putByte(0x10 | getTypeCodeLUT());
}
void ScalarArray::deserialize(ByteBuffer *buffer, DeserializableControl *control) {
throw std::runtime_error("not valid operation, use FieldCreate::deserialize instead");
}
StructureArray::StructureArray(StructureConstPtr const & structure)
: Field(structureArray),pstructure(structure)
{
}
StructureArray::~StructureArray() {
if(debugLevel==highDebug) printf("~StructureArray\n");
}
String StructureArray::getID() const
{
return pstructure->getID() + "[]";
}
void StructureArray::toString(StringBuilder buffer,int indentLevel) const {
*buffer += getID();
newLine(buffer,indentLevel + 1);
pstructure->toString(buffer,indentLevel + 1);
}
void StructureArray::serialize(ByteBuffer *buffer, SerializableControl *control) const {
control->ensureBuffer(1);
buffer->putByte(0x90);
control->cachedSerialize(pstructure, buffer);
}
void StructureArray::deserialize(ByteBuffer *buffer, DeserializableControl *control) {
throw std::runtime_error("not valid operation, use FieldCreate::deserialize instead");
}
String Structure::DEFAULT_ID = "structure";
Structure::Structure (
StringArray const & fieldNames,
FieldConstPtrArray const & infields,
String const & inid)
: Field(structure),
fieldNames(fieldNames),
fields(infields),
id(inid)
{
if(inid.empty()) {
throw std::invalid_argument("id is empty");
}
if(fieldNames.size()!=fields.size()) {
throw std::invalid_argument("fieldNames.size()!=fields.size()");
}
size_t number = fields.size();
for(size_t i=0; i<number; i++) {
String name = fieldNames[i];
if(name.size()<1) {
throw std::invalid_argument("fieldNames has a zero length string");
}
// look for duplicates
for(size_t j=i+1; j<number; j++) {
String otherName = fieldNames[j];
int result = name.compare(otherName);
if(result==0) {
String message("duplicate fieldName ");
message += name;
throw std::invalid_argument(message);
}
}
}
}
Structure::~Structure() { }
String Structure::getID() const
{
return id;
}
FieldConstPtr Structure::getField(String const & fieldName) const {
size_t numberFields = fields.size();
for(size_t i=0; i<numberFields; i++) {
FieldConstPtr pfield = fields[i];
int result = fieldName.compare(fieldNames[i]);
if(result==0) return pfield;
}
return FieldConstPtr();
}
size_t Structure::getFieldIndex(String const &fieldName) const {
size_t numberFields = fields.size();
for(size_t i=0; i<numberFields; i++) {
FieldConstPtr pfield = fields[i];
int result = fieldName.compare(fieldNames[i]);
if(result==0) return i;
}
return -1;
}
void Structure::toString(StringBuilder buffer,int indentLevel) const{
*buffer += getID();
toStringCommon(buffer,indentLevel+1);
}
void Structure::toStringCommon(StringBuilder buffer,int indentLevel) const{
newLine(buffer,indentLevel);
size_t numberFields = fields.size();
for(size_t i=0; i<numberFields; i++) {
FieldConstPtr pfield = fields[i];
*buffer += pfield->getID() + " " + fieldNames[i];
switch(pfield->getType()) {
case scalar:
case scalarArray:
break;
case structure:
{
Field const *xxx = pfield.get();
Structure const *pstruct = static_cast<Structure const*>(xxx);
pstruct->toStringCommon(buffer,indentLevel + 1);
break;
}
case structureArray:
newLine(buffer,indentLevel +1);
pfield->toString(buffer,indentLevel +1);
break;
}
if(i<numberFields-1) newLine(buffer,indentLevel);
}
}
void Structure::serialize(ByteBuffer *buffer, SerializableControl *control) const {
control->ensureBuffer(1);
buffer->putByte(0x80);
serializeStructureField(this, buffer, control);
}
void Structure::deserialize(ByteBuffer *buffer, DeserializableControl *control) {
throw std::runtime_error("not valid operation, use FieldCreate::deserialize instead");
}
ScalarConstPtr FieldCreate::createScalar(ScalarType scalarType) const
{
// TODO use singleton instance
ScalarConstPtr scalar(new Scalar(scalarType), Field::Deleter());
return scalar;
}
ScalarArrayConstPtr FieldCreate::createScalarArray(ScalarType elementType) const
{
// TODO use singleton instance
ScalarArrayConstPtr scalarArray(new ScalarArray(elementType), Field::Deleter());
return scalarArray;
}
StructureConstPtr FieldCreate::createStructure (
StringArray const & fieldNames,FieldConstPtrArray const & fields) const
{
StructureConstPtr structure(
new Structure(fieldNames,fields), Field::Deleter());
return structure;
}
StructureConstPtr FieldCreate::createStructure (
String const & id,
StringArray const & fieldNames,
FieldConstPtrArray const & fields) const
{
StructureConstPtr structure(
new Structure(fieldNames,fields,id), Field::Deleter());
return structure;
}
StructureArrayConstPtr FieldCreate::createStructureArray(
StructureConstPtr const & structure) const
{
StructureArrayConstPtr structureArray(
new StructureArray(structure), Field::Deleter());
return structureArray;
}
StructureConstPtr FieldCreate::appendField(
StructureConstPtr const & structure,
String const & fieldName,
FieldConstPtr const & field) const
{
StringArray oldNames = structure->getFieldNames();
FieldConstPtrArray oldFields = structure->getFields();
size_t oldLen = oldNames.size();
StringArray newNames(oldLen+1);
FieldConstPtrArray newFields(oldLen+1);
for(size_t i = 0; i<oldLen; i++) {
newNames[i] = oldNames[i];
newFields[i] = oldFields[i];
}
newNames[oldLen] = fieldName;
newFields[oldLen] = field;
return createStructure(structure->getID(),newNames,newFields);
}
StructureConstPtr FieldCreate::appendFields(
StructureConstPtr const & structure,
StringArray const & fieldNames,
FieldConstPtrArray const & fields) const
{
StringArray oldNames = structure->getFieldNames();
FieldConstPtrArray oldFields = structure->getFields();
size_t oldLen = oldNames.size();
size_t extra = fieldNames.size();
StringArray newNames(oldLen+extra);
FieldConstPtrArray newFields(oldLen+extra);
for(size_t i = 0; i<oldLen; i++) {
newNames[i] = oldNames[i];
newFields[i] = oldFields[i];
}
for(size_t i = 0; i<extra; i++) {
newNames[oldLen +i] = fieldNames[i];
newFields[oldLen +i] = fields[i];
}
return createStructure(structure->getID(),newNames,newFields);
}
static int decodeScalar(int8 code)
{
static const int integerLUT[] =
{
pvByte, // 8-bits
pvShort, // 16-bits
pvInt, // 32-bits
pvLong, // 64-bits
-1,
-1,
-1,
-1,
pvUByte, // unsigned 8-bits
pvUShort, // unsigned 16-bits
pvUInt, // unsigned 32-bits
pvULong, // unsigned 64-bits
-1,
-1,
-1,
-1
};
static const int floatLUT[] =
{
-1, // reserved
-1, // 16-bits
pvFloat, // 32-bits
pvDouble, // 64-bits
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1
};
// bits 7-5
switch (code >> 5)
{
case 0: return pvBoolean;
case 1: return integerLUT[code & 0x0F];
case 2: return floatLUT[code & 0x0F];
case 3: return pvString;
default: return -1;
}
}
FieldConstPtr FieldCreate::deserialize(ByteBuffer* buffer, DeserializableControl* control) const
{
control->ensureData(1);
int8 code = buffer->getByte();
if (code == -1)
return FieldConstPtr();
int typeCode = code & 0xE0;
bool notArray = ((code & 0x10) == 0);
if (notArray)
{
if (typeCode < 0x80)
{
// Type type = Type.scalar;
int scalarType = decodeScalar(code);
if (scalarType == -1)
throw std::invalid_argument("invalid scalar type encoding");
return FieldConstPtr(new Scalar(static_cast<ScalarType>(scalarType)), Field::Deleter());
}
else if (typeCode == 0x80)
{
// Type type = Type.structure;
return deserializeStructureField(this, buffer, control);
}
else
throw std::invalid_argument("invalid type encoding");
}
else // array
{
if (typeCode < 0x80)
{
// Type type = Type.scalarArray;
int scalarType = decodeScalar(code);
if (scalarType == -1)
throw std::invalid_argument("invalid scalarArray type encoding");
return FieldConstPtr(new ScalarArray(static_cast<ScalarType>(scalarType)), Field::Deleter());
}
else if (typeCode == 0x80)
{
// Type type = Type.structureArray;
StructureConstPtr elementStructure = std::tr1::static_pointer_cast<const Structure>(control->cachedDeserialize(buffer));
return FieldConstPtr(new StructureArray(elementStructure), Field::Deleter());
}
else
throw std::invalid_argument("invalid type encoding");
}
}
FieldCreatePtr FieldCreate::getFieldCreate()
{
LOCAL_STATIC_LOCK;
static FieldCreatePtr fieldCreate;
static Mutex mutex;
Lock xx(mutex);
if(fieldCreate.get()==0) fieldCreate = FieldCreatePtr(new FieldCreate());
return fieldCreate;
}
FieldCreate::FieldCreate(){}
FieldCreatePtr getFieldCreate() {
return FieldCreate::getFieldCreate();
}
}}

View File

@@ -1,100 +0,0 @@
/*PVArray.cpp*/
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
*/
#include <cstddef>
#include <cstdlib>
#include <string>
#include <cstdio>
#include <pv/pvData.h>
#include <pv/factory.h>
using std::size_t;
namespace epics { namespace pvData {
class PVArrayPvt {
public:
PVArrayPvt() : length(0),capacity(0),capacityMutable(true)
{}
size_t length;
size_t capacity;
bool capacityMutable;
};
PVArray::PVArray(FieldConstPtr const & field)
: PVField(field),pImpl(new PVArrayPvt())
{ }
PVArray::~PVArray()
{
delete pImpl;
}
void PVArray::setImmutable()
{
pImpl->capacityMutable = false;
PVField::setImmutable();
}
size_t PVArray::getLength() const {return pImpl->length;}
size_t PVArray::getCapacity() const {return pImpl->capacity;}
static String fieldImmutable("field is immutable");
void PVArray::setLength(size_t length) {
if(length==pImpl->length) return;
if(PVField::isImmutable()) {
PVField::message(fieldImmutable,errorMessage);
return;
}
if(length>pImpl->capacity) this->setCapacity(length);
if(length>pImpl->capacity) length = pImpl->capacity;
pImpl->length = length;
}
void PVArray::setCapacityLength(size_t capacity,size_t length) {
pImpl->capacity = capacity;
pImpl->length = length;
}
bool PVArray::isCapacityMutable() const
{
if(PVField::isImmutable()) {
return false;
}
return pImpl->capacityMutable;
}
void PVArray::setCapacityMutable(bool isMutable)
{
if(isMutable && PVField::isImmutable()) {
PVField::message(fieldImmutable,errorMessage);
return;
}
pImpl->capacityMutable = isMutable;
}
static String capacityImmutable("capacity is immutable");
void PVArray::setCapacity(size_t capacity) {
if(PVField::isImmutable()) {
PVField::message(fieldImmutable,errorMessage);
return;
}
if(pImpl->capacityMutable==false) {
PVField::message(capacityImmutable,errorMessage);
return;
}
pImpl->capacity = capacity;
}
}}

View File

@@ -1,84 +0,0 @@
/*PVAuxInfo.cpp*/
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
*/
#include <cstddef>
#include <cstdlib>
#include <string>
#include <cstdio>
#include <pv/noDefaultMethods.h>
#include <pv/pvData.h>
#include <pv/convert.h>
#include <pv/factory.h>
#include <pv/lock.h>
namespace epics { namespace pvData {
PVAuxInfo::PVAuxInfo(PVField * pvField)
: pvField(pvField),
pvInfos(std::map<String,std::tr1::shared_ptr<PVScalar> > ())
{
}
PVAuxInfo::~PVAuxInfo()
{
}
PVField * PVAuxInfo::getPVField() {
return pvField;
}
PVScalarPtr PVAuxInfo::createInfo(String const & key,ScalarType scalarType)
{
PVInfoIter iter = pvInfos.find(key);
if(iter!=pvInfos.end()) {
String message = key.c_str();
message += " already exists ";
pvField->message(message,errorMessage);
return nullPVScalar;
}
PVScalarPtr pvScalar = getPVDataCreate()->createPVScalar(scalarType);
pvInfos.insert(PVInfoPair(key,pvScalar));
return pvScalar;
}
PVScalarPtr PVAuxInfo::getInfo(String const & key)
{
PVInfoIter iter;
iter = pvInfos.find(key);
if(iter==pvInfos.end()) return nullPVScalar;
return iter->second;
}
PVAuxInfo::PVInfoMap & PVAuxInfo::getInfoMap()
{
return pvInfos;
}
void PVAuxInfo::toString(StringBuilder buf)
{
PVAuxInfo::toString(buf,0);
}
void PVAuxInfo::toString(StringBuilder buf,int indentLevel)
{
if(pvInfos.size()<=0) return;
ConvertPtr convert = getConvert();
convert->newLine(buf,indentLevel);
*buf += "auxInfo";
for(PVInfoIter iter = pvInfos.begin(); iter!= pvInfos.end(); ++iter) {
convert->newLine(buf,indentLevel+1);
PVFieldPtr value = iter->second;
value->toString(buf,indentLevel + 1);
}
}
}}

View File

@@ -1,705 +0,0 @@
/*PVStructure.cpp*/
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
*/
#include <cstddef>
#include <cstdlib>
#include <string>
#include <cstdio>
#include <vector>
#include <pv/pvData.h>
#include <pv/pvIntrospect.h>
#include <pv/convert.h>
#include <pv/factory.h>
#include <pv/bitSet.h>
using std::tr1::static_pointer_cast;
using std::size_t;
namespace epics { namespace pvData {
PVFieldPtr PVStructure::nullPVField;
PVBooleanPtr PVStructure::nullPVBoolean;
PVBytePtr PVStructure::nullPVByte;
PVShortPtr PVStructure::nullPVShort;
PVIntPtr PVStructure::nullPVInt;
PVLongPtr PVStructure::nullPVLong;
PVUBytePtr PVStructure::nullPVUByte;
PVUShortPtr PVStructure::nullPVUShort;
PVUIntPtr PVStructure::nullPVUInt;
PVULongPtr PVStructure::nullPVULong;
PVFloatPtr PVStructure::nullPVFloat;
PVDoublePtr PVStructure::nullPVDouble;
PVStringPtr PVStructure::nullPVString;
PVStructurePtr PVStructure::nullPVStructure;
PVStructureArrayPtr PVStructure::nullPVStructureArray;
PVScalarArrayPtr PVStructure::nullPVScalarArray;
static PVFieldPtr findSubField(
String const &fieldName,
const PVStructure *pvStructure);
PVStructure::PVStructure(StructureConstPtr const & structurePtr)
: PVField(structurePtr),
structurePtr(structurePtr),
extendsStructureName("")
{
size_t numberFields = structurePtr->getNumberFields();
FieldConstPtrArray fields = structurePtr->getFields();
StringArray fieldNames = structurePtr->getFieldNames();
// PVFieldPtrArray * xxx = const_cast<PVFieldPtrArray *>(&pvFields);
pvFields.reserve(numberFields);
PVDataCreatePtr pvDataCreate = getPVDataCreate();
for(size_t i=0; i<numberFields; i++) {
pvFields.push_back(pvDataCreate->createPVField(fields[i]));
}
for(size_t i=0; i<numberFields; i++) {
pvFields[i]->setParentAndName(this,fieldNames[i]);
}
}
PVStructure::PVStructure(StructureConstPtr const & structurePtr,
PVFieldPtrArray const & pvs
)
: PVField(structurePtr),
structurePtr(structurePtr),
extendsStructureName("")
{
size_t numberFields = structurePtr->getNumberFields();
StringArray fieldNames = structurePtr->getFieldNames();
pvFields.reserve(numberFields);
for(size_t i=0; i<numberFields; i++) {
pvFields.push_back(pvs[i]);
}
for(size_t i=0; i<numberFields; i++) {
pvFields[i]->setParentAndName(this,fieldNames[i]);
}
}
PVStructure::~PVStructure()
{
}
void PVStructure::setImmutable()
{
size_t numFields = pvFields.size();
for(size_t i=0; i<numFields; i++) {
PVFieldPtr pvField = pvFields[i];
pvField->setImmutable();
}
PVField::setImmutable();
}
StructureConstPtr PVStructure::getStructure() const
{
return structurePtr;
}
const PVFieldPtrArray & PVStructure::getPVFields() const
{
return pvFields;
}
PVFieldPtr PVStructure::getSubField(String const &fieldName) const
{
return findSubField(fieldName,this);
}
PVFieldPtr PVStructure::getSubField(size_t fieldOffset) const
{
if(fieldOffset<=getFieldOffset()) {
return nullPVField;
}
if(fieldOffset>getNextFieldOffset()) return nullPVField;
size_t numFields = pvFields.size();
for(size_t i=0; i<numFields; i++) {
PVFieldPtr pvField = pvFields[i];
if(pvField->getFieldOffset()==fieldOffset) return pvFields[i];
if(pvField->getNextFieldOffset()<=fieldOffset) continue;
if(pvField->getField()->getType()==structure) {
PVStructure *pvStructure = static_cast<PVStructure *>(pvField.get());
return pvStructure->getSubField(fieldOffset);
}
}
throw std::logic_error("PVStructure.getSubField: Logic error");
}
void PVStructure::fixParentStructure()
{
PVStructure *parent = getParent();
if(parent==NULL) return;
StructureConstPtr parentStructure = parent->structurePtr;
String fieldName = getFieldName();
size_t index = parentStructure->getFieldIndex(fieldName);
StringArray const &fieldNames = parentStructure->getFieldNames();
size_t num = fieldNames.size();
FieldConstPtrArray fields(num);
FieldConstPtrArray const & oldFields = parentStructure->getFields();
for(size_t i=0; i< num; i++) {
if(i==index) {
fields[i] = structurePtr;
} else {
fields[i] = oldFields[i];
}
}
FieldConstPtr field = getFieldCreate()->createStructure(
parentStructure->getID(),fieldNames,fields);
parent->replaceField(field);
parent->fixParentStructure();
}
void PVStructure::appendPVField(
String const &fieldName,
PVFieldPtr const & pvField)
{
size_t origLength = pvFields.size();
size_t newLength = origLength+1;
PVFieldPtrArray * xxx = const_cast<PVFieldPtrArray *>(&pvFields);
xxx->push_back(pvField);
FieldConstPtr field = getFieldCreate()->appendField(
structurePtr,fieldName,pvField->getField());
replaceField(field);
structurePtr = static_pointer_cast<const Structure>(field);
StringArray fieldNames = structurePtr->getFieldNames();
for(size_t i=0; i<newLength; i++) {
pvFields[i]->setParentAndName(this,fieldNames[i]);
}
fixParentStructure();
}
void PVStructure::appendPVFields(
StringArray const & fieldNames,
PVFieldPtrArray const & pvFields)
{
size_t origLength = this->pvFields.size();
size_t extra = fieldNames.size();
if(extra==0) return;
size_t newLength = origLength + extra;
PVFieldPtrArray * xxx = const_cast<PVFieldPtrArray *>(&this->pvFields);
xxx->reserve(newLength);
for(size_t i=0; i<extra; i++) {
xxx->push_back(pvFields[i]);
}
FieldConstPtrArray fields;
fields.reserve(extra);
for(size_t i=0; i<extra; i++) fields.push_back(pvFields[i]->getField());
FieldConstPtr field = getFieldCreate()->appendFields(
structurePtr,fieldNames,fields);
replaceField(field);
structurePtr = static_pointer_cast<const Structure>(field);
StringArray names = structurePtr->getFieldNames();
for(size_t i=0; i<newLength; i++) {
(*xxx)[i]->setParentAndName(this,names[i]);
}
fixParentStructure();
}
void PVStructure::removePVField(String const &fieldName)
{
PVFieldPtr pvField = getSubField(fieldName);
if(pvField.get()==NULL) {
String message("removePVField ");
message += fieldName + " does not exist";
this->message(message, errorMessage);
return;
}
size_t origLength = pvFields.size();
size_t newLength = origLength - 1;
PVFieldPtrArray const & origPVFields = pvFields;
FieldConstPtrArray origFields = structurePtr->getFields();
PVFieldPtrArray newPVFields;
newPVFields.reserve(newLength);
StringArray newFieldNames;
newFieldNames.reserve(newLength);
FieldConstPtrArray fields;
fields.reserve(newLength);
for(size_t i=0; i<origLength; i++) {
if(origPVFields[i]!=pvField) {
newFieldNames.push_back(origPVFields[i]->getFieldName());
newPVFields.push_back(origPVFields[i]);
fields.push_back(origFields[i]);
}
}
PVFieldPtrArray * xxx = const_cast<PVFieldPtrArray *>(&pvFields);
xxx->swap(newPVFields);
FieldConstPtr field = getFieldCreate()->createStructure(
structurePtr->getID(),newFieldNames,fields);
replaceField(field);
structurePtr = static_pointer_cast<const Structure>(field);
StringArray fieldNames = structurePtr->getFieldNames();
for(size_t i=0; i<newLength; i++) {
pvFields[i]->setParentAndName(this,fieldNames[i]);
}
}
PVBooleanPtr PVStructure::getBooleanField(String const &fieldName)
{
PVFieldPtr pvField = findSubField(fieldName,this);
if(pvField.get()==NULL) {
String message("fieldName ");
message += fieldName + " does not exist";
this->message(message, errorMessage);
return nullPVBoolean;
}
if(pvField->getField()->getType()==scalar) {
ScalarConstPtr pscalar = static_pointer_cast<const Scalar>(
pvField->getField());
if(pscalar->getScalarType()==pvBoolean) {
return std::tr1::static_pointer_cast<PVBoolean>(pvField);
}
}
String message("fieldName ");
message += fieldName + " does not have type boolean ";
this->message(message, errorMessage);
return nullPVBoolean;
}
PVBytePtr PVStructure::getByteField(String const &fieldName)
{
PVFieldPtr pvField = findSubField(fieldName,this);
if(pvField.get()==NULL) {
String message("fieldName ");
message += fieldName + " does not exist";
this->message(message, errorMessage);
return nullPVByte;
}
if(pvField->getField()->getType()==scalar) {
ScalarConstPtr pscalar = static_pointer_cast<const Scalar>(
pvField->getField());
if(pscalar->getScalarType()==pvByte) {
return std::tr1::static_pointer_cast<PVByte>(pvField);
}
}
String message("fieldName ");
message += fieldName + " does not have type byte ";
this->message(message, errorMessage);
return nullPVByte;
}
PVShortPtr PVStructure::getShortField(String const &fieldName)
{
PVFieldPtr pvField = findSubField(fieldName,this);
if(pvField.get()==NULL) {
String message("fieldName ");
message += fieldName + " does not exist";
this->message(message, errorMessage);
return nullPVShort;
}
if(pvField->getField()->getType()==scalar) {
ScalarConstPtr pscalar = static_pointer_cast<const Scalar>(
pvField->getField());
if(pscalar->getScalarType()==pvShort) {
return std::tr1::static_pointer_cast<PVShort>(pvField);
}
}
String message("fieldName ");
message += fieldName + " does not have type short ";
this->message(message, errorMessage);
return nullPVShort;
}
PVIntPtr PVStructure::getIntField(String const &fieldName)
{
PVFieldPtr pvField = findSubField(fieldName,this);
if(pvField.get()==NULL) {
String message("fieldName ");
message += fieldName + " does not exist";
this->message(message, errorMessage);
return nullPVInt;
}
if(pvField->getField()->getType()==scalar) {
ScalarConstPtr pscalar = static_pointer_cast<const Scalar>(
pvField->getField());
if(pscalar->getScalarType()==pvInt) {
return std::tr1::static_pointer_cast<PVInt>(pvField);
}
}
String message("fieldName ");
message += fieldName + " does not have type int ";
this->message(message, errorMessage);
return nullPVInt;
}
PVLongPtr PVStructure::getLongField(String const &fieldName)
{
PVFieldPtr pvField = findSubField(fieldName,this);
if(pvField.get()==NULL) {
String message("fieldName ");
message += fieldName + " does not exist";
this->message(message, errorMessage);
return nullPVLong;
}
if(pvField->getField()->getType()==scalar) {
ScalarConstPtr pscalar = static_pointer_cast<const Scalar>(
pvField->getField());
if(pscalar->getScalarType()==pvLong) {
return std::tr1::static_pointer_cast<PVLong>(pvField);
}
}
String message("fieldName ");
message += fieldName + " does not have type long ";
this->message(message, errorMessage);
return nullPVLong;
}
PVUBytePtr PVStructure::getUByteField(String const &fieldName)
{
PVFieldPtr pvField = findSubField(fieldName,this);
if(pvField.get()==NULL) {
String message("fieldName ");
message += fieldName + " does not exist";
this->message(message, errorMessage);
return nullPVUByte;
}
if(pvField->getField()->getType()==scalar) {
ScalarConstPtr pscalar = static_pointer_cast<const Scalar>(
pvField->getField());
if(pscalar->getScalarType()==pvUByte) {
return std::tr1::static_pointer_cast<PVUByte>(pvField);
}
}
String message("fieldName ");
message += fieldName + " does not have type byte ";
this->message(message, errorMessage);
return nullPVUByte;
}
PVUShortPtr PVStructure::getUShortField(String const &fieldName)
{
PVFieldPtr pvField = findSubField(fieldName,this);
if(pvField.get()==NULL) {
String message("fieldName ");
message += fieldName + " does not exist";
this->message(message, errorMessage);
return nullPVUShort;
}
if(pvField->getField()->getType()==scalar) {
ScalarConstPtr pscalar = static_pointer_cast<const Scalar>(
pvField->getField());
if(pscalar->getScalarType()==pvUShort) {
return std::tr1::static_pointer_cast<PVUShort>(pvField);
}
}
String message("fieldName ");
message += fieldName + " does not have type short ";
this->message(message, errorMessage);
return nullPVUShort;
}
PVUIntPtr PVStructure::getUIntField(String const &fieldName)
{
PVFieldPtr pvField = findSubField(fieldName,this);
if(pvField.get()==NULL) {
String message("fieldName ");
message += fieldName + " does not exist";
this->message(message, errorMessage);
return nullPVUInt;
}
if(pvField->getField()->getType()==scalar) {
ScalarConstPtr pscalar = static_pointer_cast<const Scalar>(
pvField->getField());
if(pscalar->getScalarType()==pvUInt) {
return std::tr1::static_pointer_cast<PVUInt>(pvField);
}
}
String message("fieldName ");
message += fieldName + " does not have type int ";
this->message(message, errorMessage);
return nullPVUInt;
}
PVULongPtr PVStructure::getULongField(String const &fieldName)
{
PVFieldPtr pvField = findSubField(fieldName,this);
if(pvField.get()==NULL) {
String message("fieldName ");
message += fieldName + " does not exist";
this->message(message, errorMessage);
return nullPVULong;
}
if(pvField->getField()->getType()==scalar) {
ScalarConstPtr pscalar = static_pointer_cast<const Scalar>(
pvField->getField());
if(pscalar->getScalarType()==pvULong) {
return std::tr1::static_pointer_cast<PVULong>(pvField);
}
}
String message("fieldName ");
message += fieldName + " does not have type long ";
this->message(message, errorMessage);
return nullPVULong;
}
PVFloatPtr PVStructure::getFloatField(String const &fieldName)
{
PVFieldPtr pvField = findSubField(fieldName,this);
if(pvField.get()==NULL) {
String message("fieldName ");
message += fieldName + " does not exist";
this->message(message, errorMessage);
return nullPVFloat;
}
if(pvField->getField()->getType()==scalar) {
ScalarConstPtr pscalar = static_pointer_cast<const Scalar>(
pvField->getField());
if(pscalar->getScalarType()==pvFloat) {
return std::tr1::static_pointer_cast<PVFloat>(pvField);
}
}
String message("fieldName ");
message += fieldName + " does not have type float ";
this->message(message, errorMessage);
return nullPVFloat;
}
PVDoublePtr PVStructure::getDoubleField(String const &fieldName)
{
PVFieldPtr pvField = findSubField(fieldName,this);
if(pvField.get()==NULL) {
String message("fieldName ");
message += fieldName + " does not exist";
this->message(message, errorMessage);
return nullPVDouble;
}
if(pvField->getField()->getType()==scalar) {
ScalarConstPtr pscalar = static_pointer_cast<const Scalar>(
pvField->getField());
if(pscalar->getScalarType()==pvDouble) {
return std::tr1::static_pointer_cast<PVDouble>(pvField);
}
}
String message("fieldName ");
message += fieldName + " does not have type double ";
this->message(message, errorMessage);
return nullPVDouble;
}
PVStringPtr PVStructure::getStringField(String const &fieldName)
{
PVFieldPtr pvField = findSubField(fieldName,this);
if(pvField.get()==NULL) {
String message("fieldName ");
message += fieldName + " does not exist";
this->message(message, errorMessage);
return nullPVString;
}
if(pvField->getField()->getType()==scalar) {
ScalarConstPtr pscalar = static_pointer_cast<const Scalar>(
pvField->getField());
if(pscalar->getScalarType()==pvString) {
return std::tr1::static_pointer_cast<PVString>(pvField);
}
}
String message("fieldName ");
message += fieldName + " does not have type string ";
this->message(message, errorMessage);
return nullPVString;
}
PVStructurePtr PVStructure::getStructureField(String const &fieldName)
{
PVFieldPtr pvField = findSubField(fieldName,this);
if(pvField.get()==NULL) {
String message("fieldName ");
message += fieldName + " does not exist";
this->message(message, errorMessage);
return nullPVStructure;
}
if(pvField->getField()->getType()==structure) {
return std::tr1::static_pointer_cast<PVStructure>(pvField);
}
String message("fieldName ");
message += fieldName + " does not have type structure ";
this->message(message, errorMessage);
return nullPVStructure;
}
PVScalarArrayPtr PVStructure::getScalarArrayField(
String const &fieldName,ScalarType elementType)
{
PVFieldPtr pvField = findSubField(fieldName,this);
if(pvField.get()==NULL) {
String message("fieldName ");
message += fieldName + " does not exist";
this->message(message, errorMessage);
return nullPVScalarArray;
}
FieldConstPtr field = pvField->getField();
Type type = field->getType();
if(type!=scalarArray) {
String message("fieldName ");
message += fieldName + " does not have type array ";
this->message(message, errorMessage);
return nullPVScalarArray;
}
ScalarArrayConstPtr pscalarArray
= static_pointer_cast<const ScalarArray>(pvField->getField());
if(pscalarArray->getElementType()!=elementType) {
String message("fieldName ");
message += fieldName + " is array but does not have elementType ";
ScalarTypeFunc::toString(&message,elementType);
this->message(message, errorMessage);
return nullPVScalarArray;
}
return std::tr1::static_pointer_cast<PVScalarArray>(pvField);
}
PVStructureArrayPtr PVStructure::getStructureArrayField(
String const &fieldName)
{
PVFieldPtr pvField = findSubField(fieldName,this);
if(pvField.get()==NULL) {
String message("fieldName ");
message += fieldName + " does not exist";
this->message(message, errorMessage);
return nullPVStructureArray;
}
if(pvField->getField()->getType()==structureArray) {
return std::tr1::static_pointer_cast<PVStructureArray>(pvField);
}
String message("fieldName ");
message += fieldName + " does not have type structureArray ";
this->message(message, errorMessage);
return nullPVStructureArray;
}
String PVStructure::getExtendsStructureName() const
{
return extendsStructureName;
}
bool PVStructure::putExtendsStructureName(
String const &xxx)
{
if(extendsStructureName.length()!=0) return false;
extendsStructureName = xxx;
return true;
}
void PVStructure::serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher) const {
size_t fieldsSize = pvFields.size();
for(size_t i = 0; i<fieldsSize; i++)
pvFields[i]->serialize(pbuffer, pflusher);
}
void PVStructure::deserialize(ByteBuffer *pbuffer,
DeserializableControl *pcontrol) {
size_t fieldsSize = pvFields.size();
for(size_t i = 0; i<fieldsSize; i++)
pvFields[i]->deserialize(pbuffer, pcontrol);
}
void PVStructure::serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher, BitSet *pbitSet) const {
PVStructure* nonConstThis = const_cast<PVStructure*>(this);
size_t numberFields = nonConstThis->getNumberFields();
size_t offset = nonConstThis->getFieldOffset();
int32 next = pbitSet->nextSetBit(offset);
// no more changes or no changes in this structure
if(next<0||next>=static_cast<int32>(offset+numberFields)) return;
// entire structure
if(static_cast<int32>(offset)==next) {
serialize(pbuffer, pflusher);
return;
}
size_t fieldsSize = pvFields.size();
for(size_t i = 0; i<fieldsSize; i++) {
PVFieldPtr pvField = pvFields[i];
offset = pvField->getFieldOffset();
int32 inumberFields = pvField->getNumberFields();
next = pbitSet->nextSetBit(offset);
// no more changes
if(next<0) return;
// no change in this pvField
if(next>=static_cast<int32>(offset+inumberFields)) continue;
// serialize field or fields
if(inumberFields==1) {
pvField->serialize(pbuffer, pflusher);
} else {
PVStructurePtr pvStructure = std::tr1::static_pointer_cast<PVStructure>(pvField);
pvStructure->serialize(pbuffer, pflusher, pbitSet);
}
}
}
void PVStructure::deserialize(ByteBuffer *pbuffer,
DeserializableControl *pcontrol, BitSet *pbitSet) {
size_t offset = getFieldOffset();
size_t numberFields = getNumberFields();
int32 next = pbitSet->nextSetBit(offset);
// no more changes or no changes in this structure
if(next<0||next>=static_cast<int32>(offset+numberFields)) return;
// entire structure
if(static_cast<int32>(offset)==next) {
deserialize(pbuffer, pcontrol);
return;
}
size_t fieldsSize = pvFields.size();
for(size_t i = 0; i<fieldsSize; i++) {
PVFieldPtr pvField = pvFields[i];
offset = pvField->getFieldOffset();
int32 inumberFields = pvField->getNumberFields();
next = pbitSet->nextSetBit(offset);
// no more changes
if(next<0) return;
// no change in this pvField
if(next>=static_cast<int32>(offset+inumberFields)) continue;
// deserialize field or fields
if(inumberFields==1) {
pvField->deserialize(pbuffer, pcontrol);
} else {
PVStructurePtr pvStructure = std::tr1::static_pointer_cast<PVStructure>(pvField);
pvStructure->deserialize(pbuffer, pcontrol, pbitSet);
}
}
}
static PVFieldPtr findSubField(
String const & fieldName,
PVStructure const *pvStructure)
{
if( fieldName.length()<1) return PVFieldPtr();
String::size_type index = fieldName.find('.');
String name = fieldName;
String restOfName = String();
if(index>0) {
name = fieldName.substr(0, index);
if(fieldName.length()>index) {
restOfName = fieldName.substr(index+1);
}
}
PVFieldPtrArray pvFields = pvStructure->getPVFields();
PVFieldPtr pvField;
size_t numFields = pvStructure->getStructure()->getNumberFields();
for(size_t i=0; i<numFields; i++) {
pvField = pvFields[i];
size_t result = pvField->getFieldName().compare(name);
if(result==0) {
if(restOfName.length()==0) return pvFields[i];
if(pvField->getField()->getType()!=structure) return PVFieldPtr();
PVStructurePtr pvStructure =
std::tr1::static_pointer_cast<PVStructure>(pvField);
return findSubField(restOfName,pvStructure.get());
}
}
return PVFieldPtr();
}
}}

View File

@@ -1,253 +0,0 @@
/*PVStructureArray.cpp*/
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
*/
#include <cstddef>
#include <cstdlib>
#include <string>
#include <cstdio>
#include <pv/pvData.h>
#include <pv/convert.h>
#include <pv/factory.h>
#include <pv/serializeHelper.h>
using std::tr1::static_pointer_cast;
using std::size_t;
namespace epics { namespace pvData {
PVStructureArray::PVStructureArray(StructureArrayConstPtr const & structureArray)
: PVArray(structureArray),
structureArray(structureArray),
value(std::tr1::shared_ptr<PVStructurePtrArray>(new PVStructurePtrArray()))
{
}
size_t PVStructureArray::append(size_t number)
{
size_t currentLength = getLength();
size_t newLength = currentLength + number;
setCapacity(newLength);
setLength(newLength);
StructureConstPtr structure = structureArray->getStructure();
PVStructurePtrArray *to = value.get();
for(size_t i=currentLength; i<newLength; i++) {
(*to)[i] =getPVDataCreate()->createPVStructure(structure);
}
return newLength;
}
bool PVStructureArray::remove(size_t offset,size_t number)
{
size_t length = getLength();
if(offset+number>length) return false;
PVStructurePtrArray vec = *value.get();
for(size_t i = offset; i+number < length; i++) {
vec[i] = vec[i + number];
}
size_t newLength = length - number;
setCapacityLength(newLength,newLength);
return true;
}
void PVStructureArray::compress() {
size_t length = getCapacity();
size_t newLength = 0;
PVStructurePtrArray vec = *value.get();
for(size_t i=0; i<length; i++) {
if(vec[i].get()!=NULL) {
newLength++;
continue;
}
// find first non 0
size_t notNull = 0;
for(size_t j=i+1;j<length;j++) {
if(vec[j].get()!=NULL) {
notNull = j;
break;
}
}
if(notNull!=0) {
vec[i] = vec[notNull];
vec[notNull].reset();
newLength++;
continue;
}
break;
}
setCapacityLength(newLength,newLength);
}
void PVStructureArray::setCapacity(size_t capacity) {
if(getCapacity()==capacity) return;
if(!isCapacityMutable()) {
std::string message("not capacityMutable");
PVField::message(message, errorMessage);
return;
}
size_t length = getLength();
if(length>capacity) length = capacity;
size_t oldCapacity = getCapacity();
if(oldCapacity>capacity) {
PVStructurePtrArray array;
array.reserve(capacity);
array.resize(length);
PVStructurePtr * from = get();
for (size_t i=0; i<length; i++) array[i] = from[i];
value->swap(array);
} else {
value->reserve(capacity);
}
setCapacityLength(capacity,length);
}
void PVStructureArray::setLength(size_t length) {
if(PVArray::getLength()==length) return;
size_t capacity = PVArray::getCapacity();
if(length>capacity) {
if(!PVArray::isCapacityMutable()) {
std::string message("not capacityMutable");
PVField::message(message, errorMessage);
return;
}
setCapacity(length);
}
value->resize(length);
PVArray::setCapacityLength(capacity,length);
}
StructureArrayConstPtr PVStructureArray::getStructureArray() const
{
return structureArray;
}
size_t PVStructureArray::get(
size_t offset, size_t len, StructureArrayData &data)
{
size_t n = len;
size_t length = getLength();
if(offset+len > length) {
n = length - offset;
if(n<0) n = 0;
}
data.data = *value.get();
data.offset = offset;
return n;
}
size_t PVStructureArray::put(size_t offset,size_t len,
const_vector const & from, size_t fromOffset)
{
if(isImmutable()) {
message(String("field is immutable"), errorMessage);
return 0;
}
if(&from==value.get()) return 0;
if(len<1) return 0;
size_t length = getLength();
size_t capacity = getCapacity();
if(offset+len > length) {
size_t newlength = offset + len;
if(newlength>capacity) {
setCapacity(newlength);
capacity = getCapacity();
newlength = capacity;
len = newlength - offset;
if(len<=0) return 0;
}
length = newlength;
setLength(length);
}
PVStructurePtrArray *to = value.get();
StructureConstPtr structure = structureArray->getStructure();
for(size_t i=0; i<len; i++) {
PVStructurePtr frompv = from[i+fromOffset];
if(frompv.get()!=NULL) {
if(frompv->getStructure()!=structure) {
throw std::invalid_argument(String(
"Element is not a compatible structure"));
}
}
(*to)[i+offset] = frompv;
}
postPut();
setLength(length);
return len;
}
void PVStructureArray::shareData(
std::tr1::shared_ptr<std::vector<PVStructurePtr> > const & sharedValue,
std::size_t capacity,
std::size_t length)
{
value = sharedValue;
setCapacityLength(capacity,length);
}
void PVStructureArray::serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher) const {
serialize(pbuffer, pflusher, 0, getLength());
}
void PVStructureArray::deserialize(ByteBuffer *pbuffer,
DeserializableControl *pcontrol) {
size_t size = SerializeHelper::readSize(pbuffer, pcontrol);
if(size>=0) {
// prepare array, if necessary
if(size>getCapacity()) setCapacity(size);
setLength(size);
PVStructurePtrArray *pvArray = value.get();
for(size_t i = 0; i<size; i++) {
pcontrol->ensureData(1);
size_t temp = pbuffer->getByte();
if(temp==0) {
(*pvArray)[i].reset();
}
else {
if((*pvArray)[i].get()==NULL) {
StructureConstPtr structure = structureArray->getStructure();
(*pvArray)[i] = getPVDataCreate()->createPVStructure(structure);
}
(*pvArray)[i]->deserialize(pbuffer, pcontrol);
}
}
postPut();
}
}
void PVStructureArray::serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher, size_t offset, size_t count) const {
// cache
size_t length = getLength();
// check bounds
if(offset<0)
offset = 0;
else if(offset>length) offset = length;
if(count<0) count = length;
size_t maxCount = length-offset;
if(count>maxCount) count = maxCount;
PVStructurePtrArray pvArray = *value.get();
// write
SerializeHelper::writeSize(count, pbuffer, pflusher);
for(size_t i = 0; i<count; i++) {
if(pbuffer->getRemaining()<1) pflusher->flushSerializeBuffer();
PVStructurePtr pvStructure = pvArray[i+offset];
if(pvStructure.get()==NULL) {
pbuffer->putByte(0);
}
else {
pbuffer->putByte(1);
pvStructure->serialize(pbuffer, pflusher);
}
}
}
}}

View File

@@ -1,768 +0,0 @@
/* convert.h */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* Author - Marty Kraimer
*/
/**
* @author mrk
*/
#ifndef CONVERT_H
#define CONVERT_H
#include <string>
#include <stdexcept>
#include <pv/pvIntrospect.h>
#include <pv/pvData.h>
#include <vector>
namespace epics { namespace pvData {
bool operator==(PVField&, PVField&);
static inline bool operator!=(PVField& a, PVField& b)
{return !(a==b);}
bool operator==(const Field&, const Field&);
bool operator==(const Scalar&, const Scalar&);
bool operator==(const ScalarArray&, const ScalarArray&);
bool operator==(const Structure&, const Structure&);
bool operator==(const StructureArray&, const StructureArray&);
static inline bool operator!=(const Field& a, const Field& b)
{return !(a==b);}
static inline bool operator!=(const Scalar& a, const Scalar& b)
{return !(a==b);}
static inline bool operator!=(const ScalarArray& a, const ScalarArray& b)
{return !(a==b);}
static inline bool operator!=(const Structure& a, const Structure& b)
{return !(a==b);}
static inline bool operator!=(const StructureArray& a, const StructureArray& b)
{return !(a==b);}
/**
* Convert between numeric types, convert any field to a string,
* or convert from a string to a scalar field.
* <p>Numeric conversions are between scalar numeric types or between arrays of
* numeric types. It is not possible to convert between a scalar
* and an array.
* Numeric conversions are between types:
* pvByte, pvShort, pvInt, pvLong,
* pvUByte, pvUShort, pvUInt, pvULong,
* pvFloat, or pvDouble.</p>
*
* <p>getString converts any supported type to a String.
* Code that implements a PVField interface should implement
* method toString by calling this method.</p>
*
* <p>fromString converts a String to a scalar.
* fromStringArray converts an array of Strings
* to a pvArray, which must have a scaler element type.
* A scalar field is a numeric field or pvBoolean or pvString.</p>
* <p>All from methods put data into a PVField, e.g. from means where the PVField gets it's data.</p>
*/
class Convert;
typedef std::tr1::shared_ptr<Convert> ConvertPtr;
class Convert {
public:
static ConvertPtr getConvert();
~Convert();
/**
* Get the full fieldName for the pvField.
* @param builder The builder that will have the result.
* @param pvField The pvField.
*/
void getFullName(StringBuilder buf,PVFieldPtr const & pvField);
/**
* Do fields have the same definition.
*
* @param First field
* @param Second field
* @return (false, true) if the fields (are not, are) the same.
*/
bool equals(PVFieldPtr const &a,PVFieldPtr const &b);
/**
* Do fields have the same definition.
*
* @param First field
* @param Second field
* @return (false, true) if the fields (are not, are) the same.
*/
bool equals(PVField &a,PVField &b);
/**
* Convert a PVField to a string.
* @param buf buffer for the result
* @param pv a PVField to convert to a string.
* If a PVField is a structure or array be prepared for a very long string.
* @param indentLevel indentation level
*/
void getString(StringBuilder buf,PVFieldPtr const & pvField,int indentLevel);
/**
* Convert a PVField to a string.
* param buf buffer for the result
* @param pv The PVField to convert to a string.
* If the PVField is a structure or array be prepared for a very long string.
*/
void getString(StringBuilder buf,PVFieldPtr const & pvField);
/**
* Convert a PVField to a string.
* @param buf buffer for the result
* @param pv a PVField to convert to a string.
* If a PVField is a structure or array be prepared for a very long string.
* @param indentLevel indentation level
*/
void getString(StringBuilder buf,PVField const * pvField,int indentLevel);
/**
* Convert a PVField to a string.
* param buf buffer for the result
* @param pv The PVField to convert to a string.
* If the PVField is a structure or array be prepared for a very long string.
*/
void getString(StringBuilder buf,PVField const * pvField);
/**
* Convert from an array of String to a PVScalar
* @param pv The PV.
* @param from The array of String value to convert and put into a PV.
* @param fromStartIndex The first element if the array of strings.
* @throws std::logic_error if the array of String does not have a valid values.
*/
std::size_t fromString(
PVStructurePtr const &pv,
StringArray const & from,
std::size_t fromStartIndex = 0);
/**
* Convert from a String to a PVScalar
* @param pv The PV.
* @param from The String value to convert and put into a PV.
* @throws std::logic_error if the String does not have a valid value.
*/
void fromString(PVScalarPtr const & pv, String const & from);
/**
* Convert from a String to a PVScalarArray.
* The String must be a comma separated set of values optionally enclosed in []
* @param pv The PV.
* @param from The String value to convert and put into a PV.
* @return The number of elements converted.
* @throws std::invalid_argument if the element Type is not a scalar.
* @throws std::logic_error if the String does not have a valid array values.
*/
std::size_t fromString(PVScalarArrayPtr const & pv, String from);
/**
* Convert a PVScalarArray from a String array.
* The array element type must be a scalar.
* @param pv The PV.
* @param offset Starting element in a PV.
* @param length The number of elements to transfer.
* @param from The array of values to put into the PV.
* @param fromOffset Starting element in the source array.
* @return The number of elements converted.
* @throws std::invalid_argument if the element Type is not a scalar.
* @throws std::logic_error if the String does not have a valid value.
*/
std::size_t fromStringArray(
PVScalarArrayPtr const & pv,
std::size_t offset, std::size_t length,
StringArray const & from,
std::size_t fromOffset);
/**
* Convert a PVScalarArray to a String array.
* @param pv The PV.
* @param offset Starting element in the PV array.
* @param length Number of elements to convert to the string array.
* @param to String array to receive the converted PV data.
* @param toOffset Starting element in the string array.
* @return Number of elements converted.
*/
std::size_t toStringArray(PVScalarArrayPtr const & pv,
std::size_t offset,
std::size_t length,
StringArray & to,
std::size_t toOffset);
/**
* Are from and to valid arguments to copy.
* This first checks of both arguments have the same Type.
* Then calls one of isCopyScalarCompatible,
* isCopyArrayCompatible, or isCopyStructureCompatible.
* @param from The source.
* @param to The destination.
* @return (false,true) is the arguments (are not, are) compatible.
*/
bool isCopyCompatible(FieldConstPtr const & from, FieldConstPtr const & to);
/**
* Copy from a PVField to another PVField.
* This calls one on copyScalar, copyArray, copyStructure.
* The two arguments must be compatible.
* @param from The source.
* @param to The destination
* @throws std::invalid_argument if the arguments are not compatible.
*/
void copy(PVFieldPtr const & from, PVFieldPtr const & to);
/**
* Are from and to valid arguments to copyScalar.
* false will be returned if either argument is not a scalar as defined by Type.isScalar().
* If both are scalars the return value is true if any of the following are true.
* <ul>
* <li>Both arguments are numeric.</li>
* <li>Both arguments have the same type.</li>
* <li>Either argument is a string.</li>
* </ul>
* @param from The introspection interface for the from data.
* @param to The introspection interface for the to data..
* @return (false,true) If the arguments (are not, are) compatible.
*/
bool isCopyScalarCompatible(
ScalarConstPtr const & from,
ScalarConstPtr const & to);
/**
* Copy from a scalar pv to another scalar pv.
* @param from the source.
* @param to the destination.
* @throws std::invalid_argument if the arguments are not compatible.
*/
void copyScalar(PVScalarPtr const & from, PVScalarPtr const & to);
/**
* Are from and to valid arguments to copyArray.
* The results are like isCopyScalarCompatible except that the tests are made on the elementType.
* @param from The from array.
* @param to The to array.
* @return (false,true) If the arguments (are not, are) compatible.
*/
bool isCopyScalarArrayCompatible(
ScalarArrayConstPtr const & from,
ScalarArrayConstPtr const & to);
/**
* Convert from a source PV array to a destination PV array.
* @param from The source array.
* @param offset Starting element in the source.
* @param to The destination array.
* @param toOffset Starting element in the array.
* @param length Number of elements to transfer.
* @return Number of elements converted.
* @throws std::invalid_argument if the arguments are not compatible.
*/
std::size_t copyScalarArray(
PVScalarArrayPtr const & from,
std::size_t offset,
PVScalarArrayPtr const & to,
std::size_t toOffset,
std::size_t length);
/**
* Are from and to valid arguments for copyStructure.
* They are only compatible if they have the same Structure description.
* @param from from structure.
* @param to structure.
* @return (false,true) If the arguments (are not, are) compatible.
*/
bool isCopyStructureCompatible(
StructureConstPtr const & from, StructureConstPtr const & to);
/**
* Copy from a structure pv to another structure pv.
* NOTE: Only compatible nodes are copied. This means:
* <ul>
* <li>For scalar nodes this means that isCopyScalarCompatible is true.</li>
* <li>For array nodes this means that isCopyArrayCompatible is true.</li>
* <li>For structure nodes this means that isCopyStructureCompatible is true.</li>
* <li>Link nodes are not copied.</li>
* </ul>
* @param from The source.
* @param to The destination.
* @throws std::invalid_argument if the arguments are not compatible.
*/
void copyStructure(PVStructurePtr const & from, PVStructurePtr const & to);
/**
* Are from and to valid for copyStructureArray.
* @param from The from StructureArray.
* @param to The to StructureArray.
* @return (false,true) If the arguments (are not, are) compatible.
*/
bool isCopyStructureArrayCompatible(
StructureArrayConstPtr const & from, StructureArrayConstPtr const & to);
/**
* Copy from a structure array to another structure array.
* @param from The source array.
* @param to The destination array.
*/
void copyStructureArray(
PVStructureArrayPtr const & from, PVStructureArrayPtr const & to);
/**
* Convert a PV to a <byte>.
* @param pv a PV
* @return converted value
*/
int8 toByte(PVScalarPtr const & pv);
/**
* Convert a PV to a short.
* @param pv a PV
* @return converted value
* @throws std::invalid_argument if the Type is not a numeric scalar
*/
int16 toShort(PVScalarPtr const & pv);
/**
* Convert a PV to a int.
* @param pv a PV
* @return converted value
* @throws std::invalid_argument if the Type is not a numeric scalar
*/
int32 toInt(PVScalarPtr const & pv);
/**
* Convert a PV to an long
* @param pv a PV
* @return converted value
* @throws std::invalid_argument if the Type is not a numeric scalar
*/
int64 toLong(PVScalarPtr const & pv);
/**
* Convert a PV to a ubyte.
* @param pv a PV
* @return converted value
*/
uint8 toUByte(PVScalarPtr const & pv);
/**
* Convert a PV to a ushort.
* @param pv a PV
* @return converted value
* @throws std::invalid_argument if the Type is not a numeric scalar
*/
uint16 toUShort(PVScalarPtr const & pv);
/**
* Convert a PV to a uint.
* @param pv a PV
* @return converted value
* @throws std::invalid_argument if the Type is not a numeric scalar
*/
uint32 toUInt(PVScalarPtr const & pv);
/**
* Convert a PV to an ulong
* @param pv a PV
* @return converted value
* @throws std::invalid_argument if the Type is not a numeric scalar
*/
uint64 toULong(PVScalarPtr const & pv);
/**
* Convert a PV to a float
* @param pv a PV
* @return converted value
* @throws std::invalid_argument if the Type is not a numeric scalar
*/
float toFloat(PVScalarPtr const & pv);
/**
* Convert a PV to a double
* @param pv a PV
* @return converted value
* @throws std::invalid_argument if the Type is not a numeric scalar
*/
double toDouble(PVScalarPtr const & pv);
/**
* Convert a PV to a String
* @param pv a PV
* @return converted value
*/
String toString(PVScalarPtr const & pv);
/**
* Convert a PV from a byte
* @param pv a PV
* @param from value to put into PV
* @throws std::invalid_argument if the Type is not a numeric scalar
*/
void fromByte(PVScalarPtr const & pv,int8 from);
/**
* Convert a PV from a short
* @param pv a PV
* @param from value to put into PV
* @throws std::invalid_argument if the Type is not a numeric scalar
*/
void fromShort(PVScalarPtr const & pv,int16 from);
/**
* Convert a PV from an int
* @param pv a PV
* @param from value to put into PV
* @throws std::invalid_argument if the Type is not a numeric scalar
*/
void fromInt(PVScalarPtr const & pv, int32 from);
/**
* Convert a PV from a long
* @param pv a PV
* @param from value to put into PV
* @throws std::invalid_argument if the Type is not a numeric scalar
*/
void fromLong(PVScalarPtr const & pv, int64 from);
/**
* Convert a PV from a ubyte
* @param pv a PV
* @param from value to put into PV
* @throws std::invalid_argument if the Type is not a numeric scalar
*/
void fromUByte(PVScalarPtr const & pv,uint8 from);
/**
* Convert a PV from a ushort
* @param pv a PV
* @param from value to put into PV
* @throws std::invalid_argument if the Type is not a numeric scalar
*/
void fromUShort(PVScalarPtr const & pv,uint16 from);
/**
* Convert a PV from an uint
* @param pv a PV
* @param from value to put into PV
* @throws std::invalid_argument if the Type is not a numeric scalar
*/
void fromUInt(PVScalarPtr const & pv, uint32 from);
/**
* Convert a PV from a ulong
* @param pv a PV
* @param from value to put into PV
* @throws std::invalid_argument if the Type is not a numeric scalar
*/
void fromULong(PVScalarPtr const & pv, uint64 from);
/**
* Convert a PV from a float
* @param pv a PV
* @param from value to put into PV
* @throws std::invalid_argument if the Type is not a numeric scalar
*/
void fromFloat(PVScalarPtr const & pv, float from);
/**
* Convert a PV from a double
* @param pv a PV
* @param from value to put into PV
* @throws std::invalid_argument if the Type is not a numeric scalar
*/
void fromDouble(PVScalarPtr const & pv, double from);
/**
* Convert a PV array to a byte array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param to where to put the PV data
* @param toOffset starting element in the array
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t toByteArray(PVScalarArrayPtr const & pv,
std::size_t offset,
std::size_t length,
int8* to,
std::size_t toOffset);
/**
* Convert a PV array to a short array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param to where to put the PV data
* @param toOffset starting element in the array
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t toShortArray(PVScalarArrayPtr const & pv,
std::size_t offset,
std::size_t length,
int16* to,
std::size_t toOffset);
/**
* Convert a PV array to an int array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param to where to put the PV data
* @param toOffset starting element in the array
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t toIntArray(PVScalarArrayPtr const & pv,
std::size_t offset,
std::size_t length,
int32* to,
std::size_t toOffset);
/**
* Convert a PV array to a long array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param to where to put the PV data
* @param toOffset starting element in the array
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t toLongArray(PVScalarArrayPtr const & pv,
std::size_t offset,
std::size_t length,
int64* to,
std::size_t toOffset);
/**
* Convert a PV array to a ubyte array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param to where to put the PV data
* @param toOffset starting element in the array
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t toUByteArray(PVScalarArrayPtr const & pv,
std::size_t offset,
std::size_t length,
uint8* to,
std::size_t toOffset);
/**
* Convert a PV array to a ushort array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param to where to put the PV data
* @param toOffset starting element in the array
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t toUShortArray(PVScalarArrayPtr const & pv,
std::size_t offset,
std::size_t length,
uint16* to,
std::size_t toOffset);
/**
* Convert a PV array to an uint array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param to where to put the PV data
* @param toOffset starting element in the array
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t toUIntArray(
PVScalarArrayPtr const & pv,
std::size_t offset,
std::size_t length,
uint32* to,
std::size_t toOffset);
/**
* Convert a PV array to a ulong array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param to where to put the PV data
* @param toOffset starting element in the array
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t toULongArray(
PVScalarArrayPtr const & pv,
std::size_t offset,
std::size_t length,
uint64* to,
std::size_t toOffset);
/**
* Convert a PV array to a float array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param to where to put the PV data
* @param toOffset starting element in the array
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t toFloatArray(
PVScalarArrayPtr const & pv,
std::size_t offset,
std::size_t length,
float* to,
std::size_t toOffset);
/**
* Convert a PV array to a double array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param to where to put the PV data
* @param toOffset starting element in the array
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t toDoubleArray(
PVScalarArrayPtr const & pv,
std::size_t offset,
std::size_t length,
double* to, std::size_t
toOffset);
/**
* Convert a PV array from a byte array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param from value to put into PV
* @param fromOffset
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t fromByteArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const int8* from, std::size_t fromOffset);
std::size_t fromByteArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const ByteArray & from, std::size_t fromOffset);
/**
* Convert a PV array from a short array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param from value to put into PV
* @param fromOffset starting element in the source array
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t fromShortArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const int16* from, std::size_t fromOffset);
std::size_t fromShortArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const ShortArray & from, std::size_t fromOffset);
/**
* Convert a PV array from an int array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param from value to put into PV
* @param fromOffset starting element in the source array
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t fromIntArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const int32* from, std::size_t fromOffset);
std::size_t fromIntArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const IntArray & from, std::size_t fromOffset);
/**
* Convert a PV array from a long array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param from value to put into PV
* @param fromOffset starting element in the source array
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t fromLongArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const int64* from, std::size_t fromOffset);
std::size_t fromLongArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const LongArray & from, std::size_t fromOffset);
/**
* Convert a PV array from a ubyte array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param from value to put into PV
* @param fromOffset
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t fromUByteArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const uint8* from, std::size_t fromOffset);
std::size_t fromUByteArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const UByteArray & from, std::size_t fromOffset);
/**
* Convert a PV array from a ushort array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param from value to put into PV
* @param fromOffset starting element in the source array
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t fromUShortArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const uint16* from, std::size_t fromOffset);
std::size_t fromUShortArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const UShortArray & from, std::size_t fromOffset);
/**
* Convert a PV array from an uint array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param from value to put into PV
* @param fromOffset starting element in the source array
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t fromUIntArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const uint32* from, std::size_t fromOffset);
std::size_t fromUIntArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const UIntArray & from, std::size_t fromOffset);
/**
* Convert a PV array from a ulong array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param from value to put into PV
* @param fromOffset starting element in the source array
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t fromULongArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const uint64* from, std::size_t fromOffset);
std::size_t fromULongArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const ULongArray & from, std::size_t fromOffset);
/**
* Convert a PV array from a float array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param from value to put into PV
* @param fromOffset starting element in the source array
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t fromFloatArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const float* from, std::size_t fromOffset);
std::size_t fromFloatArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const FloatArray & from, std::size_t fromOffset);
/**
* Convert a PV array from a double array.
* @param pv a PV
* @param offset starting element in a PV
* @param length number of elements to transfer
* @param from value to put into PV
* @param fromOffset starting element in the source array
* @return number of elements converted
* @throws std::invalid_argument if the element type is not numeric
*/
std::size_t fromDoubleArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const double* from, std::size_t fromOffset);
std::size_t fromDoubleArray(
PVScalarArrayPtr & pv, std::size_t offset, std::size_t length,
const DoubleArray & from, std::size_t fromOffset);
/**
* Convenience method for implementing toString.
* It generates a newline and inserts blanks at the beginning of the newline.
* @param builder The StringBuilder being constructed.
* @param indentLevel Indent level, Each level is four spaces.
*/
void newLine(StringBuilder buf, int indentLevel);
private:
Convert();
PVDataCreatePtr pvDataCreate;
String trueString;
String falseString;
String illegalScalarType;
};
extern ConvertPtr getConvert();
}}
#endif /* CONVERT_H */

File diff suppressed because it is too large Load Diff

View File

@@ -1,559 +0,0 @@
/* pvIntrospect.h */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk and Michael Davidsaver
*/
#ifndef PVINTROSPECT_H
#define PVINTROSPECT_H
#include <string>
#include <stdexcept>
#include <pv/noDefaultMethods.h>
#include <pv/pvType.h>
#include <pv/byteBuffer.h>
#include <pv/serialize.h>
namespace epics { namespace pvData {
class Field;
class Scalar;
class ScalarArray;
class Structure;
class StructureArray;
/**
* typedef for a shared pointer to an immutable Field.
*/
typedef std::tr1::shared_ptr<const Field> FieldConstPtr;
/**
* typedef for an array of shared pointer to an immutable Field.
*/
typedef std::vector<FieldConstPtr> FieldConstPtrArray;
/**
* typedef for a shared pointer to an immutable Scalar.
*/
typedef std::tr1::shared_ptr<const Scalar> ScalarConstPtr;
/**
* typedef for a shared pointer to an immutable ScalarArray.
*/
typedef std::tr1::shared_ptr<const ScalarArray> ScalarArrayConstPtr;
/**
* typedef for a shared pointer to an immutable Structure.
*/
typedef std::tr1::shared_ptr<const Structure> StructureConstPtr;
/**
* typedef for a shared pointer to an immutable StructureArray.
*/
typedef std::tr1::shared_ptr<const StructureArray> StructureArrayConstPtr;
/**
* Definition of support field types.
*/
enum Type {
/**
* The type is scalar. It has a scalarType
*/
scalar,
/**
* The type is scalarArray. Each element is a scalar of the same scalarType.
*/
scalarArray,
/**
* The type is structure.
*/
structure,
/**
* The type is structureArray. Each element is a structure.
*/
structureArray
};
/**
* Convenience functions for Type.
*/
namespace TypeFunc {
/**
* Get a name for the type.
* @param type The type.
* @return The name for the type.
*/
const char* name(Type type);
/**
* Convert the type to a string and add it to builder.
* @param builder The string builder.
* @param type The type.
*/
void toString(StringBuilder builder,const Type type);
};
/**
* Definition of support scalar types.
*/
enum ScalarType {
/**
* The type is boolean, i. e. value can be {@code false} or {@code true}
*/
pvBoolean,
/**
* The type is byte, i. e. a 8 bit signed integer.
*/
pvByte,
/**
* The type is short, i. e. a 16 bit signed integer.
*/
pvShort,
/**
* The type is int, i. e. a 32 bit signed integer.
*/
pvInt,
/**
* The type is long, i. e. a 64 bit signed integer.
*/
pvLong,
/**
* The type is unsigned byte, i. e. a 8 bit unsigned integer.
*/
pvUByte,
/**
* The type is unsigned short, i. e. a 16 bit unsigned integer.
*/
pvUShort,
/**
* The type is unsigned int, i. e. a 32 bit unsigned integer.
*/
pvUInt,
/**
* The type is unsigned long, i. e. a 64 bit unsigned integer.
*/
pvULong,
/**
* The type is float, i. e. 32 bit IEEE floating point,
*/
pvFloat,
/**
* The type is float, i. e. 64 bit IEEE floating point,
*/
pvDouble,
/**
* The type is string, i. e. a UTF8 character string.
*/
pvString
};
/**
* Convenience functions for ScalarType.
*/
namespace ScalarTypeFunc {
/**
* Is the type an integer, i. e. is it one of byte,...ulong
* @param scalarType The type.
* @return (false,true) if the scalarType is an integer.
*/
bool isInteger(ScalarType scalarType);
/**
* Is the type an unsigned integer, i. e. is it one of ubyte,...ulong
* @param scalarType The type.
* @return (false,true) if the scalarType is an integer.
*/
bool isUInteger(ScalarType scalarType);
/**
* Is the type numeric, i. e. is it one of byte,...,double
* @param scalarType The type.
* @return (false,true) if the scalarType is a numeric
*/
bool isNumeric(ScalarType scalarType);
/**
* Is the type primitive, i. e. not string
* @param scalarType The type.
* @return (false,true) if the scalarType is primitive.
*/
bool isPrimitive(ScalarType scalarType);
/**
* Get the scalarType for value.
* @param value The name of the scalar type.
* @return The scalarType.
* An exception is thrown if the name is not the name of a scalar type.
*/
ScalarType getScalarType(String const &value);
/**
* Get a name for the scalarType.
* @param scalarType The type.
* @return The name for the scalarType.
*/
const char* name(ScalarType scalarType);
/**
* Convert the scalarType to a string and add it to builder.
* @param builder The string builder.
* @param scalarType The type.
*/
void toString(StringBuilder builder,ScalarType scalarType);
};
/**
* This class implements introspection object for field.
*/
class Field :
virtual public Serializable,
public std::tr1::enable_shared_from_this<Field> {
public:
POINTER_DEFINITIONS(Field);
/**
* Destructor.
*/
virtual ~Field();
/**
* Get the field type.
* @return The type.
*/
Type getType() const{return m_fieldType;}
/**
* Get the identification string.
* @return The identification string, can be empty.
*/
virtual String getID() const = 0;
/**
* Convert the scalarType to a string and add it to builder.
* @param builder The string builder.
*/
virtual void toString(StringBuilder builder) const{toString(builder,0);}
/**
* Convert the scalarType to a string and add it to builder.
* @param builder The string builder.
* @param indentLevel The number of blanks at the beginning of new lines.
*/
virtual void toString(StringBuilder builder,int indentLevel) const;
protected:
/**
* Constructor
* @param fieldName The field type.
*/
Field(Type type);
private:
Type m_fieldType;
friend class StructureArray;
friend class Structure;
friend class PVFieldPvt;
friend class StandardField;
friend class BasePVStructureArray;
friend class FieldCreate;
struct Deleter{void operator()(Field *p){delete p;}};
};
/**
* This class implements introspection object for Scalar.
*/
class Scalar : public Field{
public:
POINTER_DEFINITIONS(Scalar);
/**
* Destructor.
*/
virtual ~Scalar();
typedef Scalar& reference;
typedef const Scalar& const_reference;
/**
* Get the scalarType
* @return the scalarType
*/
ScalarType getScalarType() const {return scalarType;}
/**
* Convert the scalar to a string and add it to builder.
* @param builder The string builder.
*/
virtual void toString(StringBuilder buf) const{toString(buf,0);}
/**
* Convert the scalar to a string and add it to builder.
* @param builder The string builder.
* @param indentLevel The number of blanks at the beginning of new lines.
*/
virtual void toString(StringBuilder buf,int indentLevel) const;
virtual String getID() const;
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
protected:
Scalar(ScalarType scalarType);
private:
const int8 getTypeCodeLUT() const;
ScalarType scalarType;
friend class FieldCreate;
};
/**
* This class implements introspection object for field.
*/
class ScalarArray : public Field{
public:
POINTER_DEFINITIONS(ScalarArray);
typedef ScalarArray& reference;
typedef const ScalarArray& const_reference;
/**
* Constructor
* @param scalarType The scalarType for the field.
*/
ScalarArray(ScalarType scalarType);
/**
* Get the scalarType for the elements.
* @return the scalarType
*/
ScalarType getElementType() const {return elementType;}
/**
* Convert the scalarType to a string and add it to builder.
* @param builder The string builder.
*/
virtual void toString(StringBuilder buf) const{toString(buf,0);}
/**
* Convert the scalarType to a string and add it to builder.
* @param builder The string builder.
* @param indentLevel The number of blanks at the beginning of new lines.
*/
virtual void toString(StringBuilder buf,int indentLevel) const;
virtual String getID() const;
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
protected:
/**
* Destructor.
*/
virtual ~ScalarArray();
private:
const int8 getTypeCodeLUT() const;
const String getIDScalarArrayLUT() const;
ScalarType elementType;
friend class FieldCreate;
};
/**
* This class implements introspection object for a structureArray
*/
class StructureArray : public Field{
public:
POINTER_DEFINITIONS(StructureArray);
typedef StructureArray& reference;
typedef const StructureArray& const_reference;
/**
* Get the introspection interface for the array elements.
* @return The introspection interface.
*/
StructureConstPtr getStructure() const {return pstructure;}
/**
* Convert the scalarType to a string and add it to builder.
* @param builder The string builder.
* @param indentLevel The number of blanks at the beginning of new lines.
*/
virtual void toString(StringBuilder buf,int indentLevel=0) const;
virtual String getID() const;
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
protected:
/**
* Constructor.
* @param structure The introspection interface for the elements.
*/
StructureArray(StructureConstPtr const & structure);
/**
* Destructor.
*/
virtual ~StructureArray();
private:
StructureConstPtr pstructure;
friend class FieldCreate;
};
/**
* This class implements introspection object for a structure.
*/
class Structure : public Field {
public:
POINTER_DEFINITIONS(Structure);
/**
* Default structure ID.
*/
static epics::pvData::String DEFAULT_ID;
/**
* Destructor.
*/
virtual ~Structure();
typedef Structure& reference;
typedef const Structure& const_reference;
/**
* Get the number of immediate subfields in the structure/
* @return The number of fields.
*/
std::size_t getNumberFields() const {return fieldNames.size();}
/**
* Get the field for the specified fieldName.
* @param fieldName The name of the field to get;
* @return The introspection interface.
* This will hold a null pointer if the field is not in the structure.
*/
FieldConstPtr getField(String const &fieldName) const;
/**
* Get the field for the specified fieldName.
* @param fieldName The index of the field to get;
* @return The introspection interface.
* This will hold a null pointer if the field is not in the structure.
*/
FieldConstPtr getField(std::size_t index) const {return fields[index];}
/**
* Get the field index for the specified fieldName.
* @return The introspection interface.
* This will be -1 if the field is not in the structure.
*/
std::size_t getFieldIndex(String const &fieldName) const;
/**
* Get the fields in the structure.
* @return The array of fields.
*/
FieldConstPtrArray const & getFields() const {return fields;}
/**
* Get the names of the fields in the structure.
* @return The array of fieldNames.
*/
StringArray const & getFieldNames() const {return fieldNames;}
void renameField(std::size_t fieldIndex,String const & newName)
{fieldNames[fieldIndex] = newName;}
/**
* Get the name of the field with the specified index;
* @param fieldIndex The index of the desired field.
* @return The fieldName.
*/
String getFieldName(std::size_t fieldIndex){return fieldNames[fieldIndex];}
/**
* Convert the structure to a string and add it to builder.
* @param builder The string builder.
*/
virtual void toString(StringBuilder buf) const{toString(buf,0);}
/**
* Convert the structure to a string and add it to builder.
* @param builder The string builder.
* @param indentLevel The number of blanks at the beginning of new lines.
*/
virtual void toString(StringBuilder buf,int indentLevel) const;
virtual String getID() const;
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
protected:
Structure(StringArray const & fieldNames, FieldConstPtrArray const & fields, String const & id = DEFAULT_ID);
private:
void toStringCommon(StringBuilder buf,int indentLevel) const;
StringArray fieldNames;
FieldConstPtrArray fields;
String id;
friend class FieldCreate;
};
/**
* This is a singlton class for creating introspection interfaces.
*/
class FieldCreate;
typedef std::tr1::shared_ptr<FieldCreate> FieldCreatePtr;
class FieldCreate {
public:
static FieldCreatePtr getFieldCreate();
/**
* Create a {@code ScalarField}.
* @param scalarType The scalar type.
* @return a {@code Scalar} interface for the newly created object.
* @throws An {@code IllegalArgumentException} if an illegal type is specified.
*/
ScalarConstPtr createScalar(ScalarType scalarType) const;
/**
* Create an {@code Array} field.
* @param elementType The {@code scalarType} for array elements
* @return An {@code Array} Interface for the newly created object.
*/
ScalarArrayConstPtr createScalarArray(ScalarType elementType) const;
/**
* Create an {@code Array} field that is has element type <i>Structure</i>
* @param fieldName The field name
* @param elementStructure The {@code Structure} for each array element.
* @return An {@code Array} Interface for the newly created object.
*/
StructureArrayConstPtr createStructureArray(StructureConstPtr const & structure) const;
/**
* Create a {@code Structure} field.
* @param fieldNames The array of {@code fieldNames} for the structure.
* @param fields The array of {@code fields} for the structure.
* @return a {@code Structure} interface for the newly created object.
*/
StructureConstPtr createStructure (
StringArray const & fieldNames,
FieldConstPtrArray const & fields) const;
/**
* Create a {@code Structure} field with identification string.
* @param id The identification string for the structure.
* @param fieldNames The array of {@code fieldNames} for the structure.
* @param fields The array of {@code fields} for the structure.
* @return a {@code Structure} interface for the newly created object.
*/
StructureConstPtr createStructure (
String const & id,
StringArray const & fieldNames,
FieldConstPtrArray const & fields) const;
/**
* Append a field to a structure.
* @param structure The structure to which the field is appended.
* @param fieldName The name of the field.
* @param field The field.
* @return a {@code Structure} interface for the newly created object.
*/
StructureConstPtr appendField(
StructureConstPtr const & structure,
String const & fieldName, FieldConstPtr const & field) const;
/**
* Append fields to a structure.
* @param structure The structure to which the fields appended.
* @param fieldName The names of the fields.
* @param field The fields.
* @return a {@code Structure} interface for the newly created object.
*/
StructureConstPtr appendFields(
StructureConstPtr const & structure,
StringArray const & fieldNames,
FieldConstPtrArray const & fields) const;
/**
* Deserialize {@code Field} instance from given byte buffer.
* @param buffer Buffer containing serialized {@code Field} instance.
* @param control Deserialization control instance.
* @return a deserialized {@code Field} instance.
*/
FieldConstPtr deserialize(ByteBuffer* buffer, DeserializableControl* control) const;
private:
FieldCreate();
};
/**
* Get the single class that implemnents FieldCreate,
* @param The fieldCreate factory.
*/
extern FieldCreatePtr getFieldCreate();
}}
#endif /* PVINTROSPECT_H */

View File

@@ -1,452 +0,0 @@
/* pvType.h */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
*/
/* Definitions for the primitive types for pvData.
* It also defines the arrays of the primitive types
*/
#ifndef PVTYPE_H
#define PVTYPE_H
#include <string>
#include <vector>
#ifdef __vxworks
typedef int intptr_t;
typedef unsigned int uintptr_t;
#define INT64_MAX (0x7fffffffffffffffLL)
#define UINT64_MAX (0xffffffffffffffffLL)
#else
#include <stdint.h>
#endif
#include <pv/sharedPtr.h>
#include <pv/localStaticLock.h>
namespace epics { namespace pvData {
/**
* This is a set of typdefs used by pvData.
*/
/**
* boolean, i.e. can only have the values {@code false} or {@code true}
*/
typedef uint8_t boolean;
/**
* A 8 bit signed integer
*/
typedef int8_t int8;
/**
* A 16 bit signed integer
*/
typedef int16_t int16;
/**
* A 32 bit signed integer
*/
typedef int32_t int32;
/**
* A 64 bit signed integer
*/
typedef int64_t int64;
/**
* A 8 bit unsigned integer
*/
typedef uint8_t uint8;
/**
* A 16 bit unsigned integer
*/
typedef uint16_t uint16;
/**
* A 32 bit unsigned integer
*/
typedef uint32_t uint32;
/**
* A 64 bit unsigned integer
*/
typedef uint64_t uint64;
// float and double are types
/**
* A string
*/
typedef std::string String;
/**
* A boolean array.
*/
typedef std::vector<uint8> BooleanArray;
typedef std::tr1::shared_ptr<BooleanArray> BooleanArrayPtr;
/* get is same is ubyte*/
typedef std::vector<uint8>::iterator BooleanArray_iterator;
typedef std::vector<uint8>::const_iterator BooleanArray_const_iterator;
/**
* A byte array.
*/
typedef std::vector<int8> ByteArray;
typedef std::tr1::shared_ptr<ByteArray> ByteArrayPtr;
inline int8 * get(ByteArray &value)
{
return &value[0];
}
inline int8 const * get(ByteArray const &value)
{
return static_cast<int8 const *>(&value[0]);
}
inline int8 * get(ByteArrayPtr &value)
{
return get(*value.get());
}
inline int8 const * get(ByteArrayPtr const &value)
{
return get(*value.get());
}
inline ByteArray & getVector(ByteArrayPtr &value)
{
return *value.get();
}
inline ByteArray const & getVector(ByteArrayPtr const &value)
{
return *value.get();
}
typedef std::vector<int8>::iterator ByteArray_iterator;
typedef std::vector<int8>::const_iterator ByteArray_const_iterator;
/**
* A short array.
*/
typedef std::vector<int16> ShortArray;
typedef std::tr1::shared_ptr<ShortArray> ShortArrayPtr;
inline int16 * get(ShortArray &value)
{
return &value[0];
}
inline int16 const * get(ShortArray const &value)
{
return static_cast<int16 const *>(&value[0]);
}
inline int16 * get(ShortArrayPtr &value)
{
return get(*value.get());
}
inline int16 const * get(ShortArrayPtr const &value)
{
return get(*value.get());
}
inline ShortArray & getVector(ShortArrayPtr &value)
{
return *value.get();
}
inline ShortArray const & getVector(ShortArrayPtr const &value)
{
return *value.get();
}
typedef std::vector<int16>::iterator ShortArray_iterator;
typedef std::vector<int16>::const_iterator ShortArray_const_iterator;
/**
* A int array.
*/
typedef std::vector<int32> IntArray;
typedef std::tr1::shared_ptr<IntArray> IntArrayPtr;
inline int32 * get(IntArray &value)
{
return &value[0];
}
inline int32 const * get(IntArray const &value)
{
return static_cast<int32 const *>(&value[0]);
}
inline int32 * get(IntArrayPtr &value)
{
return get(*value.get());
}
inline int32 const * get(IntArrayPtr const &value)
{
return get(*value.get());
}
inline IntArray & getVector(IntArrayPtr &value)
{
return *value.get();
}
inline IntArray const & getVector(IntArrayPtr const &value)
{
return *value.get();
}
typedef std::vector<int32>::iterator IntArray_iterator;
typedef std::vector<int32>::const_iterator IntArray_const_iterator;
/**
* A long array.
*/
typedef std::vector<int64> LongArray;
typedef std::tr1::shared_ptr<LongArray> LongArrayPtr;
inline int64 * get(LongArray &value)
{
return &value[0];
}
inline int64 const * get(LongArray const &value)
{
return static_cast<int64 const *>(&value[0]);
}
inline int64 * get(LongArrayPtr &value)
{
return get(*value.get());
}
inline int64 const * get(LongArrayPtr const &value)
{
return get(*value.get());
}
inline LongArray & getVector(LongArrayPtr &value)
{
return *value.get();
}
inline LongArray const & getVector(LongArrayPtr const &value)
{
return *value.get();
}
typedef std::vector<int64>::iterator LongArray_iterator;
typedef std::vector<int64>::const_iterator LongArray_const_iterator;
/**
* An unsigned byte array.
*/
typedef std::vector<uint8> UByteArray;
typedef std::tr1::shared_ptr<UByteArray> UByteArrayPtr;
inline uint8 * get(UByteArray &value)
{
return &value[0];
}
inline uint8 const * get(UByteArray const &value)
{
return static_cast<uint8 const *>(&value[0]);
}
inline uint8 * get(UByteArrayPtr &value)
{
return get(*value.get());
}
inline uint8 const * get(UByteArrayPtr const &value)
{
return get(*value.get());
}
inline UByteArray & getVector(UByteArrayPtr &value)
{
return *value.get();
}
inline UByteArray const & getVector(UByteArrayPtr const &value)
{
return *value.get();
}
typedef std::vector<uint8>::iterator UByteArray_iterator;
typedef std::vector<uint8>::const_iterator UByteArray_const_iterator;
/**
* An unsigned short array.
*/
typedef std::vector<uint16> UShortArray;
typedef std::tr1::shared_ptr<UShortArray> UShortArrayPtr;
inline uint16 * get(UShortArray &value)
{
return &value[0];
}
inline uint16 const * get(UShortArray const &value)
{
return static_cast<uint16 const *>(&value[0]);
}
inline uint16 * get(UShortArrayPtr &value)
{
return get(*value.get());
}
inline uint16 const * get(UShortArrayPtr const &value)
{
return get(*value.get());
}
inline UShortArray & getVector(UShortArrayPtr &value)
{
return *value.get();
}
inline UShortArray const & getVector(UShortArrayPtr const &value)
{
return *value.get();
}
typedef std::vector<uint16>::iterator UShortArray_iterator;
typedef std::vector<uint16>::const_iterator UShortArray_const_iterator;
/**
* An unsigned int array.
*/
typedef std::vector<uint32> UIntArray;
typedef std::tr1::shared_ptr<UIntArray> UIntArrayPtr;
inline uint32 * get(UIntArray &value)
{
return &value[0];
}
inline uint32 const * get(UIntArray const &value)
{
return static_cast<uint32 const *>(&value[0]);
}
inline uint32 * get(UIntArrayPtr &value)
{
return get(*value.get());
}
inline uint32 const * get(UIntArrayPtr const &value)
{
return get(*value.get());
}
inline UIntArray & getVector(UIntArrayPtr &value)
{
return *value.get();
}
inline UIntArray const & getVector(UIntArrayPtr const &value)
{
return *value.get();
}
typedef std::vector<uint32>::iterator UIntArray_iterator;
typedef std::vector<uint32>::const_iterator UIntArray_const_iterator;
/**
* An unsigned long array.
*/
typedef std::vector<uint64> ULongArray;
typedef std::tr1::shared_ptr<ULongArray> ULongArrayPtr;
inline uint64 * get(ULongArray &value)
{
return &value[0];
}
inline uint64 const * get(ULongArray const &value)
{
return static_cast<uint64 const *>(&value[0]);
}
inline uint64 * get(ULongArrayPtr &value)
{
return get(*value.get());
}
inline uint64 const * get(ULongArrayPtr const &value)
{
return get(*value.get());
}
inline ULongArray & getVector(ULongArrayPtr &value)
{
return *value.get();
}
inline ULongArray const & getVector(ULongArrayPtr const &value)
{
return *value.get();
}
typedef std::vector<uint64>::iterator ULongArray_iterator;
typedef std::vector<uint64>::const_iterator ULongArray_const_iterator;
/**
* A float array.
*/
typedef std::vector<float> FloatArray;
typedef std::tr1::shared_ptr<FloatArray> FloatArrayPtr;
inline float * get(FloatArray &value)
{
return &value[0];
}
inline float const * get(FloatArray const &value)
{
return static_cast<float const *>(&value[0]);
}
inline float * get(FloatArrayPtr &value)
{
return get(*value.get());
}
inline float const * get(FloatArrayPtr const &value)
{
return get(*value.get());
}
inline FloatArray & getVector(FloatArrayPtr &value)
{
return *value.get();
}
inline FloatArray const & getVector(FloatArrayPtr const &value)
{
return *value.get();
}
typedef std::vector<float>::iterator FloatArray_iterator;
typedef std::vector<float>::const_iterator FloatArray_const_iterator;
/**
* A double array.
*/
typedef std::vector<double> DoubleArray;
typedef std::tr1::shared_ptr<DoubleArray> DoubleArrayPtr;
inline double * get(DoubleArray &value)
{
return &value[0];
}
inline double const * get(DoubleArray const &value)
{
return static_cast<double const *>(&value[0]);
}
inline double * get(DoubleArrayPtr &value)
{
return get(*value.get());
}
inline double const * get(DoubleArrayPtr const &value)
{
return get(*value.get());
}
inline DoubleArray & getVector(DoubleArrayPtr &value)
{
return *value.get();
}
inline DoubleArray const & getVector(DoubleArrayPtr const &value)
{
return *value.get();
}
typedef std::vector<double>::iterator DoubleArray_iterator;
typedef std::vector<double>::const_iterator DoubleArray_const_iterator;
/**
* A string array.
*/
typedef std::vector<String> StringArray;
typedef std::tr1::shared_ptr<StringArray> StringArrayPtr;
inline String * get(StringArray &value)
{
return &value[0];
}
inline String const * get(StringArray const &value)
{
return static_cast<String const *>(&value[0]);
}
inline String * get(StringArrayPtr &value)
{
return get(*value.get());
}
inline String const * get(StringArrayPtr const &value)
{
return get(*value.get());
}
inline StringArray & getVector(StringArrayPtr &value)
{
return *value.get();
}
inline StringArray const & getVector(StringArrayPtr const &value)
{
return *value.get();
}
typedef std::vector<String>::iterator StringArray_iterator;
typedef std::vector<String>::const_iterator StringArray_const_iterator;
/**
* A convenience definition for toString methods
*/
typedef String * StringBuilder;
}}
#endif /* PVTYPE_H */

View File

@@ -1,130 +0,0 @@
/* standardField.h */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* Author - Marty Kraimer
*/
/**
* @author mrk
*/
#ifndef STANDARDFIELD_H
#define STANDARDFIELD_H
#include <string>
#include <stdexcept>
#include <pv/pvIntrospect.h>
namespace epics { namespace pvData {
/**
* Standard Fields is a class or creating or sharing Field objects for standard fields.
* For each type of standard object two methods are defined:s
* one with no properties and with properties
* The property field is a comma separated string of property names of the following:
* alarm, timeStamp, display, control, and valueAlarm.
* An example is "alarm,timeStamp,valueAlarm".
* The method with properties creates a structure with fields named fieldName
* and each of the property names.
* Each property field is a structure defining the property.
* The details about each property is given in the section named "Property".
* For example the call:
* {@code
StructureConstPtr example = standardField->scalar(
String("value"),
pvDouble,
String("value,alarm,timeStamp"));
* }
* Will result in a Field definition that has the form: {@code
structure example
double value
structure alarm
int severity
int status
string message
structure timeStamp
long secondsPastEpoch
int nanoSeconds
int userTag
* }
* In addition there are methods that create each of the property structures,
* i.e. the methods named: alarm, .... enumeratedAlarm."
*
* StandardField is a singleton class. The class is accessed via the statement: {@code
StandardField *standardField = getStandardField();
* }
*/
class StandardField;
typedef std::tr1::shared_ptr<StandardField> StandardFieldPtr;
class StandardField {
public:
static StandardFieldPtr getStandardField();
~StandardField();
StructureConstPtr scalar(ScalarType type,String const & properties);
StructureConstPtr scalarArray(ScalarType elementType, String const & properties);
StructureConstPtr structureArray(StructureConstPtr const & structure,String const & properties);
StructureConstPtr enumerated();
StructureConstPtr enumerated(String const & properties);
StructureConstPtr alarm();
StructureConstPtr timeStamp();
StructureConstPtr display();
StructureConstPtr control();
StructureConstPtr booleanAlarm();
StructureConstPtr byteAlarm();
StructureConstPtr ubyteAlarm();
StructureConstPtr shortAlarm();
StructureConstPtr ushortAlarm();
StructureConstPtr intAlarm();
StructureConstPtr uintAlarm();
StructureConstPtr longAlarm();
StructureConstPtr ulongAlarm();
StructureConstPtr floatAlarm();
StructureConstPtr doubleAlarm();
StructureConstPtr enumeratedAlarm();
private:
StandardField();
void init();
StructureConstPtr createProperties(String id,FieldConstPtr field,String properties);
FieldCreatePtr fieldCreate;
String notImplemented;
String valueFieldName;
StructureConstPtr alarmField;
StructureConstPtr timeStampField;
StructureConstPtr displayField;
StructureConstPtr controlField;
StructureConstPtr booleanAlarmField;
StructureConstPtr byteAlarmField;
StructureConstPtr shortAlarmField;
StructureConstPtr intAlarmField;
StructureConstPtr longAlarmField;
StructureConstPtr ubyteAlarmField;
StructureConstPtr ushortAlarmField;
StructureConstPtr uintAlarmField;
StructureConstPtr ulongAlarmField;
StructureConstPtr floatAlarmField;
StructureConstPtr doubleAlarmField;
StructureConstPtr enumeratedAlarmField;
void createAlarm();
void createTimeStamp();
void createDisplay();
void createControl();
void createBooleanAlarm();
void createByteAlarm();
void createShortAlarm();
void createIntAlarm();
void createLongAlarm();
void createUByteAlarm();
void createUShortAlarm();
void createUIntAlarm();
void createULongAlarm();
void createFloatAlarm();
void createDoubleAlarm();
void createEnumeratedAlarm();
friend StandardFieldPtr getStandardField();
};
extern StandardFieldPtr getStandardField();
}}
#endif /* STANDARDFIELD_H */

View File

@@ -1,54 +0,0 @@
/* standardPVField.h */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
*/
#ifndef STANDARDPVFIELD_H
#define STANDARDPVFIELD_H
#include <string>
#include <stdexcept>
#include <pv/pvIntrospect.h>
#include <pv/pvData.h>
#include <pv/standardField.h>
namespace epics { namespace pvData {
/**
* StandardPVField is a class or creating standard data fields.
* Like class StandardField it has two forms of the methods which create a fields:
* one without properties and one with properties.
* The properties are some combination of alarm, timeStamp, control, display, and valueAlarm.
* Just like StandardField there are methods to create the standard properties.
*
* StandardPVField is a singleton class. The class is accessed via the statement: {@code
StandardPVField *standardPVField = getStandardPVField();
* }
*/
class StandardPVField;
typedef std::tr1::shared_ptr<StandardPVField> StandardPVFieldPtr;
class StandardPVField : private NoDefaultMethods {
public:
static StandardPVFieldPtr getStandardPVField();
~StandardPVField();
PVStructurePtr scalar(ScalarType type,String const & properties);
PVStructurePtr scalarArray(ScalarType elementType, String const & properties);
PVStructurePtr structureArray(StructureConstPtr const &structure,String const & properties);
PVStructurePtr enumerated(StringArray const &choices);
PVStructurePtr enumerated(StringArray const &choices, String const & properties);
private:
StandardPVField();
StandardFieldPtr standardField;
FieldCreatePtr fieldCreate;
PVDataCreatePtr pvDataCreate;
String notImplemented;
};
extern StandardPVFieldPtr getStandardPVField();
}}
#endif /* STANDARDPVFIELD_H */

1
pvDataCPP.config Normal file
View File

@@ -0,0 +1 @@
// ADD PREDEFINED MACROS HERE!

1
pvDataCPP.creator Normal file
View File

@@ -0,0 +1 @@
[General]

211
pvDataCPP.files Normal file
View File

@@ -0,0 +1,211 @@
configure/CONFIG
configure/CONFIG_SITE
configure/RELEASE
configure/RELEASE.local
configure/RULES
configure/RULES.ioc
configure/RULES_DIRS
configure/RULES_TOP
documentation/pvDataCPP.html
documentation/pvDataCPP_20120927.html
documentation/pvDataCPP_20121001.html
documentation/pvDataCPP_20121026.html
documentation/pvDataCPP_20121212.html
jenkins/cloudbees_build
pvDataApp/factory/Compare.cpp
pvDataApp/factory/Convert.cpp
pvDataApp/factory/factory.h
pvDataApp/factory/FieldCreateFactory.cpp
pvDataApp/factory/PVArray.cpp
pvDataApp/factory/PVAuxInfoImpl.cpp
pvDataApp/factory/PVDataCreateFactory.cpp
pvDataApp/factory/PVDataCreateFactory.cpp.orig
pvDataApp/factory/PVField.cpp
pvDataApp/factory/PVScalar.cpp
pvDataApp/factory/PVScalarArray.cpp
pvDataApp/factory/PVStructure.cpp
pvDataApp/factory/PVStructureArray.cpp
pvDataApp/factory/StandardField.cpp
pvDataApp/factory/StandardPVField.cpp
pvDataApp/factory/TypeFunc.cpp
pvDataApp/misc/bitSet.cpp
pvDataApp/misc/bitSet.h
pvDataApp/misc/byteBuffer.cpp
pvDataApp/misc/byteBuffer.h
pvDataApp/misc/destroyable.h
pvDataApp/misc/epicsException.cpp
pvDataApp/misc/epicsException.h
pvDataApp/misc/event.cpp
pvDataApp/misc/event.h
pvDataApp/misc/executor.cpp
pvDataApp/misc/executor.h
pvDataApp/misc/localStaticLock.cpp
pvDataApp/misc/localStaticLock.h
pvDataApp/misc/localStaticLock.h.orig
pvDataApp/misc/lock.h
pvDataApp/misc/messageQueue.cpp
pvDataApp/misc/messageQueue.h
pvDataApp/misc/noDefaultMethods.h
pvDataApp/misc/queue.h
pvDataApp/misc/requester.cpp
pvDataApp/misc/requester.h
pvDataApp/misc/requester.h.orig
pvDataApp/misc/serialize.h
pvDataApp/misc/serializeHelper.cpp
pvDataApp/misc/serializeHelper.h
pvDataApp/misc/sharedPtr.h
pvDataApp/misc/status.cpp
pvDataApp/misc/status.h
pvDataApp/misc/thread.h
pvDataApp/misc/timeFunction.cpp
pvDataApp/misc/timeFunction.h
pvDataApp/misc/timer.cpp
pvDataApp/misc/timer.h
pvDataApp/monitor/monitor.h
pvDataApp/O.linux-x86_64/alarm.d
pvDataApp/O.linux-x86_64/bitSet.d
pvDataApp/O.linux-x86_64/bitSetUtil.d
pvDataApp/O.linux-x86_64/byteBuffer.d
pvDataApp/O.linux-x86_64/Compare.d
pvDataApp/O.linux-x86_64/Convert.d
pvDataApp/O.linux-x86_64/epicsException.d
pvDataApp/O.linux-x86_64/event.d
pvDataApp/O.linux-x86_64/executor.d
pvDataApp/O.linux-x86_64/FieldCreateFactory.d
pvDataApp/O.linux-x86_64/libpvData.a
pvDataApp/O.linux-x86_64/libpvData.so
pvDataApp/O.linux-x86_64/localStaticLock.d
pvDataApp/O.linux-x86_64/messageQueue.d
pvDataApp/O.linux-x86_64/pvAlarm.d
pvDataApp/O.linux-x86_64/PVArray.d
pvDataApp/O.linux-x86_64/PVAuxInfoImpl.d
pvDataApp/O.linux-x86_64/pvControl.d
pvDataApp/O.linux-x86_64/PVDataCreateFactory.d
pvDataApp/O.linux-x86_64/pvDisplay.d
pvDataApp/O.linux-x86_64/pvEnumerated.d
pvDataApp/O.linux-x86_64/PVField.d
pvDataApp/O.linux-x86_64/PVScalar.d
pvDataApp/O.linux-x86_64/PVScalarArray.d
pvDataApp/O.linux-x86_64/PVStructure.d
pvDataApp/O.linux-x86_64/PVStructureArray.d
pvDataApp/O.linux-x86_64/pvTimeStamp.d
pvDataApp/O.linux-x86_64/requester.d
pvDataApp/O.linux-x86_64/serializeHelper.d
pvDataApp/O.linux-x86_64/StandardField.d
pvDataApp/O.linux-x86_64/StandardPVField.d
pvDataApp/O.linux-x86_64/status.d
pvDataApp/O.linux-x86_64/timeFunction.d
pvDataApp/O.linux-x86_64/timer.d
pvDataApp/O.linux-x86_64/timeStamp.d
pvDataApp/O.linux-x86_64/TypeFunc.d
pvDataApp/property/alarm.cpp
pvDataApp/property/alarm.h
pvDataApp/property/alarm.h.orig
pvDataApp/property/control.h
pvDataApp/property/display.h
pvDataApp/property/pvAlarm.cpp
pvDataApp/property/pvAlarm.h
pvDataApp/property/pvControl.cpp
pvDataApp/property/pvControl.h
pvDataApp/property/pvDisplay.cpp
pvDataApp/property/pvDisplay.h
pvDataApp/property/pvEnumerated.cpp
pvDataApp/property/pvEnumerated.h
pvDataApp/property/pvTimeStamp.cpp
pvDataApp/property/pvTimeStamp.h
pvDataApp/property/timeStamp.cpp
pvDataApp/property/timeStamp.h
pvDataApp/property/timeStamp.h.orig
pvDataApp/pv/convert.h
pvDataApp/pv/convert.h.orig
pvDataApp/pv/pvData.h
pvDataApp/pv/pvData.h.orig
pvDataApp/pv/pvIntrospect.h
pvDataApp/pv/pvIntrospect.h.orig
pvDataApp/pv/pvType.h
pvDataApp/pv/standardField.h
pvDataApp/pv/standardField.h.orig
pvDataApp/pv/standardPVField.h
pvDataApp/pv/standardPVField.h.orig
pvDataApp/pvMisc/bitSetUtil.cpp
pvDataApp/pvMisc/bitSetUtil.h
testApp/capi/O.linux-x86_64/libtestc.a
testApp/capi/O.linux-x86_64/libtestc.so
testApp/capi/O.linux-x86_64/testc.d
testApp/capi/testc.cpp
testApp/capi/testc.py
testApp/mb/O.linux-x86_64/mb_test
testApp/mb/O.linux-x86_64/mb_test.d
testApp/misc/O.linux-x86_64/testBaseException
testApp/misc/O.linux-x86_64/testBaseException.d
testApp/misc/O.linux-x86_64/testBitSet
testApp/misc/O.linux-x86_64/testBitSet.d
testApp/misc/O.linux-x86_64/testByteBuffer
testApp/misc/O.linux-x86_64/testByteBuffer.d
testApp/misc/O.linux-x86_64/testByteOrder
testApp/misc/O.linux-x86_64/testByteOrder.d
testApp/misc/O.linux-x86_64/testMessageQueue
testApp/misc/O.linux-x86_64/testMessageQueue.d
testApp/misc/O.linux-x86_64/testQueue
testApp/misc/O.linux-x86_64/testQueue.d
testApp/misc/O.linux-x86_64/testSerialization
testApp/misc/O.linux-x86_64/testSerialization.d
testApp/misc/O.linux-x86_64/testThread
testApp/misc/O.linux-x86_64/testThread.d
testApp/misc/O.linux-x86_64/testTimer
testApp/misc/O.linux-x86_64/testTimer.d
testApp/misc/O.linux-x86_64/testTimeStamp
testApp/misc/O.linux-x86_64/testTimeStamp.d
testApp/misc/testBaseException.cpp
testApp/misc/testBitSet.cpp
testApp/misc/testByteBuffer.cpp
testApp/misc/testByteOrder.cpp
testApp/misc/testMessageQueue.cpp
testApp/misc/testQueue.cpp
testApp/misc/testSerialization.cpp
testApp/misc/testThread.cpp
testApp/misc/testTimer.cpp
testApp/misc/testTimeStamp.cpp
testApp/monitor/O.linux-x86_64/testMonitor
testApp/monitor/O.linux-x86_64/testMonitor.d
testApp/monitor/testMonitor.cpp
testApp/property/O.linux-x86_64/testProperty
testApp/property/O.linux-x86_64/testProperty.d
testApp/property/testProperty.cpp
testApp/pv/O.linux-x86_64/testConvert
testApp/pv/O.linux-x86_64/testConvert.d
testApp/pv/O.linux-x86_64/testIntrospect
testApp/pv/O.linux-x86_64/testIntrospect.d
testApp/pv/O.linux-x86_64/testOperators
testApp/pv/O.linux-x86_64/testOperators.d
testApp/pv/O.linux-x86_64/testPVAppend
testApp/pv/O.linux-x86_64/testPVAppend.d
testApp/pv/O.linux-x86_64/testPVAuxInfo
testApp/pv/O.linux-x86_64/testPVAuxInfo.d
testApp/pv/O.linux-x86_64/testPVData
testApp/pv/O.linux-x86_64/testPVData.d
testApp/pv/O.linux-x86_64/testPVScalarArray
testApp/pv/O.linux-x86_64/testPVScalarArray.d
testApp/pv/O.linux-x86_64/testPVStructureArray
testApp/pv/O.linux-x86_64/testPVStructureArray.d
testApp/pv/O.linux-x86_64/testPVType
testApp/pv/O.linux-x86_64/testPVType.d
testApp/pv/O.linux-x86_64/testStandardField
testApp/pv/O.linux-x86_64/testStandardField.d
testApp/pv/O.linux-x86_64/testStandardPVField
testApp/pv/O.linux-x86_64/testStandardPVField.d
testApp/pv/testConvert.cpp
testApp/pv/testIntrospect.cpp
testApp/pv/testOperators.cpp
testApp/pv/testPVAppend.cpp
testApp/pv/testPVAuxInfo.cpp
testApp/pv/testPVData.cpp
testApp/pv/testPVScalarArray.cpp
testApp/pv/testPVStructureArray.cpp
testApp/pv/testPVType.cpp
testApp/pv/testStandardField.cpp
testApp/pv/testStandardPVField.cpp
COPYRIGHT
Doxyfile
LICENSE
README.html

6
pvDataCPP.includes Normal file
View File

@@ -0,0 +1,6 @@
/home/msekoranja/epicsV4/pvDataCPP/pvDataApp/factory
/home/msekoranja/epicsV4/pvDataCPP/pvDataApp/misc
/home/msekoranja/epicsV4/pvDataCPP/pvDataApp/monitor
/home/msekoranja/epicsV4/pvDataCPP/pvDataApp/property
/home/msekoranja/epicsV4/pvDataCPP/pvDataApp/pv
/home/msekoranja/epicsV4/pvDataCPP/pvDataApp/pvMisc

24
src/Makefile Normal file
View File

@@ -0,0 +1,24 @@
# Makefile for the pvData library
TOP = ..
include $(TOP)/configure/CONFIG
INSTALL_INCLUDE = $(INSTALL_LOCATION)/include/pv
USR_INCLUDES += -I$(INSTALL_LOCATION)/include
PVDATA_SRC = $(TOP)/src
include $(PVDATA_SRC)/misc/Makefile
include $(PVDATA_SRC)/pv/Makefile
include $(PVDATA_SRC)/factory/Makefile
include $(PVDATA_SRC)/property/Makefile
include $(PVDATA_SRC)/copy/Makefile
include $(PVDATA_SRC)/pvMisc/Makefile
include $(PVDATA_SRC)/monitor/Makefile
LIBRARY = pvData
pvData_LIBS += Com
include $(TOP)/configure/RULES

9
src/copy/Makefile Normal file
View File

@@ -0,0 +1,9 @@
# This is a Makefile fragment, see ../Makefile
SRC_DIRS += $(PVDATA_SRC)/copy
INC += createRequest.h
INC += pvCopy.h
LIBSRCS += createRequest.cpp
LIBSRCS += pvCopy.cpp

533
src/copy/createRequest.cpp Normal file
View File

@@ -0,0 +1,533 @@
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* pvAccessCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#include <string>
#include <sstream>
#define epicsExportSharedSymbols
#include <pv/pvData.h>
#include <pv/lock.h>
#include <pv/createRequest.h>
using namespace epics::pvData;
using std::tr1::static_pointer_cast;
using std::cout;
using std::endl;
using std::string;
namespace epics { namespace pvData {
static PVDataCreatePtr pvDataCreate = getPVDataCreate();
static FieldCreatePtr fieldCreate = getFieldCreate();
class CreateRequestImpl : public CreateRequest {
private:
void removeBlanks(string& str)
{
while(true) {
string::size_type pos = str.find_first_of(' ');
if(pos==string::npos) return;
str.erase(pos,1);
}
}
size_t findMatchingBrace(string& request, size_t index, int numOpen) {
size_t openBrace = request.find('{', index+1);
size_t closeBrace = request.find('}', index+1);
if(openBrace == string::npos && closeBrace == string::npos){
message = request + " missing }";
return string::npos;
}
if (openBrace != string::npos && openBrace!=0) {
if(openBrace<closeBrace) return findMatchingBrace(request,openBrace,numOpen+1);
if(numOpen==1) return closeBrace;
return findMatchingBrace(request,closeBrace,numOpen-1);
}
if(numOpen==1) return closeBrace;
return findMatchingBrace(request,closeBrace,numOpen-1);
}
size_t findMatchingBracket(string& request, size_t index) {
for(size_t i=index+1; i< request.size(); ++i) {
if(request[i] == ']') {
if(i==index+1) {
message = request + " illegal []";
return string::npos;
}
return i;
}
}
message = request + " missing ]";
return string::npos;
}
size_t findEndField(string& request) {
size_t ind = 0;
size_t maxind = request.size() -1;
while(true) {
if(request[ind]==',') return ind;
if(request[ind]=='[') {
size_t closeBracket = findMatchingBracket(request,ind);
if(closeBracket==string::npos) return closeBracket;
ind = closeBracket;
continue;
}
if(request[ind]=='{') {
size_t closeBrace = findMatchingBrace(request,ind,1);
if(closeBrace==string::npos) return closeBrace;
if(ind>=request.size()) return request.size();
ind = closeBrace;
continue;
}
if(ind>=maxind) break;
++ind;
}
return request.size();
}
std::vector<string> split(string const & commaSeparatedList) {
string::size_type numValues = 1;
string::size_type index=0;
while(true) {
string::size_type pos = commaSeparatedList.find(',',index);
if(pos==string::npos) break;
numValues++;
index = pos +1;
}
std::vector<string> valueList(numValues,"");
index=0;
for(size_t i=0; i<numValues; i++) {
size_t pos = commaSeparatedList.find(',',index);
string value = commaSeparatedList.substr(index,pos-index);
valueList[i] = value;
index = pos +1;
}
return valueList;
}
StructureConstPtr createRequestOptions(
string request)
{
if(request.length()<=1) return StructureConstPtr();
std::vector<string> items = split(request);
size_t nitems = items.size();
StringArray fieldNames(nitems);
FieldConstPtrArray fields(nitems);
for(size_t j=0; j<nitems; j++) {
string item = items[j];
size_t equals = item.find('=');
if(equals==string::npos || equals==0) {
message = item + " illegal option";
StructureConstPtr xxx;
return xxx;
}
fieldNames[j] = item.substr(0,equals);
fields[j] = fieldCreate->createScalar(pvString);
}
return fieldCreate->createStructure(fieldNames,fields);
}
void initRequestOptions(
PVStructurePtr const & pvParent,
string request)
{
if(request.length()<=1) return;
std::vector<string> items = split(request);
size_t nitems = items.size();
for(size_t j=0; j<nitems; j++) {
string item = items[j];
size_t equals = item.find('=');
string name = item.substr(0,equals);
string value = item.substr(equals+1);
PVStringPtr pvValue = pvParent->getSubField<PVString>(name);
pvValue->put(value);
}
}
StructureConstPtr createSubFieldRequest(
StructureConstPtr parent,
string request)
{
if(request.length()<=0) return parent;
size_t period = request.find('.');
size_t openBracket = request.find('[');
size_t openBrace = request.find('{');
// name only
if(period==string::npos
&& openBracket==string::npos
&& openBrace==string::npos)
{
StructureConstPtr subField = fieldCreate->createStructure();
parent = fieldCreate->appendField(parent,request,subField);
return parent;
}
// period is first
if(period!=string::npos
&& (openBracket==string::npos || period<openBracket)
&& (openBrace==string::npos || period<openBrace) )
{
string fieldName = request.substr(0,period);
StructureConstPtr subField = fieldCreate->createStructure();
subField = createSubFieldRequest(subField,request.substr(period+1));
if(subField==NULL) return subField;
parent = fieldCreate->appendField(parent,fieldName,subField);
return parent;
}
// brace before [ or .
if(openBrace!=string::npos
&& (openBracket==string::npos || openBrace<openBracket) )
{
string fieldName = request.substr(0,openBrace);
size_t closeBrace = findMatchingBrace(request,openBrace,1);
if(closeBrace==string::npos) return StructureConstPtr();
size_t nextChar = closeBrace+1;
if(nextChar>= request.size()) nextChar = string::npos;
if(nextChar!=string::npos) {
message = request + " syntax error " + request[nextChar] + " after } illegal";
return StructureConstPtr();
}
StructureConstPtr subField = fieldCreate->createStructure();
string subRequest = request.substr(openBrace+1,closeBrace-openBrace-1);
subField = createFieldRequest(subField,subRequest);
if(subField==NULL) return subField;
parent = fieldCreate->appendField(parent,fieldName,subField);
return parent;
}
// [ is before brace or .
if(openBracket!=string::npos
&& (openBrace==string::npos || openBracket<openBrace) )
{
string fieldName = request.substr(0,openBracket);
size_t closeBracket = findMatchingBracket(request,openBracket);
if(closeBracket==string::npos) return StructureConstPtr();
size_t nextChar = closeBracket+1;
if(nextChar>= request.size()) nextChar = string::npos;
if(nextChar==string::npos) {
StringArray fieldNames(1);
FieldConstPtrArray fields(1);
fieldNames[0] = "_options";
fields[0] = createRequestOptions(
request.substr(openBracket+1,closeBracket-openBracket-1));
StructureConstPtr subField = fieldCreate->createStructure(fieldNames,fields);
parent = fieldCreate->appendField(parent,fieldName,subField);
return parent;
}
if(request[nextChar]=='.') {
StructureConstPtr subField = fieldCreate->createStructure();
subField = createSubFieldRequest(subField,request.substr(nextChar+1));
if(subField==NULL) return StructureConstPtr();
if(subField->getNumberFields()!=1) {
message = request + " logic error createSubFieldRequest openBracket subField";
return StructureConstPtr();
}
StringArray fieldNames(2);
FieldConstPtrArray fields(2);
fieldNames[0] = "_options";
fields[0] = createRequestOptions(
request.substr(openBracket+1,closeBracket-openBracket-1));
fieldNames[1] = subField->getFieldNames()[0];
fields[1] = subField;
subField = fieldCreate->createStructure(fieldNames,fields);
parent = fieldCreate->appendField(parent,fieldName,subField);
return parent;
}
if(request[nextChar]=='{') {
size_t closeBrace = findMatchingBrace(request,openBrace,1);
if(closeBrace==string::npos) return StructureConstPtr();
StructureConstPtr subField = fieldCreate->createStructure();
string subRequest = request.substr(openBrace+1,closeBrace-openBrace-1);
subField = createFieldRequest(subField,subRequest);
if(subField==NULL) return subField;
size_t numSub = subField->getNumberFields();
StringArray fieldNames(numSub + 1);
FieldConstPtrArray fields(numSub+1);
fieldNames[0] = "_options";
fields[0] = createRequestOptions(
request.substr(openBracket+1,closeBracket-openBracket-1));
StringArray subNames = subField->getFieldNames();
FieldConstPtrArray subFields = subField->getFields();
for(size_t i=0; i<numSub; ++i) {
fieldNames[i+1] = subNames[i];
fields[i+1] = subFields[i];
}
subField = fieldCreate->appendFields(parent,fieldNames,fields);
parent = fieldCreate->appendField(parent,fieldName,subField);
return parent;
}
}
message = request + " logic error createSubFieldRequest";
return StructureConstPtr();
}
StructureConstPtr createFieldRequest(
StructureConstPtr parent,
string request)
{
size_t length = request.length();
if(length<=0) return parent;
size_t end = findEndField(request);
if(end==string::npos) return StructureConstPtr();
StringArray fieldNames;
FieldConstPtrArray fields;
StructureConstPtr subField = fieldCreate->createStructure();
subField = createSubFieldRequest(subField,request.substr(0,end));
if(subField==NULL) return subField;
fieldNames.push_back(subField->getFieldNames()[0]);
fields.push_back(subField->getFields()[0]);
if(end!=length) {
if(request[end]!=',') {
message = request;
message += " expected char ";
message += length;
message += " to be ,";
return StructureConstPtr();
}
StructureConstPtr nextSubField = fieldCreate->createStructure();
nextSubField = createFieldRequest(nextSubField,request.substr(end+1));
if(nextSubField==NULL) return nextSubField;
size_t numFields = nextSubField->getNumberFields();
StringArray subNames = nextSubField->getFieldNames();
FieldConstPtrArray subFields = nextSubField->getFields();
for(size_t i=0; i<numFields; ++i) {
fieldNames.push_back(subNames[i]);
fields.push_back(subFields[i]);
}
}
parent = fieldCreate->appendFields(parent,fieldNames,fields);
return parent;
}
void initSubFieldOptions(
PVStructurePtr const & pvParent,
string request)
{
if(request.length()<=0) return;
size_t period = request.find('.');
size_t openBracket = request.find('[');
size_t openBrace = request.find('{');
// name only
if(period==string::npos
&& openBracket==string::npos
&& openBrace==string::npos)
{
return;
}
// period is first
if(period!=string::npos
&& (openBracket==string::npos || period<openBracket)
&& (openBrace==string::npos || period<openBrace) )
{
PVStructurePtr pvSubField = static_pointer_cast<PVStructure>(pvParent->getPVFields()[0]);
initSubFieldOptions(pvSubField,request.substr(period+1));
return;
}
// brace before [ or .
if(openBrace!=string::npos
&& (openBracket==string::npos || openBrace<openBracket) )
{
PVStructurePtr pvSubField = static_pointer_cast<PVStructure>(pvParent->getPVFields()[0]);
size_t closeBrace = findMatchingBrace(request,openBrace,1);
string subRequest = request.substr(openBrace+1,closeBrace-openBrace-1);
initFieldOptions(pvSubField,subRequest);
return;
}
PVStructurePtr pvOptions = pvParent->getSubField<PVStructure>("_options");
if(pvOptions==NULL) throw std::logic_error("initSubFieldOptions pvOptions NULL");
size_t closeBracket = findMatchingBracket(request,openBracket);
initRequestOptions(pvOptions,request.substr(openBracket+1,closeBracket-openBracket-1));
size_t nextChar = closeBracket+1;
if(nextChar>= request.size()) nextChar = string::npos;
if(nextChar==string::npos) return;
if(request[nextChar]=='.') {
PVStructurePtr pvSubField = static_pointer_cast<PVStructure>(pvParent->getPVFields()[1]);
initSubFieldOptions(pvSubField,request.substr(nextChar+1));
return;
}
if(request[nextChar]!='{') throw std::logic_error("initSubFieldOptions request[nextChar]!='{'");
size_t closeBrace = findMatchingBrace(request,openBrace,1);
const PVFieldPtrArray &pvFields = pvParent->getPVFields();
string subRequest = request.substr(openBrace+1,closeBrace-openBrace-1);
for(size_t i=1; i<pvFields.size(); ++i) {
PVStructurePtr pvSubField = static_pointer_cast<PVStructure>(pvFields[i]);
size_t comma = subRequest.find(',');
initSubFieldOptions(pvSubField, subRequest.substr(0,comma-1));
subRequest = subRequest.substr(comma+1);
}
}
void initFieldOptions(
PVStructurePtr const & pvParent,
string request)
{
if(request.find('[')==string::npos) return;
size_t num = pvParent->getStructure()->getNumberFields();
if(num==0) return;
if(num==1) {
initSubFieldOptions(pvParent,request);
return;
}
size_t end = findEndField(request);
size_t start = 0;
for(size_t i=0; i<num; ++i) {
PVStructurePtr pvSub = static_pointer_cast<PVStructure>(pvParent->getPVFields()[i]);
string subRequest = request.substr(start, end - start);
initSubFieldOptions(pvSub,subRequest);
if(i==num-1) break;
start = end +1;
string xxx = request.substr(start);
end += findEndField(xxx) + 1;
}
}
public:
virtual PVStructure::shared_pointer createRequest(
string const & crequest)
{
string request = crequest;
StructureConstPtr topStructure = fieldCreate->createStructure();
if (!request.empty()) removeBlanks(request);
if (request.empty())
{
PVFieldPtrArray pvFields;
StringArray fieldNames;
return pvDataCreate->createPVStructure(fieldNames,pvFields);
}
size_t offsetRecord = request.find("record[");
size_t offsetField = request.find("field(");
size_t offsetPutField = request.find("putField(");
size_t offsetGetField = request.find("getField(");
if(offsetRecord==string::npos
&& offsetField==string::npos
&& offsetPutField==string::npos
&& offsetGetField==string::npos)
{
request = "field(" + crequest + ")";
offsetField = request.find("field(");
}
if (offsetRecord != string::npos) {
size_t openBracket = request.find('[', offsetRecord);
size_t closeBracket = request.find(']', openBracket);
if(closeBracket == string::npos) {
message = request.substr(offsetRecord)
+ " record[ does not have matching ]";
return PVStructurePtr();
}
StructureConstPtr structure = createRequestOptions(
request.substr(openBracket+1,closeBracket-openBracket-1));
if(structure==NULL)
{
return PVStructurePtr();
}
topStructure = fieldCreate->appendField(topStructure,"record",structure);
}
if (offsetField != string::npos) {
size_t openBrace = request.find('(', offsetField);
size_t closeBrace = request.find(')', openBrace);
if(closeBrace == string::npos) {
message = request.substr(offsetField)
+ " field( does not have matching )";
return PVStructurePtr();
}
StructureConstPtr structure = fieldCreate->createStructure();
structure = createFieldRequest(structure,request.substr(openBrace+1,closeBrace-openBrace-1));
if(structure==NULL)
{
return PVStructurePtr();
}
topStructure = fieldCreate->appendField(topStructure,"field",structure);
}
if (offsetPutField != string::npos) {
size_t openBrace = request.find('(', offsetPutField);
size_t closeBrace = request.find(')', openBrace);
if(closeBrace == string::npos) {
message = request.substr(offsetField)
+ " putField( does not have matching )";
return PVStructurePtr();
}
StructureConstPtr structure = fieldCreate->createStructure();
structure = createFieldRequest(structure,request.substr(openBrace+1,closeBrace-openBrace-1));
if(structure==NULL)
{
return PVStructurePtr();
}
topStructure = fieldCreate->appendField(topStructure,"putField",structure);
}
if (offsetGetField != string::npos) {
size_t openBrace = request.find('(', offsetGetField);
size_t closeBrace = request.find(')', openBrace);
if(closeBrace == string::npos) {
message = request.substr(offsetField)
+ " getField( does not have matching )";
return PVStructurePtr();
}
StructureConstPtr structure = fieldCreate->createStructure();
structure = createFieldRequest(structure,request.substr(openBrace+1,closeBrace-openBrace-1));
if(structure==NULL)
{
return PVStructurePtr();
}
topStructure = fieldCreate->appendField(topStructure,"getField",structure);
}
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(topStructure);
if (offsetRecord != string::npos) {
size_t openBracket = request.find('[', offsetRecord);
size_t closeBracket = request.find(']', openBracket);
initRequestOptions(
pvStructure->getSubField<PVStructure>("record"),
request.substr(openBracket+1,closeBracket-openBracket-1));
}
if (offsetField != string::npos) {
size_t openParam = request.find('(', offsetField);
size_t closeParam = request.find(')', openParam);
PVStructurePtr pvSub = pvStructure->getSubField<PVStructure>("field");
if(pvSub->getStructure()->getNumberFields()==1) {
pvSub = static_pointer_cast<PVStructure>(pvSub->getPVFields()[0]);
}
if(pvSub!=NULL) initFieldOptions(pvSub,request.substr(openParam+1,closeParam-openParam-1));
}
if (offsetPutField != string::npos) {
size_t openParam = request.find('(', offsetPutField);
size_t closeParam = request.find(')', openParam);
PVStructurePtr pvSub = pvStructure->getSubField<PVStructure>("putField");
if(pvSub->getStructure()->getNumberFields()==1) {
pvSub = static_pointer_cast<PVStructure>(pvSub->getPVFields()[0]);
}
if(pvSub!=NULL) initFieldOptions(pvSub,request.substr(openParam+1,closeParam-openParam-1));
}
if (offsetGetField != string::npos) {
size_t openParam = request.find('(', offsetGetField);
size_t closeParam = request.find(')', openParam);
PVStructurePtr pvSub = pvStructure->getSubField<PVStructure>("getField");
if(pvSub->getStructure()->getNumberFields()==1) {
pvSub = static_pointer_cast<PVStructure>(pvSub->getPVFields()[0]);
}
if(pvSub!=NULL) initFieldOptions(pvSub,request.substr(openParam+1,closeParam-openParam-1));
}
return pvStructure;
}
};
CreateRequest::shared_pointer CreateRequest::create()
{
CreateRequest::shared_pointer createRequest(new CreateRequestImpl());
return createRequest;
}
}}

56
src/copy/createRequest.h Normal file
View File

@@ -0,0 +1,56 @@
/*createRequest.h*/
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#ifndef CREATEREQUEST_H
#define CREATEREQUEST_H
#include <string>
#include <sstream>
#include <pv/pvData.h>
#include <pv/lock.h>
#include <shareLib.h>
namespace epics { namespace pvData {
/**
* Class to create pvRequest structures to pass to pvAccess Channel methods.
*/
class epicsShareClass CreateRequest {
public:
POINTER_DEFINITIONS(CreateRequest);
/**
* Create s new instance of CreateRequest
* @returns A shared pointer to the new instance.
*/
static CreateRequest::shared_pointer create();
virtual ~CreateRequest() {};
/**
* Create a request structure for the create calls in Channel.
* See the package overview documentation for details.
* @param request The field request. See the package overview documentation for details.
* @param requester The requester;
* @return The request PVStructure if a valid request was given.
* If a NULL PVStructure is returned then getMessage will return
* the reason.
*/
virtual PVStructure::shared_pointer createRequest(std::string const & request) = 0;
/**
* Get the error message of createRequest returns NULL
* return the error message
*/
std::string getMessage() {return message;}
protected:
CreateRequest() {}
std::string message;
};
}}
#endif /* CREATEREQUEST_H */

650
src/copy/pvCopy.cpp Normal file
View File

@@ -0,0 +1,650 @@
/* pvCopy.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author Marty Kraimer
* @date 2013.04
*/
#include <string>
#include <stdexcept>
#include <memory>
#include <sstream>
#define epicsExportSharedSymbols
#include <pv/thread.h>
#include <pv/pvCopy.h>
#include <pv/convert.h>
using std::tr1::static_pointer_cast;
using std::tr1::dynamic_pointer_cast;
using std::string;
using std::size_t;
using std::cout;
using std::endl;
namespace epics { namespace pvData {
static PVCopyPtr NULLPVCopy;
static FieldConstPtr NULLField;
static StructureConstPtr NULLStructure;
static PVStructurePtr NULLPVStructure;
static CopyNodePtr NULLCopyNode;
static CopyMasterNodePtr NULLCopyMasterNode;
struct CopyNode {
CopyNode()
: isStructure(false),
structureOffset(0),
nfields(0)
{}
bool isStructure;
size_t structureOffset; // In the copy
size_t nfields;
PVStructurePtr options;
};
struct CopyMasterNode : public CopyNode{
PVFieldPtr masterPVField;
};
typedef std::vector<CopyNodePtr> CopyNodePtrArray;
typedef std::tr1::shared_ptr<CopyNodePtrArray> CopyNodePtrArrayPtr;
struct CopyStructureNode : public CopyNode {
CopyNodePtrArrayPtr nodes;
};
PVCopyPtr PVCopy::create(
PVStructurePtr const &pvMaster,
PVStructurePtr const &pvRequest,
string const & structureName)
{
PVStructurePtr pvStructure(pvRequest);
if(structureName.size()>0) {
if(pvRequest->getStructure()->getNumberFields()>0) {
pvStructure = pvRequest->getStructureField(structureName);
if(pvStructure.get()==NULL) return NULLPVCopy;
}
} else if(pvStructure->getSubField("field")!=NULL) {
pvStructure = pvRequest->getStructureField("field");
}
PVCopyPtr pvCopy = PVCopyPtr(new PVCopy(pvMaster));
bool result = pvCopy->init(pvStructure);
if(!result) pvCopy.reset();
return pvCopy;
}
PVCopy::PVCopy(
PVStructurePtr const &pvMaster)
: pvMaster(pvMaster)
{
}
void PVCopy::destroy()
{
headNode.reset();
}
PVStructurePtr PVCopy::getPVMaster()
{
return pvMaster;
}
void PVCopy::traverseMaster(CopyNodePtr const &innode, PVCopyTraverseMasterCallbackPtr const & callback)
{
CopyNodePtr node = innode;
if(!node->isStructure) {
CopyMasterNodePtr masterNode = static_pointer_cast<CopyMasterNode>(node);
callback->nextMasterPVField(masterNode->masterPVField);
return;
}
CopyStructureNodePtr structNode = static_pointer_cast<CopyStructureNode>(node);
CopyNodePtrArrayPtr nodes = structNode->nodes;
for(size_t i=0; i< nodes->size(); i++) {
node = (*nodes)[i];
traverseMaster(node,callback);
}
}
StructureConstPtr PVCopy::getStructure()
{
return structure;
}
PVStructurePtr PVCopy::createPVStructure()
{
if(cacheInitStructure.get()!=NULL) {
PVStructurePtr save = cacheInitStructure;
cacheInitStructure.reset();
return save;
}
PVStructurePtr pvStructure =
getPVDataCreate()->createPVStructure(structure);
return pvStructure;
}
PVStructurePtr PVCopy::getOptions(std::size_t fieldOffset)
{
if(fieldOffset==0) return headNode->options;
CopyNodePtr node = headNode;
while(true) {
if(!node->isStructure) {
if(node->structureOffset==fieldOffset) return node->options;
return NULLPVStructure;
}
CopyStructureNodePtr structNode = static_pointer_cast<CopyStructureNode>(node);
CopyNodePtrArrayPtr nodes = structNode->nodes;
boolean okToContinue = false;
for(size_t i=0; i< nodes->size(); i++) {
node = (*nodes)[i];
size_t soff = node->structureOffset;
if(fieldOffset>=soff && fieldOffset<soff+node->nfields) {
if(fieldOffset==soff) return node->options;
if(!node->isStructure) {
return NULLPVStructure;
}
okToContinue = true;
break;
}
}
if(okToContinue) continue;
throw std::invalid_argument("fieldOffset not valid");
}
}
size_t PVCopy::getCopyOffset(PVFieldPtr const &masterPVField)
{
if(masterPVField->getFieldOffset()==0) return 0;
if(!headNode->isStructure) {
CopyMasterNodePtr masterNode = static_pointer_cast<CopyMasterNode>(headNode);
if((masterNode->masterPVField.get())==masterPVField.get()) {
return headNode->structureOffset;
}
PVStructure * parent = masterPVField->getParent();
size_t offsetParent = parent->getFieldOffset();
size_t off = masterPVField->getFieldOffset();
size_t offdiff = off -offsetParent;
if(offdiff<masterNode->nfields) return headNode->structureOffset + offdiff;
return string::npos;
}
CopyStructureNodePtr node = static_pointer_cast<CopyStructureNode>(headNode);
CopyMasterNodePtr masterNode = getCopyOffset(node,masterPVField);
if(masterNode.get()!=NULL) return masterNode->structureOffset;
return string::npos;
}
size_t PVCopy::getCopyOffset(
PVStructurePtr const &masterPVStructure,
PVFieldPtr const &masterPVField)
{
CopyMasterNodePtr masterNode;
if(!headNode->isStructure) {
masterNode = static_pointer_cast<CopyMasterNode>(headNode);
if(masterNode->masterPVField.get()!=masterPVStructure.get()) return string::npos;
} else {
CopyStructureNodePtr node = static_pointer_cast<CopyStructureNode>(headNode);
masterNode = getCopyOffset(node,masterPVField);
}
if(masterNode.get()==NULL) return string::npos;
size_t diff = masterPVField->getFieldOffset()
- masterPVStructure->getFieldOffset();
return masterNode->structureOffset + diff;
}
PVFieldPtr PVCopy::getMasterPVField(size_t structureOffset)
{
CopyMasterNodePtr masterNode;
if(!headNode->isStructure) {
masterNode = static_pointer_cast<CopyMasterNode>(headNode);
} else {
CopyStructureNodePtr node = static_pointer_cast<CopyStructureNode>(headNode);
masterNode = getMasterNode(node,structureOffset);
}
if(masterNode.get()==NULL) {
throw std::invalid_argument(
"PVCopy::getMasterPVField: setstructureOffset not valid");
}
size_t diff = structureOffset - masterNode->structureOffset;
PVFieldPtr pvMasterField = masterNode->masterPVField;
if(diff==0) return pvMasterField;
PVStructurePtr pvStructure
= static_pointer_cast<PVStructure>(pvMasterField);
return pvStructure->getSubField(
pvMasterField->getFieldOffset() + diff);
}
void PVCopy::initCopy(
PVStructurePtr const &copyPVStructure,
BitSetPtr const &bitSet)
{
bitSet->clear();
bitSet->set(0);
updateCopyFromBitSet(copyPVStructure,bitSet);
}
void PVCopy::updateCopySetBitSet(
PVStructurePtr const &copyPVStructure,
BitSetPtr const &bitSet)
{
if(headNode->isStructure) {
CopyStructureNodePtr node = static_pointer_cast<CopyStructureNode>(headNode);
updateStructureNodeSetBitSet(copyPVStructure,node,bitSet);
} else {
CopyMasterNodePtr masterNode = static_pointer_cast<CopyMasterNode>(headNode);
PVFieldPtr pvMasterField= masterNode->masterPVField;
PVFieldPtr copyPVField = copyPVStructure;
PVFieldPtr pvField = pvMasterField;
if(pvField->getField()->getType()==epics::pvData::structure) {
updateSubFieldSetBitSet(copyPVField,pvMasterField,bitSet);
return;
}
ConvertPtr convert = getConvert();
bool isEqual = convert->equals(copyPVField,pvField);
if(!isEqual) {
convert->copy(pvField, copyPVField);
bitSet->set(copyPVField->getFieldOffset());
}
}
}
void PVCopy::updateCopyFromBitSet(
PVStructurePtr const &copyPVStructure,
BitSetPtr const &bitSet)
{
bool doAll = bitSet->get(0);
if(headNode->isStructure) {
CopyStructureNodePtr node = static_pointer_cast<CopyStructureNode>(headNode);
updateStructureNodeFromBitSet(copyPVStructure,node,bitSet,true,doAll);
} else {
CopyMasterNodePtr masterNode = static_pointer_cast<CopyMasterNode>(headNode);
updateSubFieldFromBitSet(copyPVStructure, masterNode->masterPVField,bitSet, true,doAll);
}
}
void PVCopy::updateMaster(
PVStructurePtr const &copyPVStructure,
BitSetPtr const &bitSet)
{
bool doAll = bitSet->get(0);
if(headNode->isStructure) {
CopyStructureNodePtr node =
static_pointer_cast<CopyStructureNode>(headNode);
updateStructureNodeFromBitSet(
copyPVStructure,node,bitSet,false,doAll);
} else {
CopyMasterNodePtr masterNode =
static_pointer_cast<CopyMasterNode>(headNode);
updateSubFieldFromBitSet( copyPVStructure,masterNode->masterPVField,bitSet,false,doAll);
}
}
string PVCopy::dump()
{
string builder;
dump(&builder,headNode,0);
return builder;
}
void PVCopy::dump(string *builder,CopyNodePtr const &node,int indentLevel)
{
getConvert()->newLine(builder,indentLevel);
std::stringstream ss;
ss << (node->isStructure ? "structureNode" : "masterNode");
ss << " structureOffset " << node->structureOffset;
ss << " nfields " << node->nfields;
*builder += ss.str();
PVStructurePtr options = node->options;
if(options.get()!=NULL) {
getConvert()->newLine(builder,indentLevel +1);
// TODO !!! ugly
std::ostringstream oss;
oss << *options;
*builder += oss.str();
getConvert()->newLine(builder,indentLevel);
}
if(!node->isStructure) {
CopyMasterNodePtr masterNode = static_pointer_cast<CopyMasterNode>(node);
string name = masterNode->masterPVField->getFullName();
*builder += " masterField " + name;
return;
}
CopyStructureNodePtr structureNode =
static_pointer_cast<CopyStructureNode>(node);
CopyNodePtrArrayPtr nodes = structureNode->nodes;
for(size_t i=0; i<nodes->size(); ++i) {
if((*nodes)[i].get()==NULL) {
getConvert()->newLine(builder,indentLevel +1);
ss.str("");
ss << "node[" << i << "] is null";
*builder += ss.str();
continue;
}
dump(builder,(*nodes)[i],indentLevel+1);
}
}
bool PVCopy::init(epics::pvData::PVStructurePtr const &pvRequest)
{
PVStructurePtr pvMasterStructure = pvMaster;
size_t len = pvRequest->getPVFields().size();
bool entireMaster = false;
if(len==string::npos) entireMaster = true;
if(len==0) entireMaster = true;
PVStructurePtr pvOptions;
if(len==1 && pvRequest->getSubField("_options")!=NULL) {
pvOptions = pvRequest->getStructureField("_options");
}
if(entireMaster) {
structure = pvMasterStructure->getStructure();
CopyMasterNodePtr masterNode(new CopyMasterNode());
headNode = masterNode;
masterNode->options = pvOptions;
masterNode->isStructure = false;
masterNode->structureOffset = 0;
masterNode->masterPVField = pvMasterStructure;
masterNode->nfields = pvMasterStructure->getNumberFields();
return true;
}
structure = createStructure(pvMasterStructure,pvRequest);
if(structure==NULL) return false;
cacheInitStructure = createPVStructure();
headNode = createStructureNodes(
pvMaster,
pvRequest,
cacheInitStructure);
return true;
}
string PVCopy::dump(
string const &value,
CopyNodePtr const &node,
int indentLevel)
{
throw std::logic_error(string("Not Implemented"));
}
StructureConstPtr PVCopy::createStructure(
PVStructurePtr const &pvMaster,
PVStructurePtr const &pvFromRequest)
{
if(pvFromRequest->getStructure()->getNumberFields()==0) {
return pvMaster->getStructure();
}
PVFieldPtrArray const &pvFromRequestFields = pvFromRequest->getPVFields();
StringArray const &fromRequestFieldNames = pvFromRequest->getStructure()->getFieldNames();
size_t length = pvFromRequestFields.size();
if(length==0) return NULLStructure;
FieldConstPtrArray fields; fields.reserve(length);
StringArray fieldNames; fields.reserve(length);
for(size_t i=0; i<length; ++i) {
string const &fieldName = fromRequestFieldNames[i];
PVFieldPtr pvMasterField = pvMaster->getSubField(fieldName);
if(pvMasterField==NULL) continue;
FieldConstPtr field = pvMasterField->getField();
if(field->getType()==epics::pvData::structure) {
PVStructurePtr pvRequestStructure = static_pointer_cast<PVStructure>(
pvFromRequestFields[i]);
if(pvRequestStructure->getNumberFields()>0) {
StringArray const &names = pvRequestStructure->getStructure()->
getFieldNames();
size_t num = names.size();
if(num>0 && names[0].compare("_options")==0) --num;
if(num>0) {
if(pvMasterField->getField()->getType()!=epics::pvData::structure) continue;
fieldNames.push_back(fieldName);
fields.push_back(createStructure(
static_pointer_cast<PVStructure>(pvMasterField),
pvRequestStructure));
continue;
}
}
}
fieldNames.push_back(fieldName);
fields.push_back(field);
}
size_t numsubfields = fields.size();
if(numsubfields==0) return NULLStructure;
return getFieldCreate()->createStructure(fieldNames, fields);
}
CopyNodePtr PVCopy::createStructureNodes(
PVStructurePtr const &pvMasterStructure,
PVStructurePtr const &pvFromRequest,
PVStructurePtr const &pvFromCopy)
{
PVFieldPtrArray const & copyPVFields = pvFromCopy->getPVFields();
PVStructurePtr pvOptions;
PVFieldPtr pvField = pvFromRequest->getSubField("_options");
if(pvField!=NULL) pvOptions = static_pointer_cast<PVStructure>(pvField);
size_t number = copyPVFields.size();
CopyNodePtrArrayPtr nodes(new CopyNodePtrArray());
nodes->reserve(number);
for(size_t i=0; i<number; i++) {
PVFieldPtr copyPVField = copyPVFields[i];
string fieldName = copyPVField->getFieldName();
PVStructurePtr requestPVStructure = static_pointer_cast<PVStructure>(
pvFromRequest->getSubField(fieldName));
PVStructurePtr pvSubFieldOptions;
PVFieldPtr pvField = requestPVStructure->getSubField("_options");
if(pvField!=NULL) pvSubFieldOptions = static_pointer_cast<PVStructure>(pvField);
PVFieldPtr pvMasterField;
PVFieldPtrArray const & pvMasterFields = pvMasterStructure->getPVFields();
for(size_t j=0; i<pvMasterFields.size(); j++ ) {
if(pvMasterFields[j]->getFieldName().compare(fieldName)==0) {
pvMasterField = pvMasterFields[j];
break;
}
}
size_t numberRequest = requestPVStructure->getPVFields().size();
if(pvSubFieldOptions!=NULL) numberRequest--;
if(numberRequest>0) {
nodes->push_back(createStructureNodes(
static_pointer_cast<PVStructure>(pvMasterField),
requestPVStructure,
static_pointer_cast<PVStructure>(copyPVField)));
continue;
}
CopyMasterNodePtr masterNode(new CopyMasterNode());
masterNode->options = pvSubFieldOptions;
masterNode->isStructure = false;
masterNode->masterPVField = pvMasterField;
masterNode->nfields = copyPVField->getNumberFields();
masterNode->structureOffset = copyPVField->getFieldOffset();
nodes->push_back(masterNode);
}
CopyStructureNodePtr structureNode(new CopyStructureNode());
structureNode->isStructure = true;
structureNode->nodes = nodes;
structureNode->structureOffset = pvFromCopy->getFieldOffset();
structureNode->nfields = pvFromCopy->getNumberFields();
structureNode->options = pvOptions;
return structureNode;
}
void PVCopy::updateStructureNodeSetBitSet(
PVStructurePtr const &pvCopy,
CopyStructureNodePtr const &structureNode,
epics::pvData::BitSetPtr const &bitSet)
{
for(size_t i=0; i<structureNode->nodes->size(); i++) {
CopyNodePtr node = (*structureNode->nodes)[i];
PVFieldPtr pvField = pvCopy->getSubField(node->structureOffset);
if(node->isStructure) {
PVStructurePtr xxx = static_pointer_cast<PVStructure>(pvField);
CopyStructureNodePtr yyy =
static_pointer_cast<CopyStructureNode>(node);
updateStructureNodeSetBitSet(xxx,yyy,bitSet);
} else {
CopyMasterNodePtr masterNode =
static_pointer_cast<CopyMasterNode>(node);
updateSubFieldSetBitSet(pvField,masterNode->masterPVField,bitSet);
}
}
}
void PVCopy::updateSubFieldSetBitSet(
PVFieldPtr const &pvCopy,
PVFieldPtr const &pvMaster,
BitSetPtr const &bitSet)
{
FieldConstPtr field = pvCopy->getField();
Type type = field->getType();
if(type!=epics::pvData::structure) {
ConvertPtr convert = getConvert();
bool isEqual = convert->equals(pvCopy,pvMaster);
if(isEqual) {
if(type==structureArray) {
// always act as though a change occurred.
// Note that array elements are shared.
bitSet->set(pvCopy->getFieldOffset());
}
}
if(isEqual) return;
convert->copy(pvMaster, pvCopy);
bitSet->set(pvCopy->getFieldOffset());
return;
}
PVStructurePtr pvCopyStructure = static_pointer_cast<PVStructure>(pvCopy);
PVFieldPtrArray const & pvCopyFields = pvCopyStructure->getPVFields();
PVStructurePtr pvMasterStructure =
static_pointer_cast<PVStructure>(pvMaster);
PVFieldPtrArray const & pvMasterFields =
pvMasterStructure->getPVFields();
size_t length = pvCopyFields.size();
for(size_t i=0; i<length; i++) {
updateSubFieldSetBitSet(pvCopyFields[i],pvMasterFields[i],bitSet);
}
}
void PVCopy::updateStructureNodeFromBitSet(
PVStructurePtr const &pvCopy,
CopyStructureNodePtr const &structureNode,
BitSetPtr const &bitSet,
bool toCopy,
bool doAll)
{
size_t offset = structureNode->structureOffset;
if(!doAll) {
size_t nextSet = bitSet->nextSetBit(offset);
if(nextSet==string::npos) return;
}
if(offset>=pvCopy->getNextFieldOffset()) return;
if(!doAll) doAll = bitSet->get(offset);
CopyNodePtrArrayPtr nodes = structureNode->nodes;
for(size_t i=0; i<nodes->size(); i++) {
CopyNodePtr node = (*nodes)[i];
PVFieldPtr pvField = pvCopy->getSubField(node->structureOffset);
if(node->isStructure) {
PVStructurePtr xxx = static_pointer_cast<PVStructure>(pvField);
CopyStructureNodePtr subStructureNode =
static_pointer_cast<CopyStructureNode>(node);
updateStructureNodeFromBitSet(
xxx,subStructureNode,bitSet,toCopy,doAll);
} else {
CopyMasterNodePtr masterNode =
static_pointer_cast<CopyMasterNode>(node);
updateSubFieldFromBitSet(
pvField,masterNode->masterPVField,bitSet,toCopy,doAll);
}
}
}
void PVCopy::updateSubFieldFromBitSet(
PVFieldPtr const &pvCopy,
PVFieldPtr const &pvMasterField,
BitSetPtr const &bitSet,
bool toCopy,
bool doAll)
{
if(!doAll) {
doAll = bitSet->get(pvCopy->getFieldOffset());
}
if(!doAll) {
size_t offset = pvCopy->getFieldOffset();
size_t nextSet = bitSet->nextSetBit(offset);
if(nextSet==string::npos) return;
if(nextSet>=pvCopy->getNextFieldOffset()) return;
}
ConvertPtr convert = getConvert();
if(pvCopy->getField()->getType()==epics::pvData::structure) {
PVStructurePtr pvCopyStructure =
static_pointer_cast<PVStructure>(pvCopy);
PVFieldPtrArray const & pvCopyFields = pvCopyStructure->getPVFields();
if(pvMasterField->getField()->getType() !=epics::pvData::structure)
{
throw std::logic_error(string("Logic error"));
}
PVStructurePtr pvMasterStructure =
static_pointer_cast<PVStructure>(pvMasterField);
PVFieldPtrArray const & pvMasterFields =
pvMasterStructure->getPVFields();
for(size_t i=0; i<pvCopyFields.size(); i++) {
updateSubFieldFromBitSet(
pvCopyFields[i],
pvMasterFields[i],
bitSet,toCopy,doAll);
}
} else {
if(toCopy) {
convert->copy(pvMasterField, pvCopy);
} else {
convert->copy(pvCopy, pvMasterField);
}
}
}
CopyMasterNodePtr PVCopy::getCopyOffset(
CopyStructureNodePtr const &structureNode,
PVFieldPtr const &masterPVField)
{
size_t offset = masterPVField->getFieldOffset();
CopyNodePtrArrayPtr nodes = structureNode->nodes;
for(size_t i=0; i< nodes->size(); i++) {
CopyNodePtr node = (*nodes)[i];
if(!node->isStructure) {
CopyMasterNodePtr masterNode =
static_pointer_cast<CopyMasterNode>(node);
size_t off = masterNode->masterPVField->getFieldOffset();
size_t nextOffset = masterNode->masterPVField->getNextFieldOffset();
if(offset>= off && offset<nextOffset) return masterNode;
} else {
CopyStructureNodePtr subNode =
static_pointer_cast<CopyStructureNode>(node);
CopyMasterNodePtr masterNode =
getCopyOffset(subNode,masterPVField);
if(masterNode.get()!=NULL) return masterNode;
}
}
return NULLCopyMasterNode;
}
CopyMasterNodePtr PVCopy::getMasterNode(
CopyStructureNodePtr const &structureNode,
std::size_t structureOffset)
{
CopyNodePtrArrayPtr nodes = structureNode->nodes;
for(size_t i=0; i< nodes->size(); i++) {
CopyNodePtr node = (*nodes)[i];
if(structureOffset>=(node->structureOffset + node->nfields)) continue;
if(!node->isStructure) {
CopyMasterNodePtr masterNode =
static_pointer_cast<CopyMasterNode>(node);
return masterNode;
}
CopyStructureNodePtr subNode =
static_pointer_cast<CopyStructureNode>(node);
return getMasterNode(subNode,structureOffset);
}
return NULLCopyMasterNode;
}
}}

230
src/copy/pvCopy.h Normal file
View File

@@ -0,0 +1,230 @@
/* pvCopy.h */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author Marty Kraimer
* @date 2013.04
*/
#ifndef PVCOPY_H
#define PVCOPY_H
#include <string>
#include <stdexcept>
#include <memory>
#include <shareLib.h>
#include <pv/pvData.h>
#include <pv/bitSet.h>
namespace epics { namespace pvData{
class PVCopyTraverseMasterCallback;
typedef std::tr1::shared_ptr<PVCopyTraverseMasterCallback> PVCopyTraverseMasterCallbackPtr;
/**
* Callback for traversing master structure
* Must be implemented by code that creates pvCopy.
*/
class epicsShareClass PVCopyTraverseMasterCallback
{
public:
POINTER_DEFINITIONS(PVCopyTraverseMasterCallback);
virtual ~PVCopyTraverseMasterCallback() {}
/**
* Called once for each field in master.
* @param pvField The field in master.
*/
virtual void nextMasterPVField(epics::pvData::PVFieldPtr const &pvField) = 0;
};
class PVCopy;
typedef std::tr1::shared_ptr<PVCopy> PVCopyPtr;
struct CopyNode;
typedef std::tr1::shared_ptr<CopyNode> CopyNodePtr;
struct CopyMasterNode;
typedef std::tr1::shared_ptr<CopyMasterNode> CopyMasterNodePtr;
struct CopyStructureNode;
typedef std::tr1::shared_ptr<CopyStructureNode> CopyStructureNodePtr;
/**
* Class that manages one or more PVStructures that holds an arbitrary subset of the fields
* in another PVStructure called master.
*/
class epicsShareClass PVCopy :
public std::tr1::enable_shared_from_this<PVCopy>
{
public:
POINTER_DEFINITIONS(PVCopy);
/**
* Create a new pvCopy
* @param pvMaster The top level sructure for which a copy of
* an arbritary subset of the fields in master will be created and managed.
* @param pvRequest Selects the set of subfields desired and options for each field.
* @param structureName The name for the top level of any PVStructure created.
*/
static PVCopyPtr create(
PVStructurePtr const &pvMaster,
PVStructurePtr const &pvRequest,
std::string const & structureName);
virtual ~PVCopy(){}
virtual void destroy();
/**
* Get the top level structure of master
* @returns The master top level structure.
* This should not be modified.
*/
PVStructurePtr getPVMaster();
/**
* Traverse all the fields in master.
* @param callback This is called for each field on master.
*/
void traverseMaster(PVCopyTraverseMasterCallbackPtr const & callback)
{
traverseMaster(headNode,callback);
}
/**
* Get the introspection interface for a PVStructure for e copy.
*/
StructureConstPtr getStructure();
/**
* Create a copy instance. Monitors keep a queue of monitor elements.
* Since each element needs a PVStructure, multiple top level structures will be created.
*/
PVStructurePtr createPVStructure();
/**
* Given a field in pvMaster. return the offset in copy for the same field.
* A value of std::string::npos means that the copy does not have this field.
* @param masterPVField The field in master.
*/
std::size_t getCopyOffset(PVFieldPtr const &masterPVField);
/**
* Given a field in pvMaster. return the offset in copy for the same field.
* A value of std::string::npos means that the copy does not have this field.
* @param masterPVStructure A structure in master that has masterPVField.
* @param masterPVField The field in master.
*/
std::size_t getCopyOffset(
PVStructurePtr const &masterPVStructure,
PVFieldPtr const &masterPVField);
/**
* Given a offset in the copy get the corresponding field in pvMaster.
* @param offset The offset in the copy.
*/
PVFieldPtr getMasterPVField(std::size_t structureOffset);
/**
* Initialize the fields in copyPVStructure by giving each field
* the value from the corresponding field in pvMaster.
* bitSet will be set to show that all fields are changed.
* @param copyPVStructure A copy top level structure.
* @param bitSet A bitSet for copyPVStructure.
*/
void initCopy(
PVStructurePtr const &copyPVStructure,
BitSetPtr const &bitSet);
/**
* Set all fields in copyPVStructure to the value of the corresponding field in pvMaster.
* Each field that is changed has it's corresponding bit set in bitSet.
* @param copyPVStructure A copy top level structure.
* @param bitSet A bitSet for copyPVStructure.
*/
void updateCopySetBitSet(
PVStructurePtr const &copyPVStructure,
BitSetPtr const &bitSet);
/**
* For each set bit in bitSet
* set the field in copyPVStructure to the value of the corrseponding field in pvMaster.
* @param copyPVStructure A copy top level structure.
* @param bitSet A bitSet for copyPVStructure.
*/
void updateCopyFromBitSet(
PVStructurePtr const &copyPVStructure,
BitSetPtr const &bitSet);
/**
* For each set bit in bitSet
* set the field in pvMaster to the value of the corrseponding field in copyPVStructure
* @param copyPVStructure A copy top level structure.
* @param bitSet A bitSet for copyPVStructure.
*/
void updateMaster(
PVStructurePtr const &copyPVStructure,
BitSetPtr const &bitSet);
/**
* Get the options for the field at the specified offset.
* @param offset the offset in copy.
* @returns A NULL is returned if no options were specified for the field.
* If options were specified,PVStructurePtr is a structures
* with a set of PVString subfields that specify name,value pairs.s
* name is the subField name and value is the subField value.
*/
PVStructurePtr getOptions(std::size_t fieldOffset);
/**
* For debugging.
*/
std::string dump();
private:
void dump(
std::string *builder,
CopyNodePtr const &node,
int indentLevel);
PVCopyPtr getPtrSelf()
{
return shared_from_this();
}
void traverseMaster(CopyNodePtr const &node, PVCopyTraverseMasterCallbackPtr const & callback);
PVStructurePtr pvMaster;
StructureConstPtr structure;
CopyNodePtr headNode;
PVStructurePtr cacheInitStructure;
PVCopy(PVStructurePtr const &pvMaster);
friend class PVCopyMonitor;
bool init(PVStructurePtr const &pvRequest);
std::string dump(
std::string const &value,
CopyNodePtr const &node,
int indentLevel);
StructureConstPtr createStructure(
PVStructurePtr const &pvMaster,
PVStructurePtr const &pvFromRequest);
CopyNodePtr createStructureNodes(
PVStructurePtr const &pvMasterStructure,
PVStructurePtr const &pvFromRequest,
PVStructurePtr const &pvFromField);
void updateStructureNodeSetBitSet(
PVStructurePtr const &pvCopy,
CopyStructureNodePtr const &structureNode,
BitSetPtr const &bitSet);
void updateSubFieldSetBitSet(
PVFieldPtr const &pvCopy,
PVFieldPtr const &pvMaster,
BitSetPtr const &bitSet);
void updateStructureNodeFromBitSet(
PVStructurePtr const &pvCopy,
CopyStructureNodePtr const &structureNode,
BitSetPtr const &bitSet,
bool toCopy,
bool doAll);
void updateSubFieldFromBitSet(
PVFieldPtr const &pvCopy,
PVFieldPtr const &pvMasterField,
BitSetPtr const &bitSet,
bool toCopy,
bool doAll);
CopyMasterNodePtr getCopyOffset(
CopyStructureNodePtr const &structureNode,
PVFieldPtr const &masterPVField);
CopyMasterNodePtr getMasterNode(
CopyStructureNodePtr const &structureNode,
std::size_t structureOffset);
};
}}
#endif /* PVCOPY_H */

330
src/factory/Compare.cpp Normal file
View File

@@ -0,0 +1,330 @@
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mes
*/
#include <algorithm>
#include <iterator>
#include <sstream>
#define epicsExportSharedSymbols
#include <pv/convert.h>
using std::string;
namespace epics { namespace pvData {
// Introspection object comparision
/** Field equality conditions:
* 1) same instance
* 2) same type (field and scalar/element), same name, same subfields (if any)
*/
bool operator==(const Field& a, const Field& b)
{
if(&a==&b)
return true;
if(a.getType()!=b.getType())
return false;
switch(a.getType()) {
case scalar: {
const Scalar &A=static_cast<const Scalar&>(a);
const Scalar &B=static_cast<const Scalar&>(b);
return A==B;
}
case scalarArray: {
const ScalarArray &A=static_cast<const ScalarArray&>(a);
const ScalarArray &B=static_cast<const ScalarArray&>(b);
return A==B;
}
case structure: {
const Structure &A=static_cast<const Structure&>(a);
const Structure &B=static_cast<const Structure&>(b);
return A==B;
}
case structureArray: {
const StructureArray &A=static_cast<const StructureArray&>(a);
const StructureArray &B=static_cast<const StructureArray&>(b);
return A==B;
}
case union_: {
const Union &A=static_cast<const Union&>(a);
const Union &B=static_cast<const Union&>(b);
return A==B;
}
case unionArray: {
const UnionArray &A=static_cast<const UnionArray&>(a);
const UnionArray &B=static_cast<const UnionArray&>(b);
return A==B;
}
default:
throw std::logic_error("Invalid Field type in comparision");
}
}
bool operator==(const Scalar& a, const Scalar& b)
{
if(&a==&b)
return true;
return a.getScalarType()==b.getScalarType();
}
bool operator==(const ScalarArray& a, const ScalarArray& b)
{
if(&a==&b)
return true;
return a.getElementType()==b.getElementType();
}
bool operator==(const Structure& a, const Structure& b)
{
if(&a==&b)
return true;
if (a.getID()!=b.getID())
return false;
size_t nflds=a.getNumberFields();
if (b.getNumberFields()!=nflds)
return false;
// std::equals does not work, since FieldConstPtrArray is an array of shared_pointers
FieldConstPtrArray af = a.getFields();
FieldConstPtrArray bf = b.getFields();
for (size_t i = 0; i < nflds; i++)
if (*(af[i].get()) != *(bf[i].get()))
return false;
StringArray an = a.getFieldNames();
StringArray bn = b.getFieldNames();
return std::equal( an.begin(), an.end(), bn.begin() );
}
bool operator==(const StructureArray& a, const StructureArray& b)
{
return *(a.getStructure().get())==*(b.getStructure().get());
}
bool operator==(const Union& a, const Union& b)
{
if(&a==&b)
return true;
if (a.getID()!=b.getID())
return false;
size_t nflds=a.getNumberFields();
if (b.getNumberFields()!=nflds)
return false;
// std::equals does not work, since FieldConstPtrArray is an array of shared_pointers
FieldConstPtrArray af = a.getFields();
FieldConstPtrArray bf = b.getFields();
for (size_t i = 0; i < nflds; i++)
if (*(af[i].get()) != *(bf[i].get()))
return false;
StringArray an = a.getFieldNames();
StringArray bn = b.getFieldNames();
return std::equal( an.begin(), an.end(), bn.begin() );
}
bool operator==(const UnionArray& a, const UnionArray& b)
{
return *(a.getUnion().get())==*(b.getUnion().get());
}
// PVXXX object comparison
namespace {
// fully typed comparisons
template<typename T>
bool compareScalar(const PVScalarValue<T>* left, const PVScalarValue<T>* right)
{
return left->get()==right->get();
}
template<typename T>
bool compareArray(const PVValueArray<T>* left, const PVValueArray<T>* right)
{
typename PVValueArray<T>::const_svector lhs(left->view()), rhs(right->view());
return std::equal(lhs.begin(), lhs.end(), rhs.begin());
}
// partially typed comparisons
bool compareField(const PVScalar* left, const PVScalar* right)
{
ScalarType lht = left->getScalar()->getScalarType();
if(lht != right->getScalar()->getScalarType())
return false;
switch(lht) {
#define OP(ENUM, TYPE) case ENUM: return compareScalar(static_cast<const PVScalarValue<TYPE>*>(left), static_cast<const PVScalarValue<TYPE>*>(right))
OP(pvBoolean, uint8);
OP(pvUByte, uint8);
OP(pvByte, int8);
OP(pvUShort, uint16);
OP(pvShort, int16);
OP(pvUInt, uint32);
OP(pvInt, int32);
OP(pvULong, uint64);
OP(pvLong, int64);
OP(pvFloat, float);
OP(pvDouble, double);
#undef OP
case pvString: {
const PVString *a=static_cast<const PVString*>(left), *b=static_cast<const PVString*>(right);
return a->get()==b->get();
}
}
throw std::logic_error("PVScalar with invalid scalar type!");
}
bool compareField(const PVScalarArray* left, const PVScalarArray* right)
{
ScalarType lht = left->getScalarArray()->getElementType();
if(lht != right->getScalarArray()->getElementType())
return false;
if(left->getLength()!=right->getLength())
return false;
switch(lht) {
#define OP(ENUM, TYPE) case ENUM: return compareArray(static_cast<const PVValueArray<TYPE>*>(left), static_cast<const PVValueArray<TYPE>*>(right))
OP(pvBoolean, uint8);
OP(pvUByte, uint8);
OP(pvByte, int8);
OP(pvUShort, uint16);
OP(pvShort, int16);
OP(pvUInt, uint32);
OP(pvInt, int32);
OP(pvULong, uint64);
OP(pvLong, int64);
OP(pvFloat, float);
OP(pvDouble, double);
OP(pvString, string);
#undef OP
}
throw std::logic_error("PVScalarArray with invalid element type!");
}
bool compareField(const PVStructure* left, const PVStructure* right)
{
StructureConstPtr ls = left->getStructure();
if(*ls!=*right->getStructure())
return false;
const PVFieldPtrArray& lf = left->getPVFields();
const PVFieldPtrArray& rf = right->getPVFields();
for(size_t i=0, nfld=ls->getNumberFields(); i<nfld; i++) {
if(*lf[i]!=*rf[i])
return false;
}
return true;
}
bool compareField(const PVStructureArray* left, const PVStructureArray* right)
{
if(*left->getStructureArray()->getStructure()
!= *right->getStructureArray()->getStructure())
return false;
PVStructureArray::const_svector ld=left->view(), rd=right->view();
if(ld.size()!=rd.size())
return false;
PVStructureArray::const_svector::const_iterator lit, lend, rit;
for(lit=ld.begin(), lend=ld.end(), rit=rd.begin();
lit!=lend;
++lit, ++rit)
{
if(**lit != **rit)
return false;
}
return true;
}
bool compareField(const PVUnion* left, const PVUnion* right)
{
UnionConstPtr ls = left->getUnion();
if(*ls!=*right->getUnion())
return false;
if (ls->isVariant())
{
PVFieldPtr lval = left->get();
if (lval.get() == 0)
return right->get().get() == 0;
else
return *(lval.get()) == *(right->get().get());
}
else
{
int32 lix = left->getSelectedIndex();
if (lix == right->getSelectedIndex())
{
if (lix == PVUnion::UNDEFINED_INDEX || *(left->get()) == *(right->get().get()))
return true;
else
return false;
}
else
return false;
}
}
bool compareField(const PVUnionArray* left, const PVUnionArray* right)
{
if(*left->getUnionArray()->getUnion()
!= *right->getUnionArray()->getUnion())
return false;
PVUnionArray::const_svector ld=left->view(), rd=right->view();
if(ld.size()!=rd.size())
return false;
PVUnionArray::const_svector::const_iterator lit, lend, rit;
for(lit=ld.begin(), lend=ld.end(), rit=rd.begin();
lit!=lend;
++lit, ++rit)
{
if(**lit != **rit)
return false;
}
return true;
}
} // end namespace
// untyped comparison
bool operator==(const PVField& left, const PVField& right)
{
if(&left == &right)
return true;
Type lht = left.getField()->getType();
if(lht != right.getField()->getType())
return false;
switch(lht) {
case scalar: return compareField(static_cast<const PVScalar*>(&left), static_cast<const PVScalar*>(&right));
case scalarArray: return compareField(static_cast<const PVScalarArray*>(&left), static_cast<const PVScalarArray*>(&right));
case structure: return compareField(static_cast<const PVStructure*>(&left), static_cast<const PVStructure*>(&right));
case structureArray: return compareField(static_cast<const PVStructureArray*>(&left), static_cast<const PVStructureArray*>(&right));
case union_: return compareField(static_cast<const PVUnion*>(&left), static_cast<const PVUnion*>(&right));
case unionArray: return compareField(static_cast<const PVUnionArray*>(&left), static_cast<const PVUnionArray*>(&right));
}
throw std::logic_error("PVField with invalid type!");
}
}} // namespace epics::pvData

535
src/factory/Convert.cpp Normal file
View File

@@ -0,0 +1,535 @@
/* Convert.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
*/
#include <cstdio>
#include <string>
#include <vector>
#include <stdexcept>
#include <typeinfo>
#define epicsExportSharedSymbols
#include <pv/lock.h>
#include <pv/pvIntrospect.h>
#include <pv/pvData.h>
#include <pv/convert.h>
#include <pv/printer.h>
using std::tr1::static_pointer_cast;
using std::size_t;
using std::string;
namespace epics { namespace pvData {
static std::vector<string> split(string commaSeparatedList) {
string::size_type numValues = 1;
string::size_type index=0;
while(true) {
string::size_type pos = commaSeparatedList.find(',',index);
if(pos==string::npos) break;
numValues++;
index = pos +1;
}
std::vector<string> valueList(numValues,"");
index=0;
for(size_t i=0; i<numValues; i++) {
size_t pos = commaSeparatedList.find(',',index);
string value = commaSeparatedList.substr(index,pos);
valueList[i] = value;
index = pos +1;
}
return valueList;
}
void Convert::getString(string *buf,PVField const *pvField,int /*indentLevel*/)
{
// TODO indextLevel ignored
std::ostringstream strm;
strm << pvField->dumpValue(strm) << std::endl;
// PrinterPlain p;
// p.setStream(strm);
// p.print(*pvField);
strm.str().swap(*buf);
}
size_t Convert::fromString(PVStructurePtr const &pvStructure, StringArray const & from, size_t fromStartIndex)
{
size_t processed = 0;
PVFieldPtrArray const & fieldsData = pvStructure->getPVFields();
if (fieldsData.size() != 0) {
size_t length = pvStructure->getStructure()->getNumberFields();
for(size_t i=0; i<length; i++) {
PVFieldPtr fieldField = fieldsData[i];
Type type = fieldField->getField()->getType();
if(type==structure) {
PVStructurePtr pv = static_pointer_cast<PVStructure>(fieldField);
size_t count = fromString(pv, from, fromStartIndex);
processed += count;
fromStartIndex += count;
}
else if(type==scalarArray) {
PVScalarArrayPtr pv = static_pointer_cast<PVScalarArray>(fieldField);
size_t count = fromString(pv, from[fromStartIndex]);
processed += count;
fromStartIndex += count;
}
else if(type==scalar) {
PVScalarPtr pv = static_pointer_cast<PVScalar>(fieldField);
fromString(pv, from[fromStartIndex++]);
processed++;
}
else {
// union, structureArray, unionArray not supported
std::ostringstream oss;
oss << "Convert::fromString unsupported fieldType " << type;
throw std::logic_error(oss.str());
}
}
}
return processed;
}
size_t Convert::fromString(PVScalarArrayPtr const &pv, string from)
{
if(from[0]=='[' && from[from.length()]==']') {
size_t offset = from.rfind(']');
from = from.substr(1, offset);
}
std::vector<string> valueList(split(from));
size_t length = valueList.size();
size_t num = fromStringArray(pv,0,length,valueList,0);
if(num<length) length = num;
pv->setLength(length);
return length;
}
size_t Convert::fromStringArray(PVScalarArrayPtr const &pv,
size_t offset, size_t length,
StringArray const & from,
size_t fromOffset)
{
size_t alen = pv->getLength();
if(offset==0 && length>=alen) {
// replace all existing elements
assert(from.size()>=fromOffset+length);
PVStringArray::svector data(length);
std::copy(from.begin()+fromOffset,
from.begin()+fromOffset+length,
data.begin());
PVStringArray::const_svector temp(freeze(data));
pv->putFrom<string>(temp);
return length;
} else {
// partial update.
throw std::runtime_error("fromStringArray: partial update not implemented");
}
}
size_t Convert::toStringArray(PVScalarArrayPtr const & pv,
size_t offset, size_t length,
StringArray &to, size_t toOffset)
{
PVStringArray::const_svector data;
pv->getAs<string>(data);
data.slice(offset, length);
if(toOffset+data.size() > to.size())
to.resize(toOffset+data.size());
std::copy(data.begin()+toOffset, data.end(), to.begin());
return data.size();
}
bool Convert::isCopyCompatible(FieldConstPtr const &from, FieldConstPtr const &to)
{
if(from->getType()!=to->getType()) return false;
switch(from->getType()) {
case scalar:
{
ScalarConstPtr xxx = static_pointer_cast<const Scalar>(from);
ScalarConstPtr yyy = static_pointer_cast<const Scalar>(to);
return isCopyScalarCompatible(xxx,yyy);
}
case scalarArray:
{
ScalarArrayConstPtr xxx = static_pointer_cast<const ScalarArray>(from);
ScalarArrayConstPtr yyy = static_pointer_cast<const ScalarArray>(to);
return isCopyScalarArrayCompatible(xxx,yyy);
}
case structure:
{
StructureConstPtr xxx = static_pointer_cast<const Structure>(from);
StructureConstPtr yyy = static_pointer_cast<const Structure>(to);
return isCopyStructureCompatible(xxx,yyy);
}
case structureArray:
{
StructureArrayConstPtr xxx = static_pointer_cast<const StructureArray>(from);
StructureArrayConstPtr yyy = static_pointer_cast<const StructureArray>(to);
return isCopyStructureArrayCompatible(xxx,yyy);
}
case union_:
{
UnionConstPtr xxx = static_pointer_cast<const Union>(from);
UnionConstPtr yyy = static_pointer_cast<const Union>(to);
return isCopyUnionCompatible(xxx,yyy);
}
case unionArray:
{
UnionArrayConstPtr xxx = static_pointer_cast<const UnionArray>(from);
UnionArrayConstPtr yyy = static_pointer_cast<const UnionArray>(to);
return isCopyUnionArrayCompatible(xxx,yyy);
}
}
string message("Convert::isCopyCompatible should never get here");
throw std::logic_error(message);
}
void Convert::copy(PVFieldPtr const & from, PVFieldPtr const & to)
{
switch(from->getField()->getType()) {
case scalar:
{
PVScalarPtr xxx = static_pointer_cast<PVScalar>(from);
PVScalarPtr yyy = static_pointer_cast<PVScalar>(to);
copyScalar(xxx,yyy);
return;
}
case scalarArray:
{
PVScalarArrayPtr fromArray = static_pointer_cast<PVScalarArray>(from);
PVScalarArrayPtr toArray = static_pointer_cast<PVScalarArray>(to);
toArray->assign(*fromArray.get());
return;
}
case structure:
{
PVStructurePtr xxx = static_pointer_cast<PVStructure>(from);
PVStructurePtr yyy = static_pointer_cast<PVStructure>(to);
copyStructure(xxx,yyy);
return;
}
case structureArray: {
PVStructureArrayPtr fromArray = static_pointer_cast<PVStructureArray>(from);
PVStructureArrayPtr toArray = static_pointer_cast<PVStructureArray>(to);
copyStructureArray(fromArray,toArray);
return;
}
case union_:
{
PVUnionPtr xxx = static_pointer_cast<PVUnion>(from);
PVUnionPtr yyy = static_pointer_cast<PVUnion>(to);
copyUnion(xxx,yyy);
return;
}
case unionArray: {
PVUnionArrayPtr fromArray = static_pointer_cast<PVUnionArray>(from);
PVUnionArrayPtr toArray = static_pointer_cast<PVUnionArray>(to);
copyUnionArray(fromArray,toArray);
return;
}
}
}
bool Convert::isCopyScalarCompatible(
ScalarConstPtr const & fromField, ScalarConstPtr const & toField)
{
ScalarType fromScalarType = fromField->getScalarType();
ScalarType toScalarType = toField->getScalarType();
if(fromScalarType==toScalarType) return true;
if(ScalarTypeFunc::isNumeric(fromScalarType)
&& ScalarTypeFunc::isNumeric(toScalarType)) return true;
if(fromScalarType==pvString) return true;
if(toScalarType==pvString) return true;
return false;
}
void Convert::copyScalar(PVScalarPtr const & from, PVScalarPtr const & to)
{
if(to->isImmutable()) {
if(from==to) return;
string message("Convert.copyScalar destination is immutable");
throw std::invalid_argument(message);
}
to->assign(*from.get());
}
bool Convert::isCopyScalarArrayCompatible(ScalarArrayConstPtr const &fromArray,
ScalarArrayConstPtr const &toArray)
{
ScalarType fromType = fromArray->getElementType();
ScalarType toType = toArray->getElementType();
if(fromType==toType) return true;
if(ScalarTypeFunc::isNumeric(fromType)
&& ScalarTypeFunc::isNumeric(toType)) return true;
if(toType==pvString) return true;
if(fromType==pvString) return true;
return false;
}
bool Convert::isCopyStructureCompatible(
StructureConstPtr const &fromStruct, StructureConstPtr const &toStruct)
{
FieldConstPtrArray fromFields = fromStruct->getFields();
FieldConstPtrArray toFields = toStruct->getFields();
size_t length = fromStruct->getNumberFields();
if(length!=toStruct->getNumberFields()) return false;
for(size_t i=0; i<length; i++) {
FieldConstPtr from = fromFields[i];
FieldConstPtr to = toFields[i];
Type fromType = from->getType();
Type toType = to->getType();
if(fromType!=toType) return false;
switch(fromType) {
case scalar:
{
ScalarConstPtr xxx = static_pointer_cast<const Scalar>(from);
ScalarConstPtr yyy = static_pointer_cast<const Scalar>(to);
if(!isCopyScalarCompatible(xxx,yyy)) return false;
}
break;
case scalarArray:
{
ScalarArrayConstPtr xxx = static_pointer_cast<const ScalarArray>(from);
ScalarArrayConstPtr yyy = static_pointer_cast<const ScalarArray>(to);
if(!isCopyScalarArrayCompatible(xxx,yyy)) return false;
}
break;
case structure:
{
StructureConstPtr xxx = static_pointer_cast<const Structure>(from);
StructureConstPtr yyy = static_pointer_cast<const Structure>(to);
if(!isCopyStructureCompatible(xxx,yyy)) return false;
}
break;
case structureArray:
{
StructureArrayConstPtr xxx = static_pointer_cast<const StructureArray>(from);
StructureArrayConstPtr yyy = static_pointer_cast<const StructureArray>(to);
if(!isCopyStructureArrayCompatible(xxx,yyy)) return false;
}
case union_:
{
UnionConstPtr xxx = static_pointer_cast<const Union>(from);
UnionConstPtr yyy = static_pointer_cast<const Union>(to);
if(!isCopyUnionCompatible(xxx,yyy)) return false;
}
break;
case unionArray:
{
UnionArrayConstPtr xxx = static_pointer_cast<const UnionArray>(from);
UnionArrayConstPtr yyy = static_pointer_cast<const UnionArray>(to);
if(!isCopyUnionArrayCompatible(xxx,yyy)) return false;
}
break;
}
}
return true;
}
void Convert::copyStructure(PVStructurePtr const & from, PVStructurePtr const & to)
{
if(to->isImmutable()) {
if(from==to) return;
throw std::invalid_argument("Convert.copyStructure destination is immutable");
}
if(from==to) return;
PVFieldPtrArray const & fromDatas = from->getPVFields();
PVFieldPtrArray const & toDatas = to->getPVFields();
if(from->getStructure()->getNumberFields()
!= to->getStructure()->getNumberFields()) {
string message("Convert.copyStructure Illegal copyStructure");
throw std::invalid_argument(message);
}
size_t numberFields = from->getStructure()->getNumberFields();
if(numberFields>=2) {
string name0 = fromDatas[0]->getFieldName();
string name1 = fromDatas[1]->getFieldName();
// look for enumerated structure and copy choices first
if(name0.compare("index")==0 && name1.compare("choices")==0) {
FieldConstPtr fieldIndex = fromDatas[0]->getField();
FieldConstPtr fieldChoices = fromDatas[1]->getField();
if(fieldIndex->getType()==scalar
&& fieldChoices->getType()==scalarArray) {
PVScalarPtr pvScalar = static_pointer_cast<PVScalar>(fromDatas[0]);
PVScalarArrayPtr pvArray =
static_pointer_cast<PVScalarArray>(fromDatas[1]);
if((pvScalar->getScalar()->getScalarType()==pvInt)
&& (pvArray->getScalarArray()->getElementType()==pvString)) {
PVScalarArrayPtr toArray =
static_pointer_cast<PVScalarArray>(toDatas[1]);
toArray->assign(*pvArray.get());
PVScalarPtr toScalar = static_pointer_cast<PVScalar>(toDatas[0]);
copyScalar(pvScalar,toScalar);
return;
}
}
}
}
for(size_t i=0; i < numberFields; i++) {
PVFieldPtr fromData = fromDatas[i];
PVFieldPtr toData = toDatas[i];
Type fromType = fromData->getField()->getType();
Type toType = toData->getField()->getType();
if(fromType!=toType) {
string message("Convert.copyStructure Illegal copyStructure");
throw std::invalid_argument(message);
}
if(toData->isImmutable()) {
if(fromData==toData) return;
throw std::invalid_argument("Convert.copyStructure destination is immutable");
}
switch(fromType) {
case scalar:
{
PVScalarPtr xxx = static_pointer_cast<PVScalar>(fromData);
PVScalarPtr yyy = static_pointer_cast<PVScalar>(toData);
copyScalar(xxx,yyy);
break;
}
case scalarArray:
{
PVScalarArrayPtr fromArray = static_pointer_cast<PVScalarArray>(fromData);
PVScalarArrayPtr toArray = static_pointer_cast<PVScalarArray>(toData);
toArray->assign(*fromArray.get());
break;
}
case structure:
{
PVStructurePtr xxx = static_pointer_cast<PVStructure>(fromData);
PVStructurePtr yyy = static_pointer_cast<PVStructure>(toData);
copyStructure(xxx,yyy);
break;
}
case structureArray:
{
PVStructureArrayPtr fromArray =
static_pointer_cast<PVStructureArray>(fromData);
PVStructureArrayPtr toArray =
static_pointer_cast<PVStructureArray>(toData);
copyStructureArray(fromArray,toArray);
break;
}
case union_:
{
PVUnionPtr xxx = static_pointer_cast<PVUnion>(fromData);
PVUnionPtr yyy = static_pointer_cast<PVUnion>(toData);
copyUnion(xxx,yyy);
break;
}
case unionArray:
{
PVUnionArrayPtr fromArray =
static_pointer_cast<PVUnionArray>(fromData);
PVUnionArrayPtr toArray =
static_pointer_cast<PVUnionArray>(toData);
copyUnionArray(fromArray,toArray);
break;
}
}
}
}
bool Convert::isCopyUnionCompatible(
UnionConstPtr const &from, UnionConstPtr const &to)
{
return *(from.get()) == *(to.get());
}
void Convert::copyUnion(PVUnionPtr const & from, PVUnionPtr const & to)
{
if(to->isImmutable()) {
if(from==to) return;
throw std::invalid_argument("Convert.copyUnion destination is immutable");
}
if(from==to) return;
if(!isCopyUnionCompatible(from->getUnion(), to->getUnion())) {
throw std::invalid_argument("Illegal copyUnion");
}
PVFieldPtr fromValue = from->get();
if (from->getUnion()->isVariant())
{
if (fromValue.get() == 0)
to->set(PVFieldPtr());
else
to->set(getPVDataCreate()->createPVField(fromValue)); // clone value // TODO cache getPVDataCreate()
}
else
{
if (fromValue.get() == 0)
to->select(PVUnion::UNDEFINED_INDEX);
else
to->set(from->getSelectedFieldName(),from->get());
}
}
bool Convert::isCopyStructureArrayCompatible(
StructureArrayConstPtr const &from, StructureArrayConstPtr const &to)
{
StructureConstPtr xxx = from->getStructure();
StructureConstPtr yyy = to->getStructure();
return isCopyStructureCompatible(xxx,yyy);
}
void Convert::copyStructureArray(
PVStructureArrayPtr const & from, PVStructureArrayPtr const & to)
{
if(from==to) {
return;
} else if(to->isImmutable()) {
throw std::invalid_argument("Convert.copyStructureArray destination is immutable");
}
to->replace(from->view());
}
bool Convert::isCopyUnionArrayCompatible(
UnionArrayConstPtr const &from, UnionArrayConstPtr const &to)
{
UnionConstPtr xxx = from->getUnion();
UnionConstPtr yyy = to->getUnion();
return isCopyUnionCompatible(xxx,yyy);
}
void Convert::copyUnionArray(
PVUnionArrayPtr const & from, PVUnionArrayPtr const & to)
{
if(from==to) {
return;
} else if(to->isImmutable()) {
throw std::invalid_argument("Convert.copyUnionArray destination is immutable");
}
to->replace(from->view());
}
void Convert::newLine(string *buffer, int indentLevel)
{
*buffer += "\n";
*buffer += string(indentLevel*4, ' ');
}
ConvertPtr Convert::getConvert()
{
static ConvertPtr convert;
static Mutex mutex;
Lock xx(mutex);
if(convert.get()==0) {
convert = ConvertPtr(new Convert());
}
return convert;
}
}}

File diff suppressed because it is too large Load Diff

23
src/factory/Makefile Normal file
View File

@@ -0,0 +1,23 @@
# This is a Makefile fragment, see ../Makefile
SRC_DIRS += $(PVDATA_SRC)/factory
INC += factory.h
LIBSRCS += TypeFunc.cpp
LIBSRCS += FieldCreateFactory.cpp
LIBSRCS += PVField.cpp
LIBSRCS += PVScalar.cpp
LIBSRCS += PVArray.cpp
LIBSRCS += PVScalarArray.cpp
LIBSRCS += PVStructure.cpp
LIBSRCS += PVStructureArray.cpp
LIBSRCS += PVUnion.cpp
LIBSRCS += PVUnionArray.cpp
LIBSRCS += PVDataCreateFactory.cpp
LIBSRCS += Convert.cpp
LIBSRCS += pvSubArrayCopy.cpp
LIBSRCS += Compare.cpp
LIBSRCS += StandardField.cpp
LIBSRCS += StandardPVField.cpp
LIBSRCS += printer.cpp

56
src/factory/PVArray.cpp Normal file
View File

@@ -0,0 +1,56 @@
/*PVArray.cpp*/
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
*/
#include <cstddef>
#include <cstdlib>
#include <string>
#include <cstdio>
#define epicsExportSharedSymbols
#include <pv/pvData.h>
#include <pv/factory.h>
using std::size_t;
namespace epics { namespace pvData {
PVArray::PVArray(FieldConstPtr const & field)
: PVField(field),capacityMutable(true)
{ }
void PVArray::setImmutable()
{
capacityMutable = false;
PVField::setImmutable();
}
bool PVArray::isCapacityMutable() const
{
if(PVField::isImmutable()) {
return false;
}
return capacityMutable;
}
void PVArray::setCapacityMutable(bool isMutable)
{
if(isMutable && PVField::isImmutable()) {
throw std::runtime_error("field is immutable");
}
capacityMutable = isMutable;
}
std::ostream& operator<<(format::array_at_internal const& manip, const PVArray& array)
{
return array.dumpValue(manip.stream, manip.index);
}
}}

View File

@@ -7,13 +7,17 @@
/**
* @author mrk
*/
#ifdef _WIN32
#define NOMINMAX
#endif
#include <cstddef>
#include <cstdlib>
#include <string>
#include <cstdio>
#define epicsExportSharedSymbols
#include <pv/lock.h>
#include <pv/pvIntrospect.h>
#include <pv/pvData.h>
@@ -23,11 +27,38 @@
using std::tr1::static_pointer_cast;
using std::size_t;
using std::string;
using std::min;
namespace epics { namespace pvData {
template<> const ScalarType PVBoolean::typeCode = pvBoolean;
template<> const ScalarType PVByte::typeCode = pvByte;
template<> const ScalarType PVShort::typeCode = pvShort;
template<> const ScalarType PVInt::typeCode = pvInt;
template<> const ScalarType PVLong::typeCode = pvLong;
template<> const ScalarType PVUByte::typeCode = pvUByte;
template<> const ScalarType PVUShort::typeCode = pvUShort;
template<> const ScalarType PVUInt::typeCode = pvUInt;
template<> const ScalarType PVULong::typeCode = pvULong;
template<> const ScalarType PVFloat::typeCode = pvFloat;
template<> const ScalarType PVDouble::typeCode = pvDouble;
template<> const ScalarType PVScalarValue<string>::typeCode = pvString;
template<> const ScalarType PVBooleanArray::typeCode = pvBoolean;
template<> const ScalarType PVByteArray::typeCode = pvByte;
template<> const ScalarType PVShortArray::typeCode = pvShort;
template<> const ScalarType PVIntArray::typeCode = pvInt;
template<> const ScalarType PVLongArray::typeCode = pvLong;
template<> const ScalarType PVUByteArray::typeCode = pvUByte;
template<> const ScalarType PVUShortArray::typeCode = pvUShort;
template<> const ScalarType PVUIntArray::typeCode = pvUInt;
template<> const ScalarType PVULongArray::typeCode = pvULong;
template<> const ScalarType PVFloatArray::typeCode = pvFloat;
template<> const ScalarType PVDoubleArray::typeCode = pvDouble;
template<> const ScalarType PVStringArray::typeCode = pvString;
/** Default storage for scalar values
*/
template<typename T>
@@ -53,7 +84,7 @@ template<typename T>
BasePVScalar<T>::BasePVScalar(ScalarConstPtr const & scalar)
: PVScalarValue<T>(scalar),value(0)
{}
//Note: '0' is a suitable default for all POD types (not String)
//Note: '0' is a suitable default for all POD types (not string)
template<typename T>
BasePVScalar<T>::~BasePVScalar() {}
@@ -62,7 +93,11 @@ template<typename T>
T BasePVScalar<T>::get() const { return value;}
template<typename T>
void BasePVScalar<T>::put(T val){value = val;}
void BasePVScalar<T>::put(T val)
{
value = val;
PVField::postPut();
}
template<typename T>
void BasePVScalar<T>::serialize(ByteBuffer *pbuffer,
@@ -94,14 +129,14 @@ typedef BasePVScalar<double> BasePVDouble;
// BasePVString is special case, since it implements SerializableArray
class BasePVString : public PVString {
public:
typedef String value_type;
typedef String* pointer;
typedef const String* const_pointer;
typedef string value_type;
typedef string* pointer;
typedef const string* const_pointer;
BasePVString(ScalarConstPtr const & scalar);
virtual ~BasePVString();
virtual String get() const ;
virtual void put(String val);
virtual string get() const ;
virtual void put(string val);
virtual void serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher) const;
virtual void deserialize(ByteBuffer *pbuffer,
@@ -109,7 +144,7 @@ public:
virtual void serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher, size_t offset, size_t count) const;
private:
String value;
string value;
};
BasePVString::BasePVString(ScalarConstPtr const & scalar)
@@ -118,9 +153,13 @@ BasePVString::BasePVString(ScalarConstPtr const & scalar)
BasePVString::~BasePVString() {}
String BasePVString::get() const { return value;}
string BasePVString::get() const { return value;}
void BasePVString::put(String val){value = val;}
void BasePVString::put(string val)
{
value = val;
postPut();
}
void BasePVString::serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher) const
@@ -139,9 +178,9 @@ void BasePVString::serialize(ByteBuffer *pbuffer,
{
// check bounds
const size_t length = /*(value == null) ? 0 :*/ value.length();
if (offset < 0) offset = 0;
else if (offset > length) offset = length;
if (count < 0) count = length;
/*if (offset < 0) offset = 0;
else*/ if (offset > length) offset = length;
//if (count < 0) count = length;
const size_t maxCount = length - offset;
if (count > maxCount)
@@ -162,157 +201,79 @@ public:
typedef const std::vector<T> const_vector;
typedef std::tr1::shared_ptr<vector> shared_vector;
typedef ::epics::pvData::shared_vector<T> svector;
typedef ::epics::pvData::shared_vector<const T> const_svector;
DefaultPVArray(ScalarArrayConstPtr const & scalarArray);
virtual ~DefaultPVArray();
virtual size_t getLength() const {return value.size();}
virtual size_t getCapacity() const {return value.capacity();}
virtual void setCapacity(size_t capacity);
virtual void setLength(size_t length);
virtual size_t get(size_t offset, size_t length, PVArrayData<T> &data) ;
virtual size_t put(size_t offset,size_t length, const_pointer from,
size_t fromOffset);
virtual void shareData(
std::tr1::shared_ptr<std::vector<T> > const & value,
std::size_t capacity,
std::size_t length);
virtual pointer get() ;
virtual pointer get() const ;
virtual vector const & getVector() { return *value.get(); }
virtual shared_vector const & getSharedVector(){return value;};
virtual const_svector view() const {return value;}
virtual void swap(const_svector &other);
virtual void replace(const const_svector& next);
// from Serializable
virtual void serialize(ByteBuffer *pbuffer,SerializableControl *pflusher) const;
virtual void deserialize(ByteBuffer *pbuffer,DeserializableControl *pflusher);
virtual void serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher, size_t offset, size_t count) const;
private:
shared_vector value;
const_svector value;
};
template<typename T>
T *DefaultPVArray<T>::get()
{
std::vector<T> *vec = value.get();
T *praw = &((*vec)[0]);
return praw;
}
template<typename T>
T *DefaultPVArray<T>::get() const
{
std::vector<T> *vec = value.get();
T *praw = &((*vec)[0]);
return praw;
}
template<typename T>
DefaultPVArray<T>::DefaultPVArray(ScalarArrayConstPtr const & scalarArray)
: PVValueArray<T>(scalarArray),
value(std::tr1::shared_ptr<std::vector<T> >(new std::vector<T>()))
value()
{ }
template<typename T>
DefaultPVArray<T>::~DefaultPVArray()
{ }
template<typename T>
void DefaultPVArray<T>::setCapacity(size_t capacity)
{
if(PVArray::getCapacity()==capacity) return;
if(!PVArray::isCapacityMutable()) {
std::string message("not capacityMutable");
PVField::message(message, errorMessage);
return;
if(this->isCapacityMutable()) {
value.reserve(capacity);
}
size_t length = PVArray::getLength();
if(length>capacity) length = capacity;
size_t oldCapacity = PVArray::getCapacity();
if(oldCapacity>capacity) {
std::vector<T> array;
array.reserve(capacity);
array.resize(length);
T * from = get();
for (size_t i=0; i<length; i++) array[i] = from[i];
value->swap(array);
} else {
value->reserve(capacity);
}
PVArray::setCapacityLength(capacity,length);
}
template<typename T>
void DefaultPVArray<T>::setLength(size_t length)
{
if(PVArray::getLength()==length) return;
size_t capacity = PVArray::getCapacity();
if(length>capacity) {
if(!PVArray::isCapacityMutable()) {
std::string message("not capacityMutable");
PVField::message(message, errorMessage);
return;
}
setCapacity(length);
}
value->resize(length);
PVArray::setCapacityLength(capacity,length);
if(this->isImmutable())
THROW_EXCEPTION2(std::logic_error,"Immutable");
if(length == value.size())
return;
else if(length < value.size())
value.slice(0, length);
else
value.resize(length);
}
template<typename T>
size_t DefaultPVArray<T>::get(size_t offset, size_t len, PVArrayData<T> &data)
void DefaultPVArray<T>::replace(const const_svector& next)
{
size_t n = len;
size_t length = this->getLength();
if(offset+len > length) {
n = length-offset;
if(n<0) n = 0;
}
data.data = *value.get();
data.offset = offset;
return n;
}
template<typename T>
size_t DefaultPVArray<T>::put(size_t offset,size_t len,
const_pointer from,size_t fromOffset)
{
if(PVField::isImmutable()) {
PVField::message("field is immutable",errorMessage);
return 0;
}
T * pvalue = get();
if(from==pvalue) return len;
if(len<1) return 0;
size_t length = this->getLength();
size_t capacity = this->getCapacity();
if(offset+len > length) {
size_t newlength = offset + len;
if(newlength>capacity) {
setCapacity(newlength);
newlength = this->getCapacity();
len = newlength - offset;
if(len<=0) return 0;
}
length = newlength;
setLength(length);
}
pvalue = get();
for(size_t i=0;i<len;i++) {
pvalue[i+offset] = from[i+fromOffset];
}
this->setLength(length);
value = next;
this->postPut();
return len;
}
template<typename T>
void DefaultPVArray<T>::shareData(
std::tr1::shared_ptr<std::vector<T> > const & sharedValue,
std::size_t capacity,
std::size_t length)
void DefaultPVArray<T>::swap(const_svector &other)
{
value = sharedValue;
PVArray::setCapacityLength(capacity,length);
if(this->isImmutable())
THROW_EXCEPTION2(std::logic_error,"Immutable");
value.swap(other);
}
template<typename T>
void DefaultPVArray<T>::serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher) const {
@@ -323,117 +284,122 @@ template<typename T>
void DefaultPVArray<T>::deserialize(ByteBuffer *pbuffer,
DeserializableControl *pcontrol) {
size_t size = SerializeHelper::readSize(pbuffer, pcontrol);
// if (size>0) { pcontrol->ensureData(sizeof(T)-1); pbuffer->align(sizeof(T)); }
if(size>=0) {
// prepare array, if necessary
if(size>this->getCapacity()) this->setCapacity(size);
// set new length
this->setLength(size);
// retrieve value from the buffer
size_t i = 0;
while(true) {
/*
size_t maxIndex = min(size-i, (int)(pbuffer->getRemaining()/sizeof(T)))+i;
for(; i<maxIndex; i++)
value[i] = pbuffer->get<T>();
*/
size_t maxCount = min(size-i, (pbuffer->getRemaining()/sizeof(T)));
pbuffer->getArray(get()+i, maxCount);
i += maxCount;
if(i<size)
pcontrol->ensureData(sizeof(T)); // this is not OK since can exceen max local buffer (size-i)*sizeof(T));
else
break;
}
svector nextvalue(thaw(value));
nextvalue.resize(size); // TODO: avoid copy of stuff we will then overwrite
T* cur = nextvalue.data();
// try to avoid deserializing from the buffer
// this is only possible if we do not need to do endian-swapping
if (!pbuffer->reverse<T>())
if (pcontrol->directDeserialize(pbuffer, (char*)cur, size, sizeof(T)))
{
// inform about the change?
PVField::postPut();
return;
}
// TODO null arrays (size == -1) not supported
// retrieve value from the buffer
size_t remaining = size;
while(remaining) {
const size_t have_bytes = pbuffer->getRemaining();
// correctly rounds down in an element is partially received
const size_t available = have_bytes/sizeof(T);
if(available == 0) {
// get at least one element
pcontrol->ensureData(sizeof(T));
continue;
}
const size_t n2read = std::min(remaining, available);
pbuffer->getArray(cur, n2read);
cur += n2read;
remaining -= n2read;
}
value = freeze(nextvalue);
// inform about the change?
PVField::postPut();
}
template<typename T>
void DefaultPVArray<T>::serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher, size_t offset, size_t count) const {
// cache
size_t length = this->getLength();
SerializableControl *pflusher, size_t offset, size_t count) const
{
//TODO: avoid incrementing the ref counter...
const_svector temp(value);
temp.slice(offset, count);
count = temp.size();
// check bounds
if(offset<0)
offset = 0;
else if(offset>length) offset = length;
if(count<0) count = length;
SerializeHelper::writeSize(temp.size(), pbuffer, pflusher);
size_t maxCount = length-offset;
if(count>maxCount) count = maxCount;
const T* cur = temp.data();
// write
SerializeHelper::writeSize(count, pbuffer, pflusher);
//if (count == 0) return; pcontrol->ensureData(sizeof(T)-1); pbuffer->align(sizeof(T));
size_t end = offset+count;
size_t i = offset;
while(true) {
/*
size_t maxIndex = min<int>(end-i, (int)(pbuffer->getRemaining()/sizeof(T)))+i;
for(; i<maxIndex; i++)
pbuffer->put<T>(value[i]);
*/
size_t maxCount = min<int>(end-i, (int)(pbuffer->getRemaining()/sizeof(T)));
T * pvalue = const_cast<T *>(get());
pbuffer->putArray(pvalue+i, maxCount);
i += maxCount;
if(i<end)
// try to avoid copying into the buffer
// this is only possible if we do not need to do endian-swapping
if (!pbuffer->reverse<T>())
if (pflusher->directSerialize(pbuffer, (const char*)cur, count, sizeof(T)))
return;
while(count) {
const size_t empty = pbuffer->getRemaining();
const size_t space_for = empty/sizeof(T);
if(space_for==0) {
pflusher->flushSerializeBuffer();
else
break;
// Can we be certain that more space is now free???
// If not then we spinnnnnnnnn
continue;
}
const size_t n2send = std::min(count, space_for);
pbuffer->putArray(cur, n2send);
cur += n2send;
count -= n2send;
}
}
// specializations for String
// specializations for string
template<>
void DefaultPVArray<String>::deserialize(ByteBuffer *pbuffer,
void DefaultPVArray<string>::deserialize(ByteBuffer *pbuffer,
DeserializableControl *pcontrol) {
size_t size = SerializeHelper::readSize(pbuffer, pcontrol);
if(size>=0) {
// prepare array, if necessary
if(size>getCapacity()) setCapacity(size);
// set new length
setLength(size);
// retrieve value from the buffer
String * pvalue = get();
for(size_t i = 0; i<size; i++) {
pvalue[i] = SerializeHelper::deserializeString(pbuffer,
pcontrol);
}
// inform about the change?
postPut();
svector nextvalue(thaw(value));
// Decide if we must re-allocate
if(size > nextvalue.size() || !nextvalue.unique())
nextvalue.resize(size);
else if(size < nextvalue.size())
nextvalue.slice(0, size);
string * pvalue = nextvalue.data();
for(size_t i = 0; i<size; i++) {
pvalue[i] = SerializeHelper::deserializeString(pbuffer,
pcontrol);
}
// TODO null arrays (size == -1) not supported
value = freeze(nextvalue);
// inform about the change?
postPut();
}
template<>
void DefaultPVArray<String>::serialize(ByteBuffer *pbuffer,
void DefaultPVArray<string>::serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher, size_t offset, size_t count) const {
size_t length = getLength();
// check bounds
if(offset<0)
offset = 0;
else if(offset>length) offset = length;
if(count<0) count = length;
const_svector temp(value);
temp.slice(offset, count);
size_t maxCount = length-offset;
if(count>maxCount) count = maxCount;
SerializeHelper::writeSize(temp.size(), pbuffer, pflusher);
// write
SerializeHelper::writeSize(count, pbuffer, pflusher);
size_t end = offset+count;
String * pvalue = get();
for(size_t i = offset; i<end; i++) {
const string * pvalue = temp.data();
for(size_t i = 0; i<temp.size(); i++) {
SerializeHelper::serializeString(pvalue[i], pbuffer, pflusher);
}
}
@@ -449,7 +415,7 @@ typedef DefaultPVArray<uint32> BasePVUIntArray;
typedef DefaultPVArray<uint64> BasePVULongArray;
typedef DefaultPVArray<float> BasePVFloatArray;
typedef DefaultPVArray<double> BasePVDoubleArray;
typedef DefaultPVArray<String> BasePVStringArray;
typedef DefaultPVArray<string> BasePVStringArray;
// Factory
@@ -476,6 +442,14 @@ PVFieldPtr PVDataCreate::createPVField(FieldConstPtr const & field)
StructureArrayConstPtr xx = static_pointer_cast<const StructureArray>(field);
return createPVStructureArray(xx);
}
case union_: {
UnionConstPtr xx = static_pointer_cast<const Union>(field);
return createPVUnion(xx);
}
case unionArray: {
UnionArrayConstPtr xx = static_pointer_cast<const UnionArray>(field);
return createPVUnionArray(xx);
}
}
throw std::logic_error("PVDataCreate::createPVField should never get here");
}
@@ -512,6 +486,21 @@ PVFieldPtr PVDataCreate::createPVField(PVFieldPtr const & fieldToClone)
getConvert()->copyStructureArray(from, to);
return to;
}
case union_:
{
PVUnionPtr pvUnion
= static_pointer_cast<PVUnion>(fieldToClone);
return createPVUnion(pvUnion);
}
case unionArray:
{
PVUnionArrayPtr from
= static_pointer_cast<PVUnionArray>(fieldToClone);
UnionArrayConstPtr unionArray = from->getUnionArray();
PVUnionArrayPtr to = createPVUnionArray(unionArray);
getConvert()->copyUnionArray(from, to);
return to;
}
}
throw std::logic_error("PVDataCreate::createPVField should never get here");
}
@@ -560,16 +549,6 @@ PVScalarPtr PVDataCreate::createPVScalar(PVScalarPtr const & scalarToClone)
ScalarType scalarType = scalarToClone->getScalar()->getScalarType();
PVScalarPtr pvScalar = createPVScalar(scalarType);
getConvert()->copyScalar(scalarToClone, pvScalar);
PVAuxInfoPtr from = scalarToClone->getPVAuxInfo();
PVAuxInfoPtr to = pvScalar->getPVAuxInfo();
PVAuxInfo::PVInfoMap & map = from->getInfoMap();
for(PVAuxInfo::PVInfoIter iter = map.begin(); iter!= map.end(); ++iter) {
String key = iter->first;
PVScalarPtr pvFrom = iter->second;
ScalarConstPtr scalar = pvFrom->getScalar();
PVScalarPtr pvTo = to->createInfo(key,scalar->getScalarType());
getConvert()->copyScalar(pvFrom,pvTo);
}
return pvScalar;
}
@@ -618,17 +597,7 @@ PVScalarArrayPtr PVDataCreate::createPVScalarArray(
{
PVScalarArrayPtr pvArray = createPVScalarArray(
arrayToClone->getScalarArray()->getElementType());
getConvert()->copyScalarArray(arrayToClone,0, pvArray,0,arrayToClone->getLength());
PVAuxInfoPtr from = arrayToClone->getPVAuxInfo();
PVAuxInfoPtr to = pvArray->getPVAuxInfo();
PVAuxInfo::PVInfoMap & map = from->getInfoMap();
for(PVAuxInfo::PVInfoIter iter = map.begin(); iter!= map.end(); ++iter) {
String key = iter->first;
PVScalarPtr pvFrom = iter->second;
ScalarConstPtr scalar = pvFrom->getScalar();
PVScalarPtr pvTo = to->createInfo(key,scalar->getScalarType());
getConvert()->copyScalar(pvFrom,pvTo);
}
pvArray->assign(*arrayToClone.get());
return pvArray;
}
@@ -644,6 +613,28 @@ PVStructurePtr PVDataCreate::createPVStructure(
return PVStructurePtr(new PVStructure(structure));
}
PVUnionArrayPtr PVDataCreate::createPVUnionArray(
UnionArrayConstPtr const & unionArray)
{
return PVUnionArrayPtr(new PVUnionArray(unionArray));
}
PVUnionPtr PVDataCreate::createPVUnion(
UnionConstPtr const & punion)
{
return PVUnionPtr(new PVUnion(punion));
}
PVUnionPtr PVDataCreate::createPVVariantUnion()
{
return PVUnionPtr(new PVUnion(fieldCreate->createVariantUnion()));
}
PVUnionArrayPtr PVDataCreate::createPVVariantUnionArray()
{
return PVUnionArrayPtr(new PVUnionArray(fieldCreate->createVariantUnionArray()));
}
PVStructurePtr PVDataCreate::createPVStructure(
StringArray const & fieldNames,PVFieldPtrArray const & pvFields)
{
@@ -659,6 +650,7 @@ PVStructurePtr PVDataCreate::createPVStructure(PVStructurePtr const & structToCl
{
FieldConstPtrArray field;
if(structToClone==0) {
// is this correct?!
FieldConstPtrArray fields(0);
StringArray fieldNames(0);
StructureConstPtr structure = fieldCreate->createStructure(fieldNames,fields);
@@ -670,6 +662,16 @@ PVStructurePtr PVDataCreate::createPVStructure(PVStructurePtr const & structToCl
return pvStructure;
}
PVUnionPtr PVDataCreate::createPVUnion(PVUnionPtr const & unionToClone)
{
PVUnionPtr punion(new PVUnion(unionToClone->getUnion()));
// set cloned value
punion->set(unionToClone->getSelectedIndex(), createPVField(unionToClone->get()));
return punion;
}
// TODO not thread-safe (local static initializers)
// TODO replace with non-locking singleton pattern
PVDataCreatePtr PVDataCreate::getPVDataCreate()
{
static PVDataCreatePtr pvDataCreate;

View File

@@ -11,6 +11,8 @@
#include <cstdlib>
#include <string>
#include <cstdio>
#define epicsExportSharedSymbols
#include <pv/lock.h>
#include <pv/pvData.h>
#include <pv/factory.h>
@@ -18,70 +20,21 @@
using std::tr1::const_pointer_cast;
using std::size_t;
using std::string;
namespace epics { namespace pvData {
PVField::PVField(FieldConstPtr field)
: notImplemented("not implemented"),
parent(NULL),field(field),
fieldOffset(0), nextFieldOffset(0),
immutable(false),
convert(getConvert())
immutable(false)
{
}
PVField::~PVField()
{ }
void PVField::message(
String message,
MessageType messageType,
String fullFieldName)
{
if(parent!=NULL) {
if(fullFieldName.length()>0) {
fullFieldName = fieldName + '.' + fullFieldName;
} else {
fullFieldName = fieldName;
}
parent->message(message,messageType,fullFieldName);
return;
}
message = fullFieldName + " " + message;
if(requester) {
requester->message(message,messageType);
} else {
printf("%s %s %s\n",
getMessageTypeName(messageType).c_str(),
fieldName.c_str(),
message.c_str());
}
}
void PVField::message(String message,MessageType messageType)
{
PVField::message(message,messageType,"");
}
String PVField::getFieldName() const
{
return fieldName;
}
void PVField::setRequester(RequesterPtr const &req)
{
if(parent!=NULL) {
throw std::logic_error(
"PVField::setRequester only legal for top level structure");
}
if(requester.get()!=NULL) {
if(requester.get()==req.get()) return;
throw std::logic_error(
"PVField::setRequester requester is already present");
}
requester = req;
}
size_t PVField::getFieldOffset() const
{
@@ -101,12 +54,6 @@ size_t PVField::getNumberFields() const
return (nextFieldOffset - fieldOffset);
}
PVAuxInfoPtr & PVField::getPVAuxInfo(){
if(pvAuxInfo.get()==NULL) {
pvAuxInfo = PVAuxInfoPtr(new PVAuxInfo(this));
}
return pvAuxInfo;
}
bool PVField::isImmutable() const {return immutable;}
@@ -116,49 +63,9 @@ const FieldConstPtr & PVField::getField() const {return field;}
PVStructure *PVField::getParent() const {return parent;}
void PVField::replacePVField(const PVFieldPtr & newPVField)
{
if(parent==NULL) {
throw std::logic_error("no parent");
}
PVFieldPtrArray pvFields = parent->getPVFields();
StructureConstPtr structure = parent->getStructure();
StringArray fieldNames = structure->getFieldNames();
for(size_t i=0; i<fieldNames.size(); i++) {
if(newPVField->getFieldName().compare(fieldNames[i]) == 0) {
pvFields[i] = newPVField;
return;
}
}
throw std::logic_error("Did not find field in parent");
}
void PVField::replaceField(FieldConstPtr &xxx)
{
field = xxx;
}
void PVField::renameField(String const & newName)
{
if(parent==NULL) {
throw std::logic_error("no parent");
}
std::tr1::shared_ptr<Structure> parentStructure = const_pointer_cast<Structure>(
parent->getStructure());
PVFieldPtrArray pvFields = parent->getPVFields();
for(size_t i=0; i<pvFields.size(); i++) {
if(pvFields[i].get()==this) {
parentStructure->renameField(i,newName);
fieldName = newName;
return;
}
}
throw std::logic_error("Did not find field in parent");
}
void PVField::postPut()
{
if(postHandler!=NULL) postHandler->postPut();
if(postHandler.get()!=NULL) postHandler->postPut();
}
void PVField::setPostHandler(PostHandlerPtr const &handler)
@@ -172,7 +79,7 @@ void PVField::setPostHandler(PostHandlerPtr const &handler)
postHandler = handler;
}
void PVField::setParentAndName(PVStructure * xxx,String const & name)
void PVField::setParentAndName(PVStructure * xxx,string const & name)
{
parent = xxx;
fieldName = name;
@@ -180,32 +87,25 @@ void PVField::setParentAndName(PVStructure * xxx,String const & name)
bool PVField::equals(PVField &pv)
{
return convert->equals(*this,pv);
return pv==*this;
}
void PVField::toString(StringBuilder buf)
std::ostream& operator<<(std::ostream& o, const PVField& f)
{
toString(buf,0);
}
return f.dumpValue(o);
};
void PVField::toString(StringBuilder buf,int indentLevel)
string PVField::getFullName() const
{
convert->getString(buf,this,indentLevel);
if(pvAuxInfo.get()!=NULL) pvAuxInfo->toString(buf,indentLevel);
string ret(fieldName);
for(PVField *fld=getParent(); fld; fld=fld->getParent())
{
if(fld->getFieldName().size()==0) break;
ret = fld->getFieldName() + '.' + ret;
}
return ret;
}
std::ostream& PVField::dumpValue(std::ostream& o) const
{
// default implementation
// each PVField class should implement it to avoid switch statement
// and string reallocation
String tmp;
convert->getString(&tmp,this,0);
return o << tmp;
}
std::ostream& operator<<(std::ostream& o, const PVField& f) { return f.dumpValue(o); };
void PVField::computeOffset(const PVField * pvField) {
const PVStructure * pvTop = pvField->getParent();
if(pvTop==NULL) {
@@ -219,8 +119,8 @@ void PVField::computeOffset(const PVField * pvField) {
} else {
while(pvTop->getParent()!=NULL) pvTop = pvTop->getParent();
}
int offset = 0;
int nextOffset = 1;
size_t offset = 0;
size_t nextOffset = 1;
PVFieldPtrArray pvFields = pvTop->getPVFields();
for(size_t i=0; i < pvTop->getStructure()->getNumberFields(); i++) {
offset = nextOffset;
@@ -229,7 +129,9 @@ void PVField::computeOffset(const PVField * pvField) {
switch(field->getType()) {
case scalar:
case scalarArray:
case structureArray:{
case structureArray:
case union_:
case unionArray: {
nextOffset++;
pvField->fieldOffset = offset;
pvField->nextFieldOffset = nextOffset;
@@ -248,8 +150,8 @@ void PVField::computeOffset(const PVField * pvField) {
}
void PVField::computeOffset(const PVField * pvField,size_t offset) {
int beginOffset = offset;
int nextOffset = offset + 1;
size_t beginOffset = offset;
size_t nextOffset = offset + 1;
const PVStructure *pvStructure = static_cast<const PVStructure *>(pvField);
const PVFieldPtrArray pvFields = pvStructure->getPVFields();
for(size_t i=0; i < pvStructure->getStructure()->getNumberFields(); i++) {
@@ -259,7 +161,9 @@ void PVField::computeOffset(const PVField * pvField,size_t offset) {
switch(field->getType()) {
case scalar:
case scalarArray:
case structureArray: {
case structureArray:
case union_:
case unionArray: {
nextOffset++;
pvSubField->fieldOffset = offset;
pvSubField->nextFieldOffset = nextOffset;

View File

@@ -11,6 +11,8 @@
#include <cstdlib>
#include <string>
#include <cstdio>
#define epicsExportSharedSymbols
#include <pv/pvData.h>
#include <pv/factory.h>

View File

@@ -11,6 +11,8 @@
#include <cstdlib>
#include <string>
#include <cstdio>
#define epicsExportSharedSymbols
#include <pv/pvData.h>
#include <pv/factory.h>
@@ -28,16 +30,4 @@ namespace epics { namespace pvData {
return static_pointer_cast<const ScalarArray>(PVField::getField());
}
template<>
std::ostream& PVValueArray<int8>::dumpValue(std::ostream& o, size_t index) const
{
return o << static_cast<int>(*(get() + index));
}
template<>
std::ostream& PVValueArray<uint8>::dumpValue(std::ostream& o, size_t index) const
{
return o << static_cast<unsigned int>(*(get() + index));
}
}}

385
src/factory/PVStructure.cpp Normal file
View File

@@ -0,0 +1,385 @@
/*PVStructure.cpp*/
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
*/
#include <cstddef>
#include <cstdlib>
#include <string>
#include <cstdio>
#include <vector>
#define epicsExportSharedSymbols
#include <pv/pvData.h>
#include <pv/pvIntrospect.h>
#include <pv/convert.h>
#include <pv/factory.h>
#include <pv/bitSet.h>
using std::tr1::static_pointer_cast;
using std::size_t;
using std::string;
namespace epics { namespace pvData {
PVFieldPtr PVStructure::nullPVField;
PVBooleanPtr PVStructure::nullPVBoolean;
PVBytePtr PVStructure::nullPVByte;
PVShortPtr PVStructure::nullPVShort;
PVIntPtr PVStructure::nullPVInt;
PVLongPtr PVStructure::nullPVLong;
PVUBytePtr PVStructure::nullPVUByte;
PVUShortPtr PVStructure::nullPVUShort;
PVUIntPtr PVStructure::nullPVUInt;
PVULongPtr PVStructure::nullPVULong;
PVFloatPtr PVStructure::nullPVFloat;
PVDoublePtr PVStructure::nullPVDouble;
PVStringPtr PVStructure::nullPVString;
PVStructurePtr PVStructure::nullPVStructure;
PVStructureArrayPtr PVStructure::nullPVStructureArray;
PVUnionPtr PVStructure::nullPVUnion;
PVUnionArrayPtr PVStructure::nullPVUnionArray;
PVScalarArrayPtr PVStructure::nullPVScalarArray;
static PVFieldPtr findSubField(
string const &fieldName,
const PVStructure *pvStructure);
PVStructure::PVStructure(StructureConstPtr const & structurePtr)
: PVField(structurePtr),
structurePtr(structurePtr),
extendsStructureName("")
{
size_t numberFields = structurePtr->getNumberFields();
FieldConstPtrArray fields = structurePtr->getFields();
StringArray fieldNames = structurePtr->getFieldNames();
// PVFieldPtrArray * xxx = const_cast<PVFieldPtrArray *>(&pvFields);
pvFields.reserve(numberFields);
PVDataCreatePtr pvDataCreate = getPVDataCreate();
for(size_t i=0; i<numberFields; i++) {
pvFields.push_back(pvDataCreate->createPVField(fields[i]));
}
for(size_t i=0; i<numberFields; i++) {
pvFields[i]->setParentAndName(this,fieldNames[i]);
}
}
PVStructure::PVStructure(StructureConstPtr const & structurePtr,
PVFieldPtrArray const & pvs
)
: PVField(structurePtr),
structurePtr(structurePtr),
extendsStructureName("")
{
size_t numberFields = structurePtr->getNumberFields();
StringArray fieldNames = structurePtr->getFieldNames();
pvFields.reserve(numberFields);
for(size_t i=0; i<numberFields; i++) {
pvFields.push_back(pvs[i]);
}
for(size_t i=0; i<numberFields; i++) {
pvFields[i]->setParentAndName(this,fieldNames[i]);
}
}
PVStructure::~PVStructure()
{
}
void PVStructure::setImmutable()
{
size_t numFields = pvFields.size();
for(size_t i=0; i<numFields; i++) {
PVFieldPtr pvField = pvFields[i];
pvField->setImmutable();
}
PVField::setImmutable();
}
StructureConstPtr PVStructure::getStructure() const
{
return structurePtr;
}
const PVFieldPtrArray & PVStructure::getPVFields() const
{
return pvFields;
}
PVFieldPtr PVStructure::getSubField(string const &fieldName) const
{
return findSubField(fieldName,this);
}
PVFieldPtr PVStructure::getSubField(size_t fieldOffset) const
{
if(fieldOffset<=getFieldOffset()) {
return nullPVField;
}
if(fieldOffset>getNextFieldOffset()) return nullPVField;
size_t numFields = pvFields.size();
for(size_t i=0; i<numFields; i++) {
PVFieldPtr pvField = pvFields[i];
if(pvField->getFieldOffset()==fieldOffset) return pvFields[i];
if(pvField->getNextFieldOffset()<=fieldOffset) continue;
if(pvField->getField()->getType()==structure) {
PVStructure *pvStructure = static_cast<PVStructure *>(pvField.get());
return pvStructure->getSubField(fieldOffset);
}
}
throw std::logic_error("PVStructure.getSubField: Logic error");
}
PVBooleanPtr PVStructure::getBooleanField(string const &fieldName)
{
return getSubField<PVBoolean>(fieldName);
}
PVBytePtr PVStructure::getByteField(string const &fieldName)
{
return getSubField<PVByte>(fieldName);
}
PVShortPtr PVStructure::getShortField(string const &fieldName)
{
return getSubField<PVShort>(fieldName);
}
PVIntPtr PVStructure::getIntField(string const &fieldName)
{
return getSubField<PVInt>(fieldName);
}
PVLongPtr PVStructure::getLongField(string const &fieldName)
{
return getSubField<PVLong>(fieldName);
}
PVUBytePtr PVStructure::getUByteField(string const &fieldName)
{
return getSubField<PVUByte>(fieldName);
}
PVUShortPtr PVStructure::getUShortField(string const &fieldName)
{
return getSubField<PVUShort>(fieldName);
}
PVUIntPtr PVStructure::getUIntField(string const &fieldName)
{
return getSubField<PVUInt>(fieldName);
}
PVULongPtr PVStructure::getULongField(string const &fieldName)
{
return getSubField<PVULong>(fieldName);
}
PVFloatPtr PVStructure::getFloatField(string const &fieldName)
{
return getSubField<PVFloat>(fieldName);
}
PVDoublePtr PVStructure::getDoubleField(string const &fieldName)
{
return getSubField<PVDouble>(fieldName);
}
PVStringPtr PVStructure::getStringField(string const &fieldName)
{
return getSubField<PVString>(fieldName);
}
PVStructurePtr PVStructure::getStructureField(string const &fieldName)
{
return getSubField<PVStructure>(fieldName);
}
PVUnionPtr PVStructure::getUnionField(string const &fieldName)
{
return getSubField<PVUnion>(fieldName);
}
PVScalarArrayPtr PVStructure::getScalarArrayField(
string const &fieldName,ScalarType elementType)
{
PVFieldPtr pvField = findSubField(fieldName,this);
if(pvField.get()==NULL) {
return nullPVScalarArray;
}
FieldConstPtr field = pvField->getField();
Type type = field->getType();
if(type!=scalarArray) {
return nullPVScalarArray;
}
ScalarArrayConstPtr pscalarArray
= static_pointer_cast<const ScalarArray>(pvField->getField());
if(pscalarArray->getElementType()!=elementType) {
return nullPVScalarArray;
}
return std::tr1::static_pointer_cast<PVScalarArray>(pvField);
}
PVStructureArrayPtr PVStructure::getStructureArrayField(
string const &fieldName)
{
return getSubField<PVStructureArray>(fieldName);
}
PVUnionArrayPtr PVStructure::getUnionArrayField(
string const &fieldName)
{
return getSubField<PVUnionArray>(fieldName);
}
void PVStructure::serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher) const {
size_t fieldsSize = pvFields.size();
for(size_t i = 0; i<fieldsSize; i++)
pvFields[i]->serialize(pbuffer, pflusher);
}
void PVStructure::deserialize(ByteBuffer *pbuffer,
DeserializableControl *pcontrol) {
size_t fieldsSize = pvFields.size();
for(size_t i = 0; i<fieldsSize; i++)
pvFields[i]->deserialize(pbuffer, pcontrol);
}
void PVStructure::serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher, BitSet *pbitSet) const {
PVStructure* nonConstThis = const_cast<PVStructure*>(this);
size_t numberFields = nonConstThis->getNumberFields();
size_t offset = nonConstThis->getFieldOffset();
int32 next = pbitSet->nextSetBit(static_cast<uint32>(offset));
// no more changes or no changes in this structure
if(next<0||next>=static_cast<int32>(offset+numberFields)) return;
// entire structure
if(static_cast<int32>(offset)==next) {
serialize(pbuffer, pflusher);
return;
}
size_t fieldsSize = pvFields.size();
for(size_t i = 0; i<fieldsSize; i++) {
PVFieldPtr pvField = pvFields[i];
offset = pvField->getFieldOffset();
int32 inumberFields = static_cast<int32>(pvField->getNumberFields());
next = pbitSet->nextSetBit(static_cast<uint32>(offset));
// no more changes
if(next<0) return;
// no change in this pvField
if(next>=static_cast<int32>(offset+inumberFields)) continue;
// serialize field or fields
if(inumberFields==1) {
pvField->serialize(pbuffer, pflusher);
} else {
PVStructurePtr pvStructure = std::tr1::static_pointer_cast<PVStructure>(pvField);
pvStructure->serialize(pbuffer, pflusher, pbitSet);
}
}
}
void PVStructure::deserialize(ByteBuffer *pbuffer,
DeserializableControl *pcontrol, BitSet *pbitSet) {
size_t offset = getFieldOffset();
size_t numberFields = getNumberFields();
int32 next = pbitSet->nextSetBit(static_cast<uint32>(offset));
// no more changes or no changes in this structure
if(next<0||next>=static_cast<int32>(offset+numberFields)) return;
// entire structure
if(static_cast<int32>(offset)==next) {
deserialize(pbuffer, pcontrol);
return;
}
size_t fieldsSize = pvFields.size();
for(size_t i = 0; i<fieldsSize; i++) {
PVFieldPtr pvField = pvFields[i];
offset = pvField->getFieldOffset();
int32 inumberFields = static_cast<int32>(pvField->getNumberFields());
next = pbitSet->nextSetBit(static_cast<uint32>(offset));
// no more changes
if(next<0) return;
// no change in this pvField
if(next>=static_cast<int32>(offset+inumberFields)) continue;
// deserialize field or fields
if(inumberFields==1) {
pvField->deserialize(pbuffer, pcontrol);
} else {
PVStructurePtr pvStructure = std::tr1::static_pointer_cast<PVStructure>(pvField);
pvStructure->deserialize(pbuffer, pcontrol, pbitSet);
}
}
}
static PVFieldPtr findSubField(
string const & fieldName,
PVStructure const *pvStructure)
{
if( fieldName.length()<1) return PVFieldPtr();
string::size_type index = fieldName.find('.');
string name = fieldName;
string restOfName = string();
if(index>0) {
name = fieldName.substr(0, index);
if(fieldName.length()>index) {
restOfName = fieldName.substr(index+1);
}
}
PVFieldPtrArray pvFields = pvStructure->getPVFields();
PVFieldPtr pvField;
size_t numFields = pvStructure->getStructure()->getNumberFields();
for(size_t i=0; i<numFields; i++) {
pvField = pvFields[i];
size_t result = pvField->getFieldName().compare(name);
if(result==0) {
if(restOfName.length()==0) return pvFields[i];
if(pvField->getField()->getType()!=structure) return PVFieldPtr();
PVStructurePtr pvStructure =
std::tr1::static_pointer_cast<PVStructure>(pvField);
return findSubField(restOfName,pvStructure.get());
}
}
return PVFieldPtr();
}
std::ostream& PVStructure::dumpValue(std::ostream& o) const
{
o << format::indent() << getStructure()->getID() << ' ' << getFieldName();
o << std::endl;
{
format::indent_scope s(o);
PVFieldPtrArray const & fieldsData = getPVFields();
if (fieldsData.size() != 0) {
size_t length = getStructure()->getNumberFields();
for(size_t i=0; i<length; i++) {
PVFieldPtr fieldField = fieldsData[i];
Type type = fieldField->getField()->getType();
if (type == scalar || type == scalarArray)
o << format::indent() << fieldField->getField()->getID() << ' ' << fieldField->getFieldName() << ' ' << *(fieldField.get()) << std::endl;
else
o << *(fieldField.get());
}
}
}
return o;
}
}}

View File

@@ -0,0 +1,217 @@
/*PVStructureArray.cpp*/
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
*/
#include <cstddef>
#include <cstdlib>
#include <string>
#include <cstdio>
#define epicsExportSharedSymbols
#include <pv/pvData.h>
#include <pv/convert.h>
#include <pv/factory.h>
#include <pv/serializeHelper.h>
using std::tr1::static_pointer_cast;
using std::size_t;
namespace epics { namespace pvData {
size_t PVStructureArray::append(size_t number)
{
svector data(reuse());
data.resize(data.size()+number);
StructureConstPtr structure = structureArray->getStructure();
PVDataCreatePtr pvDataCreate = getPVDataCreate();
for(svector::reverse_iterator it = data.rbegin(); number; ++it, --number)
*it = pvDataCreate->createPVStructure(structure);
size_t newLength = data.size();
const_svector cdata(freeze(data));
swap(cdata);
return newLength;
}
bool PVStructureArray::remove(size_t offset,size_t number)
{
if(number==0)
return true;
else if(offset+number>getLength())
return false;
svector vec(reuse());
size_t length = vec.size();
for(size_t i = offset; i+number < length; i++) {
vec[i].swap(vec[i + number]);
}
vec.resize(length - number);
const_svector cdata(freeze(vec));
swap(cdata);
return true;
}
void PVStructureArray::compress() {
svector vec(reuse()); // TODO: check for first NULL before realloc
size_t length = vec.size();
size_t newLength = 0;
for(size_t i=0; i<length; i++) {
if(vec[i].get()!=NULL) {
newLength++;
continue;
}
// find first non 0
size_t notNull = 0;
for(size_t j=i+1;j<length;j++) {
if(vec[j].get()!=NULL) {
notNull = j;
break;
}
}
if(notNull!=0) {
vec[i] = vec[notNull];
vec[notNull].reset();
newLength++;
continue;
}
break;
}
vec.resize(newLength);
const_svector cdata(freeze(vec));
swap(cdata);
}
void PVStructureArray::setCapacity(size_t capacity)
{
if(this->isCapacityMutable()) {
const_svector value;
swap(value);
if(value.capacity()<capacity) {
svector mvalue(thaw(value));
mvalue.reserve(capacity);
value = freeze(mvalue);
}
swap(value);
}
}
void PVStructureArray::setLength(size_t length)
{
if(this->isImmutable())
THROW_EXCEPTION2(std::logic_error,"Immutable");
const_svector value;
swap(value);
if(length == value.size()) {
// nothing
} else if(length < value.size()) {
value.slice(0, length);
} else {
svector mvalue(thaw(value));
mvalue.resize(length);
value = freeze(mvalue);
}
swap(value);
}
void PVStructureArray::swap(const_svector &other)
{
if(this->isImmutable())
THROW_EXCEPTION2(std::logic_error,"Immutable");
value.swap(other);
}
void PVStructureArray::serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher) const {
serialize(pbuffer, pflusher, 0, getLength());
}
void PVStructureArray::deserialize(ByteBuffer *pbuffer,
DeserializableControl *pcontrol) {
svector data(reuse());
size_t size = SerializeHelper::readSize(pbuffer, pcontrol);
data.resize(size);
StructureConstPtr structure = structureArray->getStructure();
PVDataCreatePtr pvDataCreate = getPVDataCreate();
for(size_t i = 0; i<size; i++) {
pcontrol->ensureData(1);
size_t temp = pbuffer->getByte();
if(temp==0) {
data[i].reset();
}
else {
if(data[i].get()==NULL) {
data[i] = pvDataCreate->createPVStructure(structure);
}
data[i]->deserialize(pbuffer, pcontrol);
}
}
replace(freeze(data)); // calls postPut()
}
void PVStructureArray::serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher, size_t offset, size_t count) const {
const_svector temp(view());
temp.slice(offset, count);
SerializeHelper::writeSize(temp.size(), pbuffer, pflusher);
for(size_t i = 0; i<count; i++) {
if(pbuffer->getRemaining()<1)
pflusher->flushSerializeBuffer();
if(temp[i].get()==NULL) {
pbuffer->putByte(0);
}
else {
pbuffer->putByte(1);
temp[i]->serialize(pbuffer, pflusher);
}
}
}
std::ostream& PVStructureArray::dumpValue(std::ostream& o) const
{
o << format::indent() << getStructureArray()->getID() << ' ' << getFieldName() << std::endl;
size_t length = getLength();
if (length > 0)
{
format::indent_scope s(o);
for (size_t i = 0; i < length; i++)
dumpValue(o, i);
}
return o;
}
std::ostream& PVStructureArray::dumpValue(std::ostream& o, std::size_t index) const
{
const_svector temp(view());
if(index<temp.size())
o << *temp[index];
return o;
}
}}

212
src/factory/PVUnion.cpp Normal file
View File

@@ -0,0 +1,212 @@
/*PVUnion.cpp*/
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mse
*/
#include <cstddef>
#include <cstdlib>
#include <string>
#include <cstdio>
#include <vector>
#define epicsExportSharedSymbols
#include <pv/pvData.h>
#include <pv/pvIntrospect.h>
#include <pv/convert.h>
#include <pv/factory.h>
#include <pv/serializeHelper.h>
using std::tr1::static_pointer_cast;
using std::size_t;
using std::string;
namespace epics { namespace pvData {
#define PVUNION_UNDEFINED_INDEX -1
int32 PVUnion::UNDEFINED_INDEX = PVUNION_UNDEFINED_INDEX;
PVUnion::PVUnion(UnionConstPtr const & unionPtr)
: PVField(unionPtr),
unionPtr(unionPtr),
selector(PVUNION_UNDEFINED_INDEX), // to allow out-of-order static initialization
value(),
variant(unionPtr->isVariant())
{
}
#undef PVUNION_UNDEFINED_INDEX
PVUnion::~PVUnion()
{
}
UnionConstPtr PVUnion::getUnion() const
{
return unionPtr;
}
PVFieldPtr PVUnion::get() const
{
return value;
}
int32 PVUnion::getSelectedIndex() const
{
return selector;
}
string PVUnion::getSelectedFieldName() const
{
// no name for undefined and for variant unions
if (selector == UNDEFINED_INDEX)
return string();
else
return unionPtr->getFieldName(selector);
}
PVFieldPtr PVUnion::select(int32 index)
{
// no change
if (selector == index)
return value;
if (index == UNDEFINED_INDEX)
{
selector = UNDEFINED_INDEX;
value.reset();
return value;
}
else if (variant)
throw std::invalid_argument("index out of bounds");
else if (index < 0 || index > static_cast<int32>(unionPtr->getFields().size()))
throw std::invalid_argument("index out of bounds");
FieldConstPtr field = unionPtr->getField(index);
selector = index;
value = getPVDataCreate()->createPVField(field);
return value;
}
PVFieldPtr PVUnion::select(string const & fieldName)
{
int32 index = variant ? -1 : static_cast<int32>(unionPtr->getFieldIndex(fieldName));
if (index == -1)
throw std::invalid_argument("no such fieldName");
return select(index);
}
void PVUnion::set(PVFieldPtr const & value)
{
set(selector, value);
}
void PVUnion::set(int32 index, PVFieldPtr const & value)
{
if (variant && index != UNDEFINED_INDEX)
throw std::invalid_argument("index out of bounds");
else if (!variant)
{
if (index == UNDEFINED_INDEX)
{
// for undefined index we accept only null values
if (value.get())
throw std::invalid_argument("non-null value for index == UNDEFINED_INDEX");
}
else if (index < 0 || index > static_cast<int32>(unionPtr->getFields().size()))
throw std::invalid_argument("index out of bounds");
// value type must match
if (value->getField() != unionPtr->getField(index))
throw std::invalid_argument("selected field and its introspection data do not match");
}
selector = index;
this->value = value;
postPut();
}
void PVUnion::set(string const & fieldName, PVFieldPtr const & value)
{
int32 index = variant ? -1 : static_cast<int32>(unionPtr->getFieldIndex(fieldName));
if (index == -1)
throw std::invalid_argument("no such fieldName");
set(index, value);
}
void PVUnion::serialize(ByteBuffer *pbuffer, SerializableControl *pflusher) const
{
if (variant)
{
// write introspection data
if (value.get() == 0)
pbuffer->put((int8)-1);
else
{
pflusher->cachedSerialize(value->getField(), pbuffer);
value->serialize(pbuffer, pflusher);
}
}
else
{
// write selector value
SerializeHelper::writeSize(selector, pbuffer, pflusher);
// write value, no value for UNDEFINED_INDEX
if (selector != UNDEFINED_INDEX)
value->serialize(pbuffer, pflusher);
}
}
void PVUnion::deserialize(ByteBuffer *pbuffer, DeserializableControl *pcontrol)
{
if (variant)
{
FieldConstPtr field = pcontrol->cachedDeserialize(pbuffer);
if (field.get())
{
value = getPVDataCreate()->createPVField(field);
value->deserialize(pbuffer, pcontrol);
}
else
value.reset();
}
else
{
selector = static_cast<int32>(SerializeHelper::readSize(pbuffer, pcontrol));
if (selector != UNDEFINED_INDEX)
{
FieldConstPtr field = unionPtr->getField(selector);
value = getPVDataCreate()->createPVField(field);
value->deserialize(pbuffer, pcontrol);
}
else
value.reset();
}
}
std::ostream& PVUnion::dumpValue(std::ostream& o) const
{
o << format::indent() << getUnion()->getID() << ' ' << getFieldName() << std::endl;
{
format::indent_scope s(o);
PVFieldPtr fieldField = get();
if (fieldField.get() == NULL)
o << format::indent() << "(none)" << std::endl;
else
{
Type type = fieldField->getField()->getType();
if (type == scalar || type == scalarArray)
o << format::indent() << fieldField->getField()->getID() << ' ' << fieldField->getFieldName() << ' ' << *(fieldField.get()) << std::endl;
else
o << *(fieldField.get());
}
}
return o;
}
}}

View File

@@ -0,0 +1,217 @@
/*PVUnionArray.cpp*/
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author mrk
*/
#include <cstddef>
#include <cstdlib>
#include <string>
#include <cstdio>
#define epicsExportSharedSymbols
#include <pv/pvData.h>
#include <pv/convert.h>
#include <pv/factory.h>
#include <pv/serializeHelper.h>
using std::tr1::static_pointer_cast;
using std::size_t;
namespace epics { namespace pvData {
size_t PVUnionArray::append(size_t number)
{
svector data(reuse());
data.resize(data.size()+number);
UnionConstPtr punion = unionArray->getUnion();
PVDataCreatePtr pvDataCreate = getPVDataCreate();
for(svector::reverse_iterator it = data.rbegin(); number; ++it, --number)
*it = pvDataCreate->createPVUnion(punion);
size_t newLength = data.size();
const_svector cdata(freeze(data));
swap(cdata);
return newLength;
}
bool PVUnionArray::remove(size_t offset,size_t number)
{
if(number==0)
return true;
else if(offset+number>getLength())
return false;
svector vec(reuse());
size_t length = vec.size();
for(size_t i = offset; i+number < length; i++) {
vec[i].swap(vec[i + number]);
}
vec.resize(length - number);
const_svector cdata(freeze(vec));
swap(cdata);
return true;
}
void PVUnionArray::compress() {
svector vec(reuse()); // TODO: check for first NULL before realloc
size_t length = vec.size();
size_t newLength = 0;
for(size_t i=0; i<length; i++) {
if(vec[i].get()!=NULL) {
newLength++;
continue;
}
// find first non 0
size_t notNull = 0;
for(size_t j=i+1;j<length;j++) {
if(vec[j].get()!=NULL) {
notNull = j;
break;
}
}
if(notNull!=0) {
vec[i] = vec[notNull];
vec[notNull].reset();
newLength++;
continue;
}
break;
}
vec.resize(newLength);
const_svector cdata(freeze(vec));
swap(cdata);
}
void PVUnionArray::setCapacity(size_t capacity)
{
if(this->isCapacityMutable()) {
const_svector value;
swap(value);
if(value.capacity()<capacity) {
svector mvalue(thaw(value));
mvalue.reserve(capacity);
value = freeze(mvalue);
}
swap(value);
}
}
void PVUnionArray::setLength(size_t length)
{
if(this->isImmutable())
THROW_EXCEPTION2(std::logic_error,"Immutable");
const_svector value;
swap(value);
if(length == value.size()) {
// nothing
} else if(length < value.size()) {
value.slice(0, length);
} else {
svector mvalue(thaw(value));
mvalue.resize(length);
value = freeze(mvalue);
}
swap(value);
}
void PVUnionArray::swap(const_svector &other)
{
if(this->isImmutable())
THROW_EXCEPTION2(std::logic_error,"Immutable");
value.swap(other);
}
void PVUnionArray::serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher) const {
serialize(pbuffer, pflusher, 0, getLength());
}
void PVUnionArray::deserialize(ByteBuffer *pbuffer,
DeserializableControl *pcontrol) {
svector data(reuse());
size_t size = SerializeHelper::readSize(pbuffer, pcontrol);
data.resize(size);
UnionConstPtr punion = unionArray->getUnion();
PVDataCreatePtr pvDataCreate = getPVDataCreate();
for(size_t i = 0; i<size; i++) {
pcontrol->ensureData(1);
size_t temp = pbuffer->getByte();
if(temp==0) {
data[i].reset();
}
else {
if(data[i].get()==NULL) {
data[i] = pvDataCreate->createPVUnion(punion);
}
data[i]->deserialize(pbuffer, pcontrol);
}
}
replace(freeze(data)); // calls postPut()
}
void PVUnionArray::serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher, size_t offset, size_t count) const {
const_svector temp(view());
temp.slice(offset, count);
SerializeHelper::writeSize(temp.size(), pbuffer, pflusher);
for(size_t i = 0; i<count; i++) {
if(pbuffer->getRemaining()<1)
pflusher->flushSerializeBuffer();
if(temp[i].get()==NULL) {
pbuffer->putByte(0);
}
else {
pbuffer->putByte(1);
temp[i]->serialize(pbuffer, pflusher);
}
}
}
std::ostream& PVUnionArray::dumpValue(std::ostream& o) const
{
o << format::indent() << getUnionArray()->getID() << ' ' << getFieldName() << std::endl;
size_t length = getLength();
if (length > 0)
{
format::indent_scope s(o);
for (size_t i = 0; i < length; i++)
dumpValue(o, i);
}
return o;
}
std::ostream& PVUnionArray::dumpValue(std::ostream& o, std::size_t index) const
{
const_svector temp(view());
if(index<temp.size())
o << *temp[index];
return o;
}
}}

View File

@@ -10,13 +10,14 @@
#include <string>
#include <cstdio>
#include <stdexcept>
#include <epicsThread.h>
#include <epicsExit.h>
#define epicsExportSharedSymbols
#include <pv/lock.h>
#include <pv/pvIntrospect.h>
#include <pv/standardField.h>
using std::tr1::static_pointer_cast;
using std::string;
namespace epics { namespace pvData {
@@ -49,7 +50,7 @@ void StandardField::init()
StandardField::~StandardField(){}
StructureConstPtr StandardField::createProperties(String id,FieldConstPtr field,String properties)
StructureConstPtr StandardField::createProperties(string id,FieldConstPtr field,string properties)
{
bool gotAlarm = false;
bool gotTimeStamp = false;
@@ -57,17 +58,18 @@ StructureConstPtr StandardField::createProperties(String id,FieldConstPtr field,
bool gotControl = false;
bool gotValueAlarm = false;
int numProp = 0;
if(properties.find("alarm")!=String::npos) { gotAlarm = true; numProp++; }
if(properties.find("timeStamp")!=String::npos) { gotTimeStamp = true; numProp++; }
if(properties.find("display")!=String::npos) { gotDisplay = true; numProp++; }
if(properties.find("control")!=String::npos) { gotControl = true; numProp++; }
if(properties.find("valueAlarm")!=String::npos) { gotValueAlarm = true; numProp++; }
if(properties.find("alarm")!=string::npos) { gotAlarm = true; numProp++; }
if(properties.find("timeStamp")!=string::npos) { gotTimeStamp = true; numProp++; }
if(properties.find("display")!=string::npos) { gotDisplay = true; numProp++; }
if(properties.find("control")!=string::npos) { gotControl = true; numProp++; }
if(properties.find("valueAlarm")!=string::npos) { gotValueAlarm = true; numProp++; }
StructureConstPtr valueAlarm;
Type type= field->getType();
while(gotValueAlarm) {
if(type==epics::pvData::scalar) {
ScalarConstPtr scalar = static_pointer_cast<const Scalar>(field);
ScalarType scalarType = scalar->getScalarType();
if(type==epics::pvData::scalar || type==epics::pvData::scalarArray) {
ScalarType scalarType = (type==epics::pvData::scalar) ?
static_pointer_cast<const Scalar>(field)->getScalarType() :
static_pointer_cast<const ScalarArray>(field)->getElementType();
switch(scalarType) {
case pvBoolean: valueAlarm = booleanAlarmField; break;
case pvByte: valueAlarm = byteAlarmField; break;
@@ -81,7 +83,7 @@ StructureConstPtr StandardField::createProperties(String id,FieldConstPtr field,
case pvFloat: valueAlarm = floatAlarmField; break;
case pvDouble: valueAlarm = doubleAlarmField; break;
case pvString:
throw std::logic_error(String("valueAlarm property not supported for pvString"));
throw std::logic_error(string("valueAlarm property not supported for pvString"));
}
break;
}
@@ -92,8 +94,8 @@ StructureConstPtr StandardField::createProperties(String id,FieldConstPtr field,
FieldConstPtrArray fields = structurePtr->getFields();
FieldConstPtr first = fields[0];
FieldConstPtr second = fields[1];
String nameFirst = names[0];
String nameSecond = names[1];
string nameFirst = names[0];
string nameSecond = names[1];
int compareFirst = nameFirst.compare("index");
int compareSecond = nameSecond.compare("choices");
if(compareFirst==0 && compareSecond==0) {
@@ -111,7 +113,7 @@ StructureConstPtr StandardField::createProperties(String id,FieldConstPtr field,
}
}
}
throw std::logic_error(String("valueAlarm property for illegal type"));
throw std::logic_error(string("valueAlarm property for illegal type"));
}
size_t numFields = numProp+1;
FieldConstPtrArray fields(numFields);
@@ -498,14 +500,28 @@ void StandardField::createEnumeratedAlarm() {
StructureConstPtr StandardField::scalar(
ScalarType type,String const &properties)
ScalarType type,string const &properties)
{
ScalarConstPtr field = fieldCreate->createScalar(type); // scalar_t
return createProperties("uri:ev4:nt/2012/pwd:NTScalar",field,properties);
}
StructureConstPtr StandardField::regUnion(
UnionConstPtr const &field,
string const & properties)
{
return createProperties("uri:ev4:nt/2012/pwd:NTUnion",field,properties);
}
StructureConstPtr StandardField::variantUnion(
string const & properties)
{
UnionConstPtr field = fieldCreate->createVariantUnion();
return createProperties("uri:ev4:nt/2012/pwd:NTUnion",field,properties);
}
StructureConstPtr StandardField::scalarArray(
ScalarType elementType, String const &properties)
ScalarType elementType, string const &properties)
{
ScalarArrayConstPtr field = fieldCreate->createScalarArray(elementType); // scalar_t[]
return createProperties("uri:ev4:nt/2012/pwd:NTScalarArray",field,properties);
@@ -513,11 +529,19 @@ StructureConstPtr StandardField::scalarArray(
StructureConstPtr StandardField::structureArray(
StructureConstPtr const & structure,String const &properties)
StructureConstPtr const & structure,string const &properties)
{
StructureArrayConstPtr field = fieldCreate->createStructureArray(
structure);
return createProperties("uri:ev4:nt/2012/pwd:NTAny",field,properties);
return createProperties("uri:ev4:nt/2012/pwd:NTStructureArray",field,properties);
}
StructureConstPtr StandardField::unionArray(
UnionConstPtr const & punion,string const &properties)
{
UnionArrayConstPtr field = fieldCreate->createUnionArray(
punion);
return createProperties("uri:ev4:nt/2012/pwd:NTUnionArray",field,properties);
}
StructureConstPtr StandardField::enumerated()
@@ -533,7 +557,7 @@ StructureConstPtr StandardField::enumerated()
// NOTE: if this method is used to get NTEnum wihtout properties the ID will be wrong!
}
StructureConstPtr StandardField::enumerated(String const &properties)
StructureConstPtr StandardField::enumerated(string const &properties)
{
StructureConstPtr field = enumerated(); // enum_t
return createProperties("uri:ev4:nt/2012/pwd:NTEnum",field,properties);

View File

@@ -9,8 +9,8 @@
*/
#include <string>
#include <stdexcept>
#include <epicsThread.h>
#include <epicsExit.h>
#define epicsExportSharedSymbols
#include <pv/lock.h>
#include <pv/pvIntrospect.h>
#include <pv/pvData.h>
@@ -18,6 +18,8 @@
#include <pv/standardField.h>
#include <pv/standardPVField.h>
using std::string;
namespace epics { namespace pvData {
StandardPVField::StandardPVField()
@@ -30,7 +32,7 @@ StandardPVField::StandardPVField()
StandardPVField::~StandardPVField(){}
PVStructurePtr StandardPVField::scalar(
ScalarType type,String const & properties)
ScalarType type,string const & properties)
{
StructureConstPtr field = standardField->scalar(type,properties);
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(field);
@@ -38,7 +40,7 @@ PVStructurePtr StandardPVField::scalar(
}
PVStructurePtr StandardPVField::scalarArray(
ScalarType elementType, String const & properties)
ScalarType elementType, string const & properties)
{
StructureConstPtr field = standardField->scalarArray(elementType,properties);
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(field);
@@ -46,39 +48,43 @@ PVStructurePtr StandardPVField::scalarArray(
}
PVStructurePtr StandardPVField::structureArray(
StructureConstPtr const & structure,String const & properties)
StructureConstPtr const & structure,string const & properties)
{
StructureConstPtr field = standardField->structureArray(structure,properties);
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(field);
return pvStructure;
}
PVStructurePtr StandardPVField::unionArray(
UnionConstPtr const & punion,string const & properties)
{
StructureConstPtr field = standardField->unionArray(punion,properties);
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(field);
return pvStructure;
}
PVStructurePtr StandardPVField::enumerated(StringArray const &choices)
{
StructureConstPtr field = standardField->enumerated();
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(field);
PVScalarArrayPtr pvScalarArray = pvStructure->getScalarArrayField(
"choices",pvString);
if(pvScalarArray.get()==NULL) {
throw std::logic_error(String("StandardPVField::enumerated"));
}
PVStringArray * pvChoices = static_cast<PVStringArray *>(pvScalarArray.get());
pvChoices->put(0,choices.size(),get(choices),0);
PVStringArray::svector cdata(choices.size());
std::copy(choices.begin(), choices.end(), cdata.begin());
static_cast<PVStringArray&>(*pvScalarArray).replace(freeze(cdata));
return pvStructure;
}
PVStructurePtr StandardPVField::enumerated(
StringArray const &choices,String const & properties)
StringArray const &choices,string const & properties)
{
StructureConstPtr field = standardField->enumerated(properties);
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(field);
PVScalarArrayPtr pvScalarArray = pvStructure->getScalarArrayField(
"value.choices",pvString);
if(pvScalarArray.get()==NULL) {
throw std::logic_error(String("StandardPVField::enumerated"));
}
PVStringArray * pvChoices = static_cast<PVStringArray *>(pvScalarArray.get());
pvChoices->put(0,choices.size(),get(choices),0);
PVStringArray::svector cdata(choices.size());
std::copy(choices.begin(), choices.end(), cdata.begin());
static_cast<PVStringArray&>(*pvScalarArray).replace(freeze(cdata));
return pvStructure;
}

View File

@@ -12,27 +12,33 @@
#include <string>
#include <cstdio>
#define epicsExportSharedSymbols
#include <pv/pvIntrospect.h>
#include <pv/epicsException.h>
#include <pv/sharedVector.h>
#include "dbDefs.h" // for NELEMENTS
using std::string;
namespace epics { namespace pvData {
namespace TypeFunc {
static const char* names[] = {
"scalar", "scalarArray", "structure", "structureArray",
"scalar", "scalarArray", "structure", "structureArray", "union", "unionArray"
};
const char* name(Type t) {
if (t<int(pvBoolean) || t>int(pvString))
if (t<int(scalar) || t>int(unionArray))
THROW_EXCEPTION2(std::invalid_argument, "logic error unknown Type");
return names[t];
}
void toString(StringBuilder buf,const Type type) {
*buf += name(type);
}
} // namespace TypeFunc
std::ostream& operator<<(std::ostream& o, const Type& type)
{
return o << TypeFunc::name(type);
}
namespace ScalarTypeFunc {
bool isInteger(ScalarType type) {
@@ -61,7 +67,7 @@ namespace ScalarTypeFunc {
"ubyte", "ushort", "uint", "ulong",
"float", "double", "string",
};
ScalarType getScalarType(String pvalue) {
ScalarType getScalarType(const string& pvalue) {
for(size_t i=0; i<NELEMENTS(names); i++)
if(pvalue==names[i])
return ScalarType(i);
@@ -74,10 +80,55 @@ namespace ScalarTypeFunc {
return names[t];
}
void toString(StringBuilder buf,const ScalarType scalarType) {
*buf += name(scalarType);
size_t elementSize(ScalarType id)
{
switch(id) {
#define OP(ENUM, TYPE) case ENUM: return sizeof(TYPE)
OP(pvBoolean, boolean);
OP(pvUByte, uint8);
OP(pvByte, int8);
OP(pvUShort, uint16);
OP(pvShort, int16);
OP(pvUInt, uint32);
OP(pvInt, int32);
OP(pvULong, uint64);
OP(pvLong, int64);
OP(pvFloat, float);
OP(pvDouble, double);
OP(pvString, string);
#undef OP
default:
THROW_EXCEPTION2(std::invalid_argument, "error unknown ScalarType");
}
}
shared_vector<void> allocArray(ScalarType id, size_t len)
{
switch(id) {
#define OP(ENUM, TYPE) case ENUM: return static_shared_vector_cast<void>(shared_vector<TYPE>(len))
OP(pvBoolean, boolean);
OP(pvUByte, uint8);
OP(pvByte, int8);
OP(pvUShort, uint16);
OP(pvShort, int16);
OP(pvUInt, uint32);
OP(pvInt, int32);
OP(pvULong, uint64);
OP(pvLong, int64);
OP(pvFloat, float);
OP(pvDouble, double);
OP(pvString, string);
#undef OP
default:
throw std::bad_alloc();
}
}
} // namespace ScalarTypeFunc
std::ostream& operator<<(std::ostream& o, const ScalarType& scalarType)
{
return o << ScalarTypeFunc::name(scalarType);
}
}}

290
src/factory/printer.cpp Normal file
View File

@@ -0,0 +1,290 @@
/* printer.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#include <deque>
#define epicsExportSharedSymbols
#include <pv/printer.h>
using std::string;
namespace {
void indentN(std::ostream& strm, size_t N)
{
while(N--)
strm.put(' ');
}
}
namespace epics { namespace pvData {
namespace format
{
std::ostream& operator<<(std::ostream& os, indent_level const& indent)
{
indent_value(os) = indent.level;
return os;
}
std::ostream& operator<<(std::ostream& os, indent const&)
{
long il = indent_value(os);
std::size_t spaces = static_cast<std::size_t>(il) * 4;
return os << string(spaces, ' ');
}
array_at_internal operator<<(std::ostream& str, array_at const& manip)
{
return array_at_internal(manip.index, str);
}
};
PrinterBase::PrinterBase()
:strm(NULL)
{}
PrinterBase::~PrinterBase() {}
void PrinterBase::setStream(std::ostream& s)
{
strm = &s;
}
void PrinterBase::clearStream()
{
strm = NULL;
}
void PrinterBase::print(const PVField& pv)
{
if(!strm)
throw std::runtime_error("No stream set for PV Printer");
impl_print(pv);
}
void PrinterBase::beginStructure(const PVStructure&) {}
void PrinterBase::endStructure(const PVStructure&) {}
void PrinterBase::beginStructureArray(const PVStructureArray&) {}
void PrinterBase::endStructureArray(const PVStructureArray&) {}
void PrinterBase::beginUnion(const PVUnion&) {}
void PrinterBase::endUnion(const PVUnion&) {}
void PrinterBase::beginUnionArray(const PVUnionArray&) {}
void PrinterBase::endUnionArray(const PVUnionArray&) {}
void PrinterBase::encodeScalar(const PVScalar&) {}
void PrinterBase::encodeArray(const PVScalarArray&) {}
void PrinterBase::encodeNull() {}
void PrinterBase::impl_print(const PVField& pv)
{
static const PVField* marker = (const PVField*)&marker;
/* Depth first recursive iteration.
* Each PV to be printed is appended to the todo queue.
* The last child of a structure is followed by a NULL.
* As the tree is walked structures and structarrays
* are appended to the inprog queue.
*/
std::deque<const PVField*> todo, inprog;
todo.push_back(&pv);
while(!todo.empty()) {
const PVField *next = todo.front();
todo.pop_front();
if(next==marker) {
// finished with a structure or structarray,
// now we fall back to its parent.
assert(!inprog.empty());
switch(inprog.back()->getField()->getType()) {
case structure:
endStructure(*static_cast<const PVStructure *>(inprog.back()));
break;
case structureArray:
endStructureArray(*static_cast<const PVStructureArray *>(inprog.back()));
break;
case union_:
endUnion(*static_cast<const PVUnion *>(inprog.back()));
break;
case unionArray:
endUnionArray(*static_cast<const PVUnionArray *>(inprog.back()));
break;
default:
assert(false); // oops!
return;
}
inprog.pop_back();
} else {
// real field
if(!next) {
// NULL entry in a structure array
encodeNull();
continue;
}
switch(next->getField()->getType()) {
case scalar:
encodeScalar(*static_cast<const PVScalar*>(next));
break;
case scalarArray:
encodeArray(*static_cast<const PVScalarArray*>(next));
break;
case structure: {
const PVStructure &fld = *static_cast<const PVStructure*>(next);
const PVFieldPtrArray& vals = fld.getPVFields();
inprog.push_back(next);
beginStructure(fld);
for(size_t i=0, nfld=fld.getStructure()->getNumberFields(); i<nfld; i++)
todo.push_back(vals[i].get());
todo.push_back(marker);
break;
}
case structureArray: {
const PVStructureArray &fld = *static_cast<const PVStructureArray*>(next);
PVStructureArray::const_svector vals(fld.view());
inprog.push_back(next);
beginStructureArray(fld);
for(PVStructureArray::const_svector::const_iterator it=vals.begin();
it!=vals.end(); ++it)
{
todo.push_back(it->get());
}
todo.push_back(marker);
break;
}
case union_: {
const PVUnion &fld = *static_cast<const PVUnion*>(next);
inprog.push_back(next);
beginUnion(fld);
PVFieldPtr val = fld.get();
if (val.get()) // TODO print "(none)" ?
todo.push_back(val.get());
todo.push_back(marker);
break;
}
case unionArray: {
const PVUnionArray &fld = *static_cast<const PVUnionArray*>(next);
PVUnionArray::const_svector vals(fld.view());
inprog.push_back(next);
beginUnionArray(fld);
for(PVUnionArray::const_svector::const_iterator it=vals.begin();
it!=vals.end(); ++it)
{
todo.push_back(it->get());
}
todo.push_back(marker);
break;
}
}
}
}
}
PrinterPlain::PrinterPlain()
:PrinterBase()
,ilvl(0)
{}
PrinterPlain::~PrinterPlain() {}
void PrinterPlain::beginStructure(const PVStructure& pv)
{
indentN(S(), ilvl);
S() << pv.getStructure()->getID() << " " << pv.getFieldName();
S() << std::endl;
ilvl++;
}
void PrinterPlain::endStructure(const PVStructure&) {ilvl--;}
void PrinterPlain::beginStructureArray(const PVStructureArray& pv)
{
indentN(S(), ilvl);
S() << pv.getStructureArray()->getID() << " "
<< pv.getFieldName() << "[] ";
ilvl++;
}
void PrinterPlain::endStructureArray(const PVStructureArray&) {ilvl--;}
void PrinterPlain::beginUnion(const PVUnion& pv)
{
indentN(S(), ilvl);
S() << pv.getUnion()->getID() << " " << pv.getFieldName() << std::endl;
ilvl++;
}
void PrinterPlain::endUnion(const PVUnion&) {ilvl--;}
void PrinterPlain::beginUnionArray(const PVUnionArray& pv)
{
indentN(S(), ilvl);
S() << pv.getUnionArray()->getID() << " "
<< pv.getFieldName() << "[] ";
ilvl++;
}
void PrinterPlain::endUnionArray(const PVUnionArray&) {ilvl--;}
void PrinterPlain::encodeScalar(const PVScalar& pv)
{
indentN(S(), ilvl);
S() << pv.getScalar()->getID() << " "
<< pv.getFieldName() << " "
<< pv.getAs<string>() << std::endl;
}
void PrinterPlain::encodeArray(const PVScalarArray& pv)
{
indentN(S(), ilvl);
shared_vector<const string> temp;
pv.getAs<string>(temp);
S() << pv.getScalarArray()->getID() << " "
<< pv.getFieldName() << " [";
for(size_t i=0, len=pv.getLength(); i<len; i++) {
S() << temp[i];
if(i!=len-1)
S().put(',');
}
S() << "]" << std::endl;
}
void PrinterPlain::encodeNull()
{
indentN(S(), ilvl);
S() << "NULL" << std::endl;
}
}}

View File

@@ -0,0 +1,276 @@
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* @author Marty Kraimer
* @date 2013.07
*/
#include <string>
#include <stdexcept>
#include <memory>
#define epicsExportSharedSymbols
#include <pv/pvSubArrayCopy.h>
using std::cout;
using std::endl;
using std::string;
namespace epics { namespace pvData {
template<typename T>
void copy(
PVValueArray<T> & pvFrom,
size_t fromOffset,
size_t fromStride,
PVValueArray<T> & pvTo,
size_t toOffset,
size_t toStride,
size_t count)
{
if(pvTo.isImmutable()) throw std::invalid_argument("pvSubArrayCopy: pvTo is immutable");
if(fromStride<1 || toStride<1) throw std::invalid_argument("stride must be >=1");
size_t fromLength = pvFrom.getLength();
size_t maxcount = (fromLength -fromOffset + fromStride -1)/fromStride;
if(count>maxcount) throw std::invalid_argument("pvSubArrayCopy pvFrom length error");
size_t newLength = toOffset + count*toStride;
size_t capacity = pvTo.getCapacity();
if(newLength>capacity) capacity = newLength;
shared_vector<T> temp(capacity);
typename PVValueArray<T>::const_svector vecFrom = pvFrom.view();
typename PVValueArray<T>::const_svector vecTo = pvTo.view();
for(size_t i=0; i<pvTo.getLength(); ++i) temp[i] = vecTo[i];
for(size_t i=pvTo.getLength(); i< capacity; ++i) temp[i] = T();
for(size_t i=0; i<count; ++i) temp[i*toStride + toOffset] = vecFrom[i*fromStride+fromOffset];
shared_vector<const T> temp2(freeze(temp));
pvTo.replace(temp2);
}
void copy(
PVScalarArray & from,
size_t fromOffset,
size_t fromStride,
PVScalarArray & to,
size_t toOffset,
size_t toStride,
size_t count)
{
ScalarType scalarType = from.getScalarArray()->getElementType();
ScalarType otherType = to.getScalarArray()->getElementType();
if(scalarType!=otherType) {
throw std::invalid_argument("pvSubArrayCopy element types do not match");
}
switch(scalarType)
{
case pvBoolean:
{
copy(dynamic_cast<PVValueArray<boolean> &>(from),fromOffset,fromStride,
dynamic_cast<PVValueArray<boolean>& >(to),
toOffset,toStride,count);
}
break;
case pvByte:
{
copy(dynamic_cast<PVValueArray<int8> &>(from),fromOffset,fromStride,
dynamic_cast<PVValueArray<int8>& >(to),
toOffset,toStride,count);
}
break;
case pvShort:
{
copy(dynamic_cast<PVValueArray<int16> &>(from),fromOffset,fromStride,
dynamic_cast<PVValueArray<int16>& >(to),
toOffset,toStride,count);
}
break;
case pvInt:
{
copy(dynamic_cast<PVValueArray<int32> &>(from),fromOffset,fromStride,
dynamic_cast<PVValueArray<int32>& >(to),
toOffset,toStride,count);
}
break;
case pvLong:
{
copy(dynamic_cast<PVValueArray<int64> &>(from),fromOffset,fromStride,
dynamic_cast<PVValueArray<int64>& >(to),
toOffset,toStride,count);
}
break;
case pvUByte:
{
copy(dynamic_cast<PVValueArray<uint8> &>(from),fromOffset,fromStride,
dynamic_cast<PVValueArray<uint8>& >(to),
toOffset,toStride,count);
}
break;
case pvUShort:
{
copy(dynamic_cast<PVValueArray<uint16> &>(from),fromOffset,fromStride,
dynamic_cast<PVValueArray<uint16>& >(to),
toOffset,toStride,count);
}
break;
case pvUInt:
{
copy(dynamic_cast<PVValueArray<uint32> &>(from),fromOffset,fromStride,
dynamic_cast<PVValueArray<uint32>& >(to),
toOffset,toStride,count);
}
break;
case pvULong:
{
copy(dynamic_cast<PVValueArray<uint64> &>(from),fromOffset,fromStride,
dynamic_cast<PVValueArray<uint64>& >(to),
toOffset,toStride,count);
}
break;
case pvFloat:
{
copy(dynamic_cast<PVValueArray<float> &>(from),fromOffset,fromStride,
dynamic_cast<PVValueArray<float>& >(to),
toOffset,toStride,count);
}
break;
case pvDouble:
{
copy(dynamic_cast<PVValueArray<double> &>(from),fromOffset,fromStride,
dynamic_cast<PVValueArray<double>& >(to),
toOffset,toStride,count);
}
break;
case pvString:
{
copy(dynamic_cast<PVValueArray<string> &>(from),fromOffset,fromStride,
dynamic_cast<PVValueArray<string>& >(to),
toOffset,toStride,count);
}
break;
}
}
void copy(
PVStructureArray & pvFrom,
size_t pvFromOffset,
size_t pvFromStride,
PVStructureArray & pvTo,
size_t toOffset,
size_t toStride,
size_t count)
{
if(pvTo.isImmutable()) {
throw std::logic_error("pvSubArrayCopy pvTo is immutable");
}
if(pvFromStride<1 || toStride<1) throw std::invalid_argument("stride must be >=1");
StructureArrayConstPtr pvFromStructure = pvFrom.getStructureArray();
StructureArrayConstPtr toStructure = pvTo.getStructureArray();
if(pvFromStructure->getStructure()!=toStructure->getStructure()) {
throw std::invalid_argument(
"pvSubArrayCopy structureArray pvTo and pvFrom have different structures");
}
size_t pvFromLength = pvFrom.getLength();
size_t maxcount = (pvFromLength -pvFromOffset + pvFromStride -1)/pvFromStride;
if(count>maxcount) throw std::invalid_argument("pvSubArrayCopy pvFrom length error");
size_t newLength = toOffset + count*toStride;
size_t capacity = pvTo.getCapacity();
if(newLength>capacity) capacity = newLength;
shared_vector<PVStructurePtr> temp(capacity);
PVValueArray<PVStructurePtr>::const_svector vecFrom = pvFrom.view();
PVValueArray<PVStructurePtr>::const_svector vecTo = pvTo.view();
for(size_t i=0; i<pvTo.getLength(); ++i) temp[i] = vecTo[i];
for(size_t i=pvTo.getLength(); i< capacity; ++i)
temp[i] = getPVDataCreate()->createPVStructure(toStructure->getStructure());
for(size_t i=0; i<count; ++i) temp[i*toStride + toOffset] = vecFrom[i*pvFromStride+pvFromOffset];
shared_vector<const PVStructurePtr> temp2(freeze(temp));
pvTo.replace(temp2);
}
void copy(
PVUnionArray & pvFrom,
size_t pvFromOffset,
size_t pvFromStride,
PVUnionArray & pvTo,
size_t toOffset,
size_t toStride,
size_t count)
{
if(pvTo.isImmutable()) {
throw std::logic_error("pvSubArrayCopy pvTo is immutable");
}
if(pvFromStride<1 || toStride<1) throw std::invalid_argument("stride must be >=1");
UnionArrayConstPtr pvFromUnion = pvFrom.getUnionArray();
UnionArrayConstPtr toUnion = pvTo.getUnionArray();
if(pvFromUnion->getUnion()!=toUnion->getUnion()) {
throw std::invalid_argument(
"pvSubArrayCopy unionArray pvTo and pvFrom have different unions");
}
size_t pvFromLength = pvFrom.getLength();
size_t maxcount = (pvFromLength -pvFromOffset + pvFromStride -1)/pvFromStride;
if(count>maxcount) throw std::invalid_argument("pvSubArrayCopy pvFrom length error");
size_t newLength = toOffset + count*toStride;
size_t capacity = pvTo.getCapacity();
if(newLength>capacity) capacity = newLength;
shared_vector<PVUnionPtr> temp(capacity);
PVValueArray<PVUnionPtr>::const_svector vecFrom = pvFrom.view();
PVValueArray<PVUnionPtr>::const_svector vecTo = pvTo.view();
for(size_t i=0; i<pvTo.getLength(); ++i) temp[i] = vecTo[i];
for(size_t i=pvTo.getLength(); i< capacity; ++i)
temp[i] = getPVDataCreate()->createPVUnion(toUnion->getUnion());
for(size_t i=0; i<count; ++i) temp[i*toStride + toOffset] = vecFrom[i*pvFromStride+pvFromOffset];
shared_vector<const PVUnionPtr> temp2(freeze(temp));
pvTo.replace(temp2);
}
void copy(
PVArray & pvFrom,
size_t pvFromOffset,
size_t pvFromStride,
PVArray & pvTo,
size_t pvToOffset,
size_t pvToStride,
size_t count)
{
Type pvFromType = pvFrom.getField()->getType();
Type pvToType = pvTo.getField()->getType();
if(pvFromType!=pvToType) throw std::invalid_argument("pvSubArrayCopy: pvFrom and pvTo different types");
if(pvFromType==scalarArray) {
ScalarType pvFromScalarType= static_cast<ScalarType>(pvFromType);
ScalarType pvToScalarType = static_cast<ScalarType>(pvToType);
if(pvFromScalarType!=pvToScalarType){
throw std::invalid_argument("pvSubArrayCopy: pvFrom and pvTo different types");
}
}
if(pvTo.isImmutable()) throw std::invalid_argument("pvSubArrayCopy: pvTo is immutable");
if(pvFromType==scalarArray) {
copy(dynamic_cast<PVScalarArray &>(pvFrom) ,pvFromOffset,pvFromStride,
dynamic_cast<PVScalarArray&>(pvTo),
pvToOffset,pvToStride,count);
}
if(pvFromType==structureArray) {
copy(dynamic_cast<PVStructureArray &>(pvFrom) ,pvFromOffset,pvFromStride,
dynamic_cast<PVStructureArray&>(pvTo),
pvToOffset,pvToStride,count);
}
if(pvFromType==unionArray) {
copy(dynamic_cast<PVUnionArray &>(pvFrom) ,pvFromOffset,pvFromStride,
dynamic_cast<PVUnionArray&>(pvTo),
pvToOffset,pvToStride,count);
}
}
void copy(
PVArray::shared_pointer const & pvFrom,
size_t pvFromOffset,
size_t pvFromStride,
PVArray::shared_pointer & pvTo,
size_t pvToOffset,
size_t pvToStride,
size_t count)
{
copy(*pvFrom,pvFromOffset,pvFromStride,*pvTo,pvToOffset,pvToStride,count);
}
}}

44
src/misc/Makefile Normal file
View File

@@ -0,0 +1,44 @@
# This is a Makefile fragment, see ../Makefile
SRC_DIRS += $(PVDATA_SRC)/misc
INC += noDefaultMethods.h
INC += lock.h
INC += requester.h
INC += serialize.h
INC += bitSet.h
INC += byteBuffer.h
INC += epicsException.h
INC += serializeHelper.h
INC += event.h
INC += thread.h
INC += executor.h
INC += timeFunction.h
INC += timer.h
INC += queue.h
INC += messageQueue.h
INC += destroyable.h
INC += status.h
INC += sharedPtr.h
INC += localStaticLock.h
INC += typeCast.h
INC += printer.h
INC += sharedVector.h
INC += templateMeta.h
INC += current_function.h
LIBSRCS += byteBuffer.cpp
LIBSRCS += bitSet.cpp
LIBSRCS += epicsException.cpp
LIBSRCS += requester.cpp
LIBSRCS += serializeHelper.cpp
LIBSRCS += event.cpp
LIBSRCS += executor.cpp
LIBSRCS += timeFunction.cpp
LIBSRCS += timer.cpp
LIBSRCS += status.cpp
LIBSRCS += messageQueue.cpp
LIBSRCS += localStaticLock.cpp
LIBSRCS += typeCast.cpp
LIBSRCS += parseToPOD.cpp

View File

@@ -7,11 +7,14 @@
/**
* @author mes
*/
#include "string.h"
#include "stdio.h"
#include <pv/bitSet.h>
#include <string.h>
#include <stdio.h>
#include <iostream>
#define epicsExportSharedSymbols
#include <pv/lock.h>
#include <pv/serializeHelper.h>
#include <pv/bitSet.h>
namespace epics { namespace pvData {
@@ -199,6 +202,8 @@ namespace epics { namespace pvData {
}
BitSet& BitSet::operator&=(const BitSet& set) {
// Check for self-assignment!
if (this == &set) return *this;
while (wordsInUse > set.wordsInUse)
words[--wordsInUse] = 0;
@@ -213,76 +218,49 @@ namespace epics { namespace pvData {
}
BitSet& BitSet::operator|=(const BitSet& set) {
uint32 wordsInCommon;
// Check for self-assignment!
if (this == &set) return *this;
uint32 wordsInCommon = wordsInUse;
if(wordsInUse>set.wordsInUse) wordsInCommon = set.wordsInUse;
if (wordsInUse < set.wordsInUse) {
wordsInCommon = wordsInUse;
//ensureCapacity(set.wordsInUse);
//wordsInUse = set.wordsInUse;
ensureCapacity(set.wordsInUse);
wordsInUse = set.wordsInUse;
}
else
wordsInCommon = set.wordsInUse;
// Perform logical OR on words in common
uint32 i = 0;
for (; i < wordsInCommon; i++)
for (uint32 i =0; i < wordsInCommon; i++) {
words[i] |= set.words[i];
// TODO what to do if BitSets are not the same size !!!
}
// Copy any remaining words
for(uint32 i=wordsInCommon; i<set.wordsInUse; ++i) {
words[i] = set.words[i];
}
// recalculateWordsInUse() is not needed
return *this;
}
BitSet& BitSet::operator^=(const BitSet& set) {
uint32 wordsInCommon;
uint32 wordsInCommon = wordsInUse;
if(wordsInUse>set.wordsInUse) wordsInCommon = set.wordsInUse;
if (wordsInUse < set.wordsInUse) {
wordsInCommon = wordsInUse;
//ensureCapacity(set.wordsInUse);
//wordsInUse = set.wordsInUse;
ensureCapacity(set.wordsInUse);
wordsInUse = set.wordsInUse;
}
else
wordsInCommon = set.wordsInUse;
// Perform logical XOR on words in common
uint32 i = 0;
for (; i < wordsInCommon; i++)
// Perform logical OR on words in common
for (uint32 i =0; i < wordsInCommon; i++) {
words[i] ^= set.words[i];
// TODO what to do if BitSets are not the same size !!!
recalculateWordsInUse();
return *this;
}
BitSet& BitSet::operator-=(const BitSet& set) {
uint32 wordsInCommon;
if (wordsInUse < set.wordsInUse) {
wordsInCommon = wordsInUse;
//ensureCapacity(set.wordsInUse);
//wordsInUse = set.wordsInUse;
}
// Copy any remaining words
for(uint32 i=wordsInCommon; i<set.wordsInUse; ++i) {
words[i] = set.words[i];
}
else
wordsInCommon = set.wordsInUse;
// Perform logical (a & !b) on words in common
uint32 i = 0;
for (; i < wordsInCommon; i++)
words[i] &= ~set.words[i];
recalculateWordsInUse();
return *this;
}
BitSet& BitSet::operator=(const BitSet &set) {
// Check for self-assignment!
if (this == &set)
return *this;
if (this == &set) return *this;
// we ensure that words array size is adequate (and not wordsInUse to ensure capacity to the future)
if (wordsLength < set.wordsLength)
@@ -331,21 +309,6 @@ namespace epics { namespace pvData {
return !(*this == set);
}
void BitSet::toString(StringBuilder buffer, int indentLevel) const
{
*buffer += '{';
int32 i = nextSetBit(0);
char tmp[30];
if (i != -1) {
sprintf(tmp,"%d",(int)i); *buffer += tmp;
for (i = nextSetBit(i+1); i >= 0; i = nextSetBit(i+1)) {
int32 endOfRun = nextClearBit(i);
do { *buffer += ", "; sprintf(tmp,"%d",(int)i); *buffer += tmp; } while (++i < endOfRun);
}
}
*buffer += '}';
}
void BitSet::serialize(ByteBuffer* buffer, SerializableControl* flusher) const {
uint32 n = wordsInUse;
@@ -369,7 +332,7 @@ namespace epics { namespace pvData {
void BitSet::deserialize(ByteBuffer* buffer, DeserializableControl* control) {
uint32 bytes = SerializeHelper::readSize(buffer, control); // in bytes
uint32 bytes = static_cast<uint32>(SerializeHelper::readSize(buffer, control)); // in bytes
wordsInUse = (bytes + 7) / 8;
if (wordsInUse > wordsLength)
@@ -396,5 +359,20 @@ namespace epics { namespace pvData {
words[i] |= (buffer->getByte() & 0xffL) << (8 * j);
}
epicsShareExtern std::ostream& operator<<(std::ostream& o, const BitSet& b)
{
o << '{';
int32 i = b.nextSetBit(0);
if (i != -1) {
o << i;
for (i = b.nextSetBit(i+1); i >= 0; i = b.nextSetBit(i+1)) {
int32 endOfRun = b.nextClearBit(i);
do { o << ", " << i; } while (++i < endOfRun);
}
}
o << '}';
return o;
}
}};

View File

@@ -9,11 +9,15 @@
*/
#ifndef BITSET_H
#define BITSET_H
#include <stdexcept>
#include <pv/pvType.h>
#include <pv/serialize.h>
#include <pv/sharedPtr.h>
#include <shareLib.h>
namespace epics { namespace pvData {
class BitSet;
@@ -42,10 +46,10 @@ namespace epics { namespace pvData {
*
* Based on Java implementation.
*/
class BitSet : public Serializable {
class epicsShareClass BitSet : public Serializable {
public:
POINTER_DEFINITIONS(BitSet);
static BitSet::shared_pointer create(uint32 nbits);
static BitSetPtr create(uint32 nbits);
/**
* Creates a new bit set. All bits are initially {@code false}.
*/
@@ -201,15 +205,6 @@ namespace epics { namespace pvData {
*/
BitSet& operator^=(const BitSet& set);
/**
* Clears all of the bits in this {@code BitSet} whose corresponding
* bit is set in the specified {@code BitSet}.
*
* @param set the {@code BitSet} with which to mask this
* {@code BitSet}
*/
BitSet& operator-=(const BitSet& set);
/**
* Assigment operator.
*/
@@ -230,8 +225,6 @@ namespace epics { namespace pvData {
bool operator!=(const BitSet &set) const;
void toString(StringBuilder buffer, int indentLevel = 0) const;
virtual void serialize(ByteBuffer *buffer,
SerializableControl *flusher) const;
virtual void deserialize(ByteBuffer *buffer,
@@ -322,6 +315,8 @@ namespace epics { namespace pvData {
static uint32 bitCount(uint64 i);
};
epicsShareExtern std::ostream& operator<<(std::ostream& o, const BitSet& b);
}}
#endif /* BITSET_H */

View File

@@ -4,5 +4,5 @@
* in file LICENSE that is included with this distribution.
*/
/**
* @author mes
* @author mse
*/

View File

@@ -11,12 +11,25 @@
#define BYTEBUFFER_H
#include <string>
#include <pv/pvType.h>
#include <epicsEndian.h>
#include <string.h>
#ifdef epicsExportSharedSymbols
#define byteBufferepicsExportSharedSymbols
#undef epicsExportSharedSymbols
#endif
#include <epicsEndian.h>
#ifdef byteBufferepicsExportSharedSymbols
#define epicsExportSharedSymbols
#undef byteBufferepicsExportSharedSymbols
#endif
#include <pv/pvType.h>
#include <pv/epicsException.h>
#include <shareLib.h>
namespace epics {
namespace pvData {
@@ -189,22 +202,40 @@ public:
*
* @param size The number of bytes.
* @param byteOrder The byte order.
* Must be one of EPICS_BYTE_ORDER,EPICS_ENDIAN_LITTLE,EPICS_ENDIAN_BIG,
* Must be one of EPICS_BYTE_ORDER,EPICS_ENDIAN_LITTLE,EPICS_ENDIAN_BIG.
*/
ByteBuffer(std::size_t size, int byteOrder = EPICS_BYTE_ORDER) :
_buffer(0), _size(size),
_reverseEndianess(byteOrder != EPICS_BYTE_ORDER),
_reverseFloatEndianess(byteOrder != EPICS_FLOAT_WORD_ORDER)
_reverseFloatEndianess(byteOrder != EPICS_FLOAT_WORD_ORDER),
_wrapped(false)
{
_buffer = (char*)malloc(size);
clear();
}
/**
* Constructor for wrapping existing buffers.
* Given buffer will not be released by the ByteBuffer instance.
* @param buffer Existing buffer.
* @param size The number of bytes.
* @param byteOrder The byte order.
* Must be one of EPICS_BYTE_ORDER,EPICS_ENDIAN_LITTLE,EPICS_ENDIAN_BIG.
*/
ByteBuffer(char* buffer, std::size_t size, int byteOrder = EPICS_BYTE_ORDER) :
_buffer(buffer), _size(size),
_reverseEndianess(byteOrder != EPICS_BYTE_ORDER),
_reverseFloatEndianess(byteOrder != EPICS_FLOAT_WORD_ORDER),
_wrapped(true)
{
clear();
}
/**
* Destructor
*/
~ByteBuffer()
{
if (_buffer) free(_buffer);
if (_buffer && !_wrapped) free(_buffer);
}
/**
* Set the byte order.
@@ -379,7 +410,7 @@ public:
* @param count The number of elements.
*/
template<typename T>
inline void putArray(T* values, std::size_t count);
inline void putArray(const T* values, std::size_t count);
/**
* Get an array of type {@code T} from the byte buffer.
* The position is adjusted.
@@ -605,9 +636,28 @@ private:
char* _limit;
std::size_t _size;
bool _reverseEndianess;
bool _reverseFloatEndianess;
bool _reverseFloatEndianess;
bool _wrapped;
};
template<>
inline bool ByteBuffer::reverse<bool>()
{
return false;
}
template<>
inline bool ByteBuffer::reverse<int8>()
{
return false;
}
template<>
inline bool ByteBuffer::reverse<uint8>()
{
return false;
}
template<>
inline bool ByteBuffer::reverse<float>()
{
@@ -824,7 +874,7 @@ private:
}
template<typename T>
inline void ByteBuffer::putArray(T* values, std::size_t count)
inline void ByteBuffer::putArray(const T* values, std::size_t count)
{
// this avoids int8 specialization, compiler will take care if optimization, -O2 or more
if (sizeof(T) == 1)

42
src/misc/current_function.h Executable file
View File

@@ -0,0 +1,42 @@
#ifndef CURRENT_FUNCTION_HPP_INCLUDED
#define CURRENT_FUNCTION_HPP_INCLUDED
// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif
#if defined(__GNUC__) || (defined(__MWERKS__) && (__MWERKS__ >= 0x3000)) || (defined(__ICC) && (__ICC >= 600)) || defined(__ghs__)
# define CURRENT_FUNCTION __PRETTY_FUNCTION__
#elif defined(__DMC__) && (__DMC__ >= 0x810)
# define CURRENT_FUNCTION __PRETTY_FUNCTION__
#elif defined(__FUNCSIG__)
# define CURRENT_FUNCTION __FUNCSIG__
#elif (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 600)) || (defined(__IBMCPP__) && (__IBMCPP__ >= 500))
# define CURRENT_FUNCTION __FUNCTION__
#elif defined(__BORLANDC__) && (__BORLANDC__ >= 0x550)
# define CURRENT_FUNCTION __FUNC__
#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901)
# define CURRENT_FUNCTION __func__
#else
# define CURRENT_FUNCTION "(unknown)"
#endif
#endif // #ifndef BOOST_CURRENT_FUNCTION_HPP_INCLUDED

View File

@@ -12,6 +12,8 @@
#include <pv/sharedPtr.h>
#include <shareLib.h>
namespace epics { namespace pvData {
@@ -19,7 +21,7 @@ namespace epics { namespace pvData {
* Instance declaring destroy method.
* @author mse
*/
class Destroyable {
class epicsShareClass Destroyable {
public:
POINTER_DEFINITIONS(Destroyable);
/**

View File

@@ -7,14 +7,17 @@
* @author mes
*/
#include <pv/epicsException.h>
#include <sstream>
#include <cstdio>
#include <cstring>
#include <string>
namespace epics{namespace pvData{
#define epicsExportSharedSymbols
#include <pv/epicsException.h>
using std::string;
namespace epics{ namespace pvData {
void
ExceptionMixin::print(FILE *fp) const
@@ -31,7 +34,7 @@ ExceptionMixin::print(FILE *fp) const
#endif
}
std::string
string
ExceptionMixin::show() const
{
std::ostringstream out;
@@ -61,7 +64,7 @@ BaseException::what() const throw()
try{
if (base_msg.size()==0) {
const char *base=std::logic_error::what();
std::string out, stack;
string out, stack;
const ExceptionMixin *info=dynamic_cast<const ExceptionMixin*>(this);
if(info) {

View File

@@ -34,6 +34,10 @@
#ifndef EPICSEXCEPTION_H_
#define EPICSEXCEPTION_H_
#ifdef _WIN32
#pragma warning( push )
#pragma warning(disable: 4275) // warning C4275: non dll-interface class used as base for dll-interface class (std::logic_error)
#endif
#include <stdexcept>
#include <string>
@@ -43,6 +47,8 @@
#include <stdio.h>
#include <stdlib.h>
#include <shareLib.h>
// Users may redefine this for a large size if desired
#ifndef EXCEPT_DEPTH
# define EXCEPT_DEPTH 20
@@ -67,7 +73,7 @@ namespace epics { namespace pvData {
/* Stores file and line number given, and when possible the call stack
* at the point where it was constructed
*/
class ExceptionMixin {
class epicsShareClass ExceptionMixin {
const char *m_file;
int m_line;
#ifndef EXCEPT_USE_NONE
@@ -103,7 +109,7 @@ namespace detail {
*
* Takes advantage of the requirement that all exception classes
* must be copy constructable. Of course this also requires
* the and extra copy be constructed...
* that an extra copy be constructed...
*/
template<typename E>
class ExceptionMixed : public E, public ExceptionMixin {
@@ -197,7 +203,7 @@ do { \
#endif // THROW_EXCEPTION_COMPAT
class BaseException : public std::logic_error {
class epicsShareClass BaseException : public std::logic_error {
public:
explicit BaseException(const std::string msg) : std::logic_error(msg) {}
@@ -209,6 +215,10 @@ private:
mutable std::string base_msg;
};
#ifdef _WIN32
#pragma warning( pop )
#endif
#define THROW_BASE_EXCEPTION(msg) THROW_EXCEPTION2(::epics::pvData::BaseException, msg)
#define THROW_BASE_EXCEPTION_CAUSE(msg, cause) THROW_EXCEPTION2(::epics::pvData::BaseException, msg)

View File

@@ -19,11 +19,15 @@
#include <epicsThread.h>
#include <epicsMutex.h>
#include <epicsEvent.h>
#define epicsExportSharedSymbols
#include <pv/noDefaultMethods.h>
#include <pv/pvType.h>
#include <pv/lock.h>
#include <pv/event.h>
using std::string;
namespace epics { namespace pvData {
@@ -41,27 +45,27 @@ Event::Event(bool full)
void Event::signal()
{
if(id==0) throw std::logic_error(String("event was deleted"));
if(id==0) throw std::logic_error(string("event was deleted"));
epicsEventSignal(id);
}
bool Event::wait ()
{
if(id==0) throw std::logic_error(String("event was deleted"));
if(id==0) throw std::logic_error(string("event was deleted"));
epicsEventWaitStatus status = epicsEventWait(id);
return status==epicsEventWaitOK ? true : false;
}
bool Event::wait ( double timeOut )
{
if(id==0) throw std::logic_error(String("event was deleted"));
if(id==0) throw std::logic_error(string("event was deleted"));
epicsEventWaitStatus status = epicsEventWaitWithTimeout(id,timeOut);
return status==epicsEventWaitOK ? true : false;
}
bool Event::tryWait ()
{
if(id==0) throw std::logic_error(String("event was deleted"));
if(id==0) throw std::logic_error(string("event was deleted"));
epicsEventWaitStatus status = epicsEventTryWait(id);
return status==epicsEventWaitOK ? true : false;
}

View File

@@ -9,18 +9,33 @@
*/
#ifndef EVENT_H
#define EVENT_H
#include <memory>
#include <vector>
#ifdef epicsExportSharedSymbols
#define eventepicsExportSharedSymbols
#undef epicsExportSharedSymbols
#endif
#include <epicsEvent.h>
#ifdef eventepicsExportSharedSymbols
#define epicsExportSharedSymbols
#undef eventepicsExportSharedSymbols
#endif
#include <pv/pvType.h>
#include <pv/sharedPtr.h>
#include <shareLib.h>
namespace epics { namespace pvData {
class Event;
typedef std::tr1::shared_ptr<Event> EventPtr;
class Event {
class epicsShareClass Event {
public:
POINTER_DEFINITIONS(Event);
explicit Event(bool = false);
@@ -31,7 +46,7 @@ public:
bool tryWait (); /* false if empty */
private:
epicsEventId id;
String alreadyOn;
std::string alreadyOn;
};
}}

View File

@@ -13,8 +13,11 @@
#include <string>
#include <cstdio>
#define epicsExportSharedSymbols
#include <pv/executor.h>
using std::string;
namespace epics { namespace pvData {
// special instance to stop the executor thread
@@ -30,7 +33,7 @@ static
std::tr1::shared_ptr<Command> shutdown(new ExecutorShutdown());
Executor::Executor(String threadName,ThreadPriority priority)
Executor::Executor(string const & threadName,ThreadPriority priority)
: thread(threadName,priority,this)
{
}
@@ -57,6 +60,7 @@ void Executor::run()
xx.lock();
}
CommandPtr command = head;
head = command->next;
if(command.get()==NULL) continue;
if(command.get()==shutdown.get()) break;
xx.unlock();
@@ -83,7 +87,8 @@ void Executor::execute(CommandPtr const & command)
moreWork.signal();
return;
}
if(tail.get()==NULL) return;
CommandPtr tail = head;
while(tail->next!=NULL) tail = tail->next;
tail->next = command;
}

View File

@@ -9,13 +9,17 @@
*/
#ifndef EXECUTOR_H
#define EXECUTOR_H
#include <memory>
#include <pv/pvType.h>
#include <pv/lock.h>
#include <pv/event.h>
#include <pv/thread.h>
#include <pv/sharedPtr.h>
#include <shareLib.h>
namespace epics { namespace pvData {
class Command;
@@ -23,7 +27,7 @@ class Executor;
typedef std::tr1::shared_ptr<Command> CommandPtr;
typedef std::tr1::shared_ptr<Executor> ExecutorPtr;
class Command {
class epicsShareClass Command {
public:
POINTER_DEFINITIONS(Command);
virtual ~Command(){}
@@ -33,10 +37,10 @@ private:
friend class Executor;
};
class Executor : public Runnable{
class epicsShareClass Executor : public Runnable{
public:
POINTER_DEFINITIONS(Executor);
Executor(String threadName,ThreadPriority priority);
Executor(std::string const & threadName,ThreadPriority priority);
~Executor();
void execute(CommandPtr const &node);
virtual void run();

View File

@@ -8,6 +8,7 @@
* @author mse
*/
#define epicsExportSharedSymbols
#include <pv/localStaticLock.h>
static int nifty_counter;

View File

@@ -12,7 +12,9 @@
#include <pv/lock.h>
extern epics::pvData::Mutex& getLocalStaticInitMutex();
#include <shareLib.h>
epicsShareExtern epics::pvData::Mutex& getLocalStaticInitMutex();
#if defined(__GNUC__) && __GNUC__ >= 4
// noop
@@ -21,7 +23,7 @@ extern epics::pvData::Mutex& getLocalStaticInitMutex();
#define LOCAL_STATIC_LOCK epics::pvData::Lock localStaticInitMutexLock(getLocalStaticInitMutex());
#endif
static class MutexInitializer {
static class epicsShareClass MutexInitializer {
public:
MutexInitializer ();
~MutexInitializer ();

View File

@@ -9,9 +9,25 @@
*/
#ifndef LOCK_H
#define LOCK_H
#include <stdexcept>
#ifdef epicsExportSharedSymbols
#define lockepicsExportSharedSymbols
#undef epicsExportSharedSymbols
#endif
#include <epicsMutex.h>
#ifdef lockepicsExportSharedSymbols
#define epicsExportSharedSymbols
#undef lockepicsExportSharedSymbols
#endif
#include <pv/noDefaultMethods.h>
#include <shareLib.h>
/* This is based on item 14 of
* Effective C++, Third Edition, Scott Meyers
*/
@@ -22,7 +38,7 @@ namespace epics { namespace pvData {
typedef epicsMutex Mutex;
class Lock : private NoDefaultMethods {
class epicsShareClass Lock : private NoDefaultMethods {
public:
explicit Lock(Mutex &m)
: mutexPtr(m), locked(true)
@@ -44,6 +60,15 @@ public:
locked=false;
}
}
bool tryLock()
{
if(locked) return true;
if(mutexPtr.tryLock()) {
locked = true;
return true;
}
return false;
}
bool ownsLock() const{return locked;}
private:
Mutex &mutexPtr;

View File

@@ -8,14 +8,19 @@
* @author mrk
*/
#include <string>
#define epicsExportSharedSymbols
#include <pv/messageQueue.h>
using std::string;
namespace epics { namespace pvData {
MessageNode::MessageNode()
: messageType(infoMessage)
{}
String MessageNode::getMessage() const
string MessageNode::getMessage() const
{
return message;
}
@@ -56,7 +61,7 @@ void MessageQueue::release() {
releaseUsed(lastGet);
lastGet.reset();
}
bool MessageQueue::put(String message,MessageType messageType,bool replaceLast)
bool MessageQueue::put(string message,MessageType messageType,bool replaceLast)
{
MessageNodePtr node = getFree();
if(node.get()!= NULL) {

View File

@@ -18,6 +18,8 @@
#include <pv/requester.h>
#include <pv/queue.h>
#include <shareLib.h>
namespace epics { namespace pvData {
class MessageNode;
@@ -26,18 +28,18 @@ typedef std::tr1::shared_ptr<MessageNode> MessageNodePtr;
typedef std::vector<MessageNodePtr> MessageNodePtrArray;
typedef std::tr1::shared_ptr<MessageQueue> MessageQueuePtr;
class MessageNode {
class epicsShareClass MessageNode {
public:
MessageNode();
String getMessage() const;
std::string getMessage() const;
MessageType getMessageType() const;
private:
String message;
std::string message;
MessageType messageType;
friend class MessageQueue;
};
class MessageQueue : public Queue<MessageNode> {
class epicsShareClass MessageQueue : public Queue<MessageNode> {
public:
POINTER_DEFINITIONS(MessageQueue);
static MessageQueuePtr create(int size);
@@ -47,7 +49,7 @@ public:
// must call release before next get
void release();
// return (false,true) if message (was not, was) put into queue
bool put(String message,MessageType messageType,bool replaceLast);
bool put(std::string message,MessageType messageType,bool replaceLast);
bool isEmpty() ;
bool isFull() ;
int getClearOverrun();

View File

@@ -9,13 +9,16 @@
*/
#ifndef NO_DEFAULT_METHODS_H
#define NO_DEFAULT_METHODS_H
#include <shareLib.h>
namespace epics { namespace pvData {
/* This is based on Item 6 of
* Effective C++, Third Edition, Scott Meyers
*/
class NoDefaultMethods {
class epicsShareClass NoDefaultMethods {
protected:
// allow by derived objects
NoDefaultMethods(){};

480
src/misc/parseToPOD.cpp Normal file
View File

@@ -0,0 +1,480 @@
#include <ctype.h>
#include <stdio.h>
#include <errno.h>
#include <float.h>
#include <limits.h>
#include <epicsVersion.h>
#include <epicsMath.h>
#include <epicsStdlib.h>
#include <epicsString.h>
#include <epicsConvert.h>
#define epicsExportSharedSymbols
#include "typeCast.h"
using std::string;
// need to use "long long" when sizeof(int)==sizeof(long)
#if (ULONG_MAX == 0xfffffffful) || defined(_WIN32) || defined(__rtems__)
#define NEED_LONGLONG
#endif
#ifndef EPICS_VERSION_INT
#define VERSION_INT(V,R,M,P) ( ((V)<<24) | ((R)<<16) | ((M)<<8) | (P))
#define EPICS_VERSION_INT VERSION_INT(EPICS_VERSION, EPICS_REVISION, EPICS_MODIFICATION, EPICS_PATCH_LEVEL)
#endif
#if EPICS_VERSION_INT < VERSION_INT(3,15,0,1)
/* integer conversion primatives added to epicsStdlib.c in 3.15.0.1 */
#define S_stdlib_noConversion 1 /* No digits to convert */
#define S_stdlib_extraneous 2 /* Extraneous characters */
#define S_stdlib_underflow 3 /* Too small to represent */
#define S_stdlib_overflow 4 /* Too large to represent */
#define S_stdlib_badBase 5 /* Number base not supported */
static int
epicsParseLong(const char *str, long *to, int base, char **units)
{
int c;
char *endp;
long value;
while ((c = *str) && isspace(c))
++str;
errno = 0;
value = strtol(str, &endp, base);
if (endp == str)
return S_stdlib_noConversion;
if (errno == EINVAL) /* Not universally supported */
return S_stdlib_badBase;
if (errno == ERANGE)
return S_stdlib_overflow;
while ((c = *endp) && isspace(c))
++endp;
if (c && !units)
return S_stdlib_extraneous;
*to = value;
if (units)
*units = endp;
return 0;
}
static int
epicsParseULong(const char *str, unsigned long *to, int base, char **units)
{
int c;
char *endp;
unsigned long value;
while ((c = *str) && isspace(c))
++str;
errno = 0;
value = strtoul(str, &endp, base);
if (endp == str)
return S_stdlib_noConversion;
if (errno == EINVAL) /* Not universally supported */
return S_stdlib_badBase;
if (errno == ERANGE)
return S_stdlib_overflow;
while ((c = *endp) && isspace(c))
++endp;
if (c && !units)
return S_stdlib_extraneous;
*to = value;
if (units)
*units = endp;
return 0;
}
static int
epicsParseDouble(const char *str, double *to, char **units)
{
int c;
char *endp;
double value;
while ((c = *str) && isspace(c))
++str;
errno = 0;
value = epicsStrtod(str, &endp);
if (endp == str)
return S_stdlib_noConversion;
if (errno == ERANGE)
return (value == 0) ? S_stdlib_underflow : S_stdlib_overflow;
while ((c = *endp) && isspace(c))
++endp;
if (c && !units)
return S_stdlib_extraneous;
*to = value;
if (units)
*units = endp;
return 0;
}
/* These call the primitives */
static int
epicsParseInt8(const char *str, epicsInt8 *to, int base, char **units)
{
long value;
int status = epicsParseLong(str, &value, base, units);
if (status)
return status;
if (value < -0x80 || value > 0x7f)
return S_stdlib_overflow;
*to = (epicsInt8)value;
return 0;
}
static int
epicsParseUInt8(const char *str, epicsUInt8 *to, int base, char **units)
{
unsigned long value;
int status = epicsParseULong(str, &value, base, units);
if (status)
return status;
if (value > 0xff && value <= ~0xffUL)
return S_stdlib_overflow;
*to = (epicsUInt8)value;
return 0;
}
static int
epicsParseInt16(const char *str, epicsInt16 *to, int base, char **units)
{
long value;
int status = epicsParseLong(str, &value, base, units);
if (status)
return status;
if (value < -0x8000 || value > 0x7fff)
return S_stdlib_overflow;
*to = (epicsInt16)value;
return 0;
}
static int
epicsParseUInt16(const char *str, epicsUInt16 *to, int base, char **units)
{
unsigned long value;
int status = epicsParseULong(str, &value, base, units);
if (status)
return status;
if (value > 0xffff && value <= ~0xffffUL)
return S_stdlib_overflow;
*to = (epicsUInt16)value;
return 0;
}
static int
epicsParseInt32(const char *str, epicsInt32 *to, int base, char **units)
{
long value;
int status = epicsParseLong(str, &value, base, units);
if (status)
return status;
#if (LONG_MAX > 0x7fffffff)
if (value < -0x80000000L || value > 0x7fffffffL)
return S_stdlib_overflow;
#endif
*to = (epicsInt32)value;
return 0;
}
static int
epicsParseUInt32(const char *str, epicsUInt32 *to, int base, char **units)
{
unsigned long value;
int status = epicsParseULong(str, &value, base, units);
if (status)
return status;
#if (ULONG_MAX > 0xffffffff)
if (value > 0xffffffffUL && value <= ~0xffffffffUL)
return S_stdlib_overflow;
#endif
*to = (epicsUInt32)value;
return 0;
}
static int
epicsParseFloat(const char *str, float *to, char **units)
{
double value, abs;
int status = epicsParseDouble(str, &value, units);
if (status)
return status;
abs = fabs(value);
if (value > 0 && abs <= FLT_MIN)
return S_stdlib_underflow;
if (finite(value) && abs >= FLT_MAX)
return S_stdlib_overflow;
*to = (float)value;
return 0;
}
#endif
#if defined(NEED_LONGLONG) && (defined(__vxworks) || defined (_WIN32))
static
long long strtoll(const char *ptr, char ** endp, int base)
{
size_t inlen = strlen(ptr);
long long result;
unsigned char offset=0;
assert(base==0);
if(ptr[0]=='-')
offset=1;
try {
std::istringstream strm(ptr);
assert(strm.rdbuf()->in_avail()>=0
&& inlen==(size_t)strm.rdbuf()->in_avail());
if(ptr[offset]=='0') {
if(ptr[offset+1]=='x')
strm >> std::hex;
else
strm >> std::oct;
}
strm >> result;
if(strm.fail())
goto noconvert;
assert(strm.rdbuf()->in_avail()>=0
&& inlen>=(size_t)strm.rdbuf()->in_avail());
size_t consumed = inlen - strm.rdbuf()->in_avail();
*endp = (char*)ptr + consumed;
return result;
} catch(...) {
goto noconvert;
}
return result;
noconvert:
*endp = (char*)ptr;
return 0;
}
static
unsigned long long strtoull(const char *ptr, char ** endp, int base)
{
size_t inlen = strlen(ptr);
unsigned long long result;
assert(base==0);
try {
std::istringstream strm(ptr);
assert(strm.rdbuf()->in_avail()>=0
&& inlen==(size_t)strm.rdbuf()->in_avail());
if(ptr[0]=='0') {
if(ptr[1]=='x')
strm >> std::hex;
else
strm >> std::oct;
}
strm >> result;
if(strm.fail())
goto noconvert;
assert(strm.rdbuf()->in_avail()>=0
&& inlen>=(size_t)strm.rdbuf()->in_avail());
size_t consumed = inlen - strm.rdbuf()->in_avail();
*endp = (char*)ptr + consumed;
return result;
} catch(...) {
goto noconvert;
}
return result;
noconvert:
*endp = (char*)ptr;
return 0;
}
#endif
/* do we need long long? */
#ifdef NEED_LONGLONG
static int
epicsParseLongLong(const char *str, long long *to, int base, char **units)
{
int c;
char *endp;
long long value;
while ((c = *str) && isspace(c))
++str;
errno = 0;
value = strtoll(str, &endp, base);
if (endp == str)
return S_stdlib_noConversion;
if (errno == EINVAL) /* Not universally supported */
return S_stdlib_badBase;
if (errno == ERANGE)
return S_stdlib_overflow;
while ((c = *endp) && isspace(c))
++endp;
if (c && !units)
return S_stdlib_extraneous;
*to = value;
if (units)
*units = endp;
return 0;
}
static int
epicsParseULongLong(const char *str, unsigned long long *to, int base, char **units)
{
int c;
char *endp;
unsigned long long value;
while ((c = *str) && isspace(c))
++str;
errno = 0;
value = strtoull(str, &endp, base);
if (endp == str)
return S_stdlib_noConversion;
if (errno == EINVAL) /* Not universally supported */
return S_stdlib_badBase;
if (errno == ERANGE)
return S_stdlib_overflow;
while ((c = *endp) && isspace(c))
++endp;
if (c && !units)
return S_stdlib_extraneous;
*to = value;
if (units)
*units = endp;
return 0;
}
#endif
static
void handleParseError(int err)
{
switch(err) {
case 0: break;
case S_stdlib_noConversion: throw std::runtime_error("parseToPOD: No digits to convert");
case S_stdlib_extraneous: throw std::runtime_error("parseToPOD: Extraneous characters");
case S_stdlib_underflow: throw std::runtime_error("parseToPOD: Too small to represent");
case S_stdlib_overflow: throw std::runtime_error("parseToPOD: Too large to represent");
case S_stdlib_badBase: throw std::runtime_error("parseToPOD: Number base not supported");
default:
throw std::runtime_error("parseToPOD: unknown error");
}
}
namespace epics { namespace pvData { namespace detail {
void parseToPOD(const string & in, boolean *out)
{
if(epicsStrCaseCmp(in.c_str(),"true")==0)
*out = 1;
else if(epicsStrCaseCmp(in.c_str(),"false")==0)
*out = 0;
else
throw std::runtime_error("parseToPOD: string no match true/false");
}
#define INTFN(T, S) \
void parseToPOD(const string& in, T *out) { \
epics ## S temp; \
int err = epicsParse ## S (in.c_str(), &temp, 0, NULL); \
if(err) handleParseError(err); \
else *out = temp; \
}
INTFN(int8, Int8);
INTFN(uint8, UInt8);
INTFN(int16_t, Int16);
INTFN(uint16_t, UInt16);
INTFN(int32_t, Int32);
INTFN(uint32_t, UInt32);
void parseToPOD(const string& in, int64_t *out) {
#ifdef NEED_LONGLONG
int err = epicsParseLongLong(in.c_str(), out, 0, NULL);
#else
int err = epicsParseLong(in.c_str(), out, 0, NULL);
#endif
if(err) handleParseError(err);
}
void parseToPOD(const string& in, uint64_t *out) {
#ifdef NEED_LONGLONG
int err = epicsParseULongLong(in.c_str(), out, 0, NULL);
#else
int err = epicsParseULong(in.c_str(), out, 0, NULL);
#endif
if(err) handleParseError(err);
}
void parseToPOD(const string& in, float *out) {
int err = epicsParseFloat(in.c_str(), out, NULL);
if(err) handleParseError(err);
}
void parseToPOD(const string& in, double *out) {
int err = epicsParseDouble(in.c_str(), out, NULL);
if(err) handleParseError(err);
}
}}}

View File

@@ -7,12 +7,15 @@
/**
* @author mrk
*/
#ifndef QUEUE_H
#define QUEUE_H
#include <vector>
#include <cstddef>
#include <stdexcept>
#include <pv/sharedPtr.h>
#ifndef QUEUE_H
#define QUEUE_H
namespace epics { namespace pvData {
template <typename T>
@@ -29,12 +32,13 @@ public:
int getNumberFree();
int getNumberUsed();
queueElementPtr & getFree();
void setUsed(queueElementPtr &element);
void setUsed(queueElementPtr const &element);
queueElementPtr & getUsed();
void releaseUsed(queueElementPtr &element);
void releaseUsed(queueElementPtr const &element);
private:
queueElementPtr nullElement;
queueElementPtrArray elements;
// TODO use size_t instead
int size;
int numberFree;
int numberUsed;
@@ -46,7 +50,7 @@ private:
template <typename T>
Queue<T>::Queue(std::vector<queueElementPtr> &xxx)
: size(xxx.size()),
: size(static_cast<int>(xxx.size())),
numberFree(size),
numberUsed(0),
nextGetFree(0),
@@ -92,7 +96,7 @@ std::tr1::shared_ptr<T> & Queue<T>::getFree()
}
template <typename T>
void Queue<T>::setUsed(std::tr1::shared_ptr<T> &element)
void Queue<T>::setUsed(std::tr1::shared_ptr<T> const &element)
{
if(element!=elements[nextSetUsed++]) {
throw std::logic_error("not correct queueElement");
@@ -112,7 +116,7 @@ std::tr1::shared_ptr<T> & Queue<T>::getUsed()
}
template <typename T>
void Queue<T>::releaseUsed(std::tr1::shared_ptr<T> &element)
void Queue<T>::releaseUsed(std::tr1::shared_ptr<T> const &element)
{
if(element!=elements[nextReleaseUsed++]) {
throw std::logic_error(

View File

@@ -9,15 +9,20 @@
*/
#include <string>
#include <cstdio>
#define epicsExportSharedSymbols
#include <pv/lock.h>
#include <pv/requester.h>
using std::string;
namespace epics { namespace pvData {
const size_t messageTypeCount = 4;
static StringArray messageTypeName(messageTypeCount);
static StringArray messageTypeName(MESSAGE_TYPE_COUNT);
String getMessageTypeName(MessageType messageType)
string getMessageTypeName(MessageType messageType)
{
// TODO not thread-safe
static Mutex mutex;
Lock xx(mutex);
if(messageTypeName[0].size()==0) {

View File

@@ -10,9 +10,12 @@
#ifndef REQUESTER_H
#define REQUESTER_H
#include <string>
#include <pv/pvType.h>
#include <pv/sharedPtr.h>
#include <shareLib.h>
namespace epics { namespace pvData {
class Requester;
@@ -21,15 +24,16 @@ typedef std::tr1::shared_ptr<Requester> RequesterPtr;
enum MessageType {
infoMessage,warningMessage,errorMessage,fatalErrorMessage
};
#define MESSAGE_TYPE_COUNT 4
extern String getMessageTypeName(MessageType messageType);
extern const size_t messageTypeCount;
class Requester {
epicsShareExtern std::string getMessageTypeName(MessageType messageType);
class epicsShareClass Requester {
public:
POINTER_DEFINITIONS(Requester);
virtual ~Requester(){}
virtual String getRequesterName() = 0;
virtual void message(String const & message,MessageType messageType) = 0;
virtual std::string getRequesterName() = 0;
virtual void message(std::string const & message,MessageType messageType) = 0;
};
}}

View File

@@ -9,8 +9,12 @@
*/
#ifndef SERIALIZE_H
#define SERIALIZE_H
#include <pv/byteBuffer.h>
#include <pv/sharedPtr.h>
#include <shareLib.h>
namespace epics { namespace pvData {
class SerializableControl;
@@ -21,24 +25,28 @@ namespace epics { namespace pvData {
class BitSet;
class Field;
class SerializableControl {
class epicsShareClass SerializableControl {
public:
virtual ~SerializableControl(){}
virtual void flushSerializeBuffer() =0;
virtual void ensureBuffer(std::size_t size) =0;
virtual void alignBuffer(std::size_t alignment) =0;
virtual bool directSerialize(ByteBuffer *existingBuffer, const char* toSerialize,
std::size_t elementCount, std::size_t elementSize) = 0;
virtual void cachedSerialize(std::tr1::shared_ptr<const Field> const & field, ByteBuffer* buffer) = 0;
};
class DeserializableControl {
class epicsShareClass DeserializableControl {
public:
virtual ~DeserializableControl(){}
virtual void ensureData(std::size_t size) =0;
virtual void alignData(std::size_t alignment) =0;
virtual bool directDeserialize(ByteBuffer *existingBuffer, char* deserializeTo,
std::size_t elementCount, std::size_t elementSize) = 0;
virtual std::tr1::shared_ptr<const Field> cachedDeserialize(ByteBuffer* buffer) = 0;
};
class Serializable {
class epicsShareClass Serializable {
public:
virtual ~Serializable(){}
virtual void serialize(ByteBuffer *buffer,
@@ -47,7 +55,7 @@ namespace epics { namespace pvData {
DeserializableControl *flusher) = 0;
};
class BitSetSerializable {
class epicsShareClass BitSetSerializable {
public:
virtual ~BitSetSerializable(){}
virtual void serialize(ByteBuffer *buffer,
@@ -57,7 +65,7 @@ namespace epics { namespace pvData {
};
class SerializableArray : virtual public Serializable {
class epicsShareClass SerializableArray : virtual public Serializable {
public:
virtual ~SerializableArray(){}
virtual void serialize(ByteBuffer *buffer,

View File

@@ -11,13 +11,13 @@
*/
#include <algorithm>
#include <pv/pvType.h>
#define epicsExportSharedSymbols
#include <pv/pvType.h>
#include <pv/epicsException.h>
#include <pv/byteBuffer.h>
#include <pv/serializeHelper.h>
using namespace std;
namespace epics {
@@ -33,11 +33,11 @@ namespace epics {
if(s==(std::size_t)-1) // null // TODO remove
buffer->putByte(-1);
else if(s<254)
buffer->putByte(s);
buffer->putByte(static_cast<int8>(s));
else
{
buffer->putByte(-2);
buffer->putInt(s); // (byte)-2 + size
buffer->putInt(static_cast<uint32>(s)); // (byte)-2 + size
}
}
@@ -57,7 +57,7 @@ namespace epics {
return (std::size_t)(b<0 ? b+256 : b);
}
void SerializeHelper::serializeString(const String& value,
void SerializeHelper::serializeString(const string& value,
ByteBuffer* buffer, SerializableControl* flusher) {
std::size_t len = value.length();
SerializeHelper::writeSize(len, buffer, flusher);
@@ -74,17 +74,17 @@ namespace epics {
}
}
void SerializeHelper::serializeSubstring(const String& value,
void SerializeHelper::serializeSubstring(const string& value,
std::size_t offset, std::size_t count, ByteBuffer* buffer,
SerializableControl* flusher) {
if(offset<0)
/*if(offset<0)
offset = 0;
else if(offset>(std::size_t)value.length()) offset = value.length();
else*/ if(offset>value.length()) offset = value.length();
if(offset+count>(std::size_t)value.length()) count = value.length()-offset;
if(offset+count>value.length()) count = value.length()-offset;
SerializeHelper::writeSize(count, buffer, flusher);
if (count<=0) return;
/*if (count<=0)*/ return;
std::size_t i = 0;
while(true) {
std::size_t maxToWrite = min(count-i, buffer->getRemaining());
@@ -97,9 +97,9 @@ namespace epics {
}
}
static String emptyString;
static string emptyStringtring;
String SerializeHelper::deserializeString(ByteBuffer* buffer,
string SerializeHelper::deserializeString(ByteBuffer* buffer,
DeserializableControl* control) {
std::size_t size = SerializeHelper::readSize(buffer, control);
@@ -109,13 +109,13 @@ namespace epics {
{
// entire string is in buffer, simply create a string out of it (copy)
std::size_t pos = buffer->getPosition();
String str(buffer->getArray()+pos, size);
string str(buffer->getArray()+pos, size);
buffer->setPosition(pos+size);
return str;
}
else
{
String str;
string str;
str.reserve(size);
try {
std::size_t i = 0;
@@ -137,7 +137,7 @@ namespace epics {
}
}
else
return emptyString;
return emptyStringtring;
}
}

View File

@@ -18,10 +18,12 @@
#include <pv/noDefaultMethods.h>
#include <pv/pvIntrospect.h>
#include <shareLib.h>
namespace epics {
namespace pvData {
class SerializeHelper : public NoDefaultMethods {
class epicsShareClass SerializeHelper : public NoDefaultMethods {
public:
/**
@@ -44,30 +46,30 @@ namespace epics {
DeserializableControl* control);
/**
* String serialization helper method.
* std::string serialization helper method.
*
* @param[in] value String to serialize
* @param[in] value std::string to serialize
* @param[in] buffer serialization buffer
* @param[in] flusher flusher
*/
static void serializeString(const String& value, ByteBuffer* buffer,
static void serializeString(const std::string& value, ByteBuffer* buffer,
SerializableControl* flusher);
/**
* String serialization helper method.
* std::string serialization helper method.
*
* @param[in] value String to serialize
* @param[in] value std::string to serialize
* @param[in] offset start of the substring in {@code value}
* @param[in] count the number of characters to write
* @param[in] buffer serialization buffer
* @param[in] flusher flusher
*/
static void serializeSubstring(const String& value, std::size_t offset,
static void serializeSubstring(const std::string& value, std::size_t offset,
std::size_t count, ByteBuffer* buffer,
SerializableControl* flusher);
/**
* String deserialization helper method.
* std::string deserialization helper method.
* TODO This method cannot return "null", but Java implementation
* could have serialized "null" value as well. We need to decide
* how to deserialize "null".
@@ -80,7 +82,7 @@ namespace epics {
* could have serialized "null" value as well. We need to decide
* how to deserialize "null".
*/
static String deserializeString(ByteBuffer* buffer,
static std::string deserializeString(ByteBuffer* buffer,
DeserializableControl* control);
private:

View File

@@ -4,7 +4,7 @@
* in file LICENSE that is included with this distribution.
*/
/**
* @author Michael DavidSaver
* @author Michael Davidsaver
*/
#ifndef SHAREDPTR_H
@@ -77,6 +77,6 @@
typedef std::tr1::shared_ptr<clazz> shared_pointer; \
typedef std::tr1::shared_ptr<const clazz> const_shared_pointer; \
typedef std::tr1::weak_ptr<clazz> weak_pointer; \
typedef std::tr1::weak_ptr<const clazz> const_weak_pointer;
typedef std::tr1::weak_ptr<const clazz> const_weak_pointer
#endif // SHAREDPTR_H

1015
src/misc/sharedVector.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -7,14 +7,17 @@
/**
* @author mrk
*/
#include <pv/status.h>
#define epicsExportSharedSymbols
#include <pv/epicsException.h>
#include <pv/serializeHelper.h>
#include <pv/status.h>
using std::string;
namespace epics { namespace pvData {
const char* Status::StatusTypeName[] = { "OK", "WARNING", "ERROR", "FATAL" };
epics::pvData::String Status::m_emptyString;
string Status::m_emptyStringtring;
Status Status::Ok;
@@ -25,7 +28,7 @@ Status::Status() :
{
}
Status::Status(StatusType type, String const & message) :
Status::Status(StatusType type, string const & message) :
m_statusType(type), m_message(message)
{
if (type == STATUSTYPE_OK)
@@ -34,7 +37,7 @@ Status::Status(StatusType type, String const & message) :
//PVDATA_REFCOUNT_MONITOR_CONSTRUCT(status);
}
Status::Status(StatusType type, String const & message, String const & stackDump) :
Status::Status(StatusType type, string const & message, string const & stackDump) :
m_statusType(type), m_message(message), m_stackDump(stackDump)
{
if (type == STATUSTYPE_OK)
@@ -53,12 +56,12 @@ Status::StatusType Status::getType() const
}
epics::pvData::String Status::getMessage() const
string Status::getMessage() const
{
return m_message;
}
epics::pvData::String Status::getStackDump() const
string Status::getStackDump() const
{
return m_stackDump;
}
@@ -99,7 +102,7 @@ void Status::deserialize(ByteBuffer *buffer, DeserializableControl *flusher)
if (m_statusType != STATUSTYPE_OK)
{
m_statusType = STATUSTYPE_OK;
m_message = m_stackDump = m_emptyString;
m_message = m_stackDump = m_emptyStringtring;
}
}
else
@@ -110,29 +113,26 @@ void Status::deserialize(ByteBuffer *buffer, DeserializableControl *flusher)
}
}
String Status::toString() const
void Status::dump(std::ostream& o) const
{
String str;
toString(&str, 0);
return str;
o << "Status [type=" << Status::StatusTypeName[m_statusType];
if (!m_message.empty())
o << ", message=" << m_message;
if (!m_stackDump.empty())
o << ", stackDump=" << std::endl << m_stackDump;
o << ']';
}
std::ostream& operator<<(std::ostream& o, const Status& status)
{
status.dump(o);
return o;
}
void Status::toString(StringBuilder buffer, int indentLevel) const
std::ostream& operator<<(std::ostream& o, const Status::StatusType& statusType)
{
*buffer += "Status [type=";
*buffer += StatusTypeName[m_statusType];
if (!m_message.empty())
{
*buffer += ", message=";
*buffer += m_message;
}
if (!m_stackDump.empty())
{
*buffer += ", stackDump=";
*buffer += '\n';
*buffer += m_stackDump;
}
*buffer += ']';
o << Status::StatusTypeName[statusType];
return o;
}
}}

View File

@@ -10,17 +10,21 @@
#ifndef STATUS_H
#define STATUS_H
#include <ostream>
#include <pv/serialize.h>
#include <pv/byteBuffer.h>
#include <pv/sharedPtr.h>
#include <shareLib.h>
namespace epics { namespace pvData {
/**
* Status.
* @author mse
*/
class Status : public epics::pvData::Serializable {
class epicsShareClass Status : public epics::pvData::Serializable {
public:
POINTER_DEFINITIONS(Status);
/**
@@ -49,12 +53,12 @@ namespace epics { namespace pvData {
/**
* Create non-OK status.
*/
Status(StatusType type, epics::pvData::String const & message);
Status(StatusType type, std::string const & message);
/**
* Create non-OK status.
*/
Status(StatusType type, epics::pvData::String const & message, epics::pvData::String const & stackDump);
Status(StatusType type, std::string const & message, std::string const & stackDump);
~Status();
@@ -68,13 +72,13 @@ namespace epics { namespace pvData {
* Get error message describing an error. Required if error status.
* @return error message.
*/
epics::pvData::String getMessage() const;
std::string getMessage() const;
/**
* Get stack dump where error (exception) happened. Optional.
* @return stack dump.
*/
epics::pvData::String getStackDump() const;
std::string getStackDump() const;
/**
* Convenient OK test. Same as <code>(getType() == StatusType.OK)</code>.
@@ -91,20 +95,23 @@ namespace epics { namespace pvData {
*/
bool isSuccess() const;
String toString() const;
void toString(StringBuilder buffer, int indentLevel = 0) const;
void serialize(ByteBuffer *buffer, SerializableControl *flusher) const;
void deserialize(ByteBuffer *buffer, DeserializableControl *flusher);
void dump(std::ostream& o) const;
private:
static epics::pvData::String m_emptyString;
static std::string m_emptyStringtring;
StatusType m_statusType;
String m_message;
String m_stackDump;
std::string m_message;
std::string m_stackDump;
};
epicsShareExtern std::ostream& operator<<(std::ostream& o, const Status& status);
epicsShareExtern std::ostream& operator<<(std::ostream& o, const Status::StatusType& statusType);
}}
#endif /* STATUS_H */

120
src/misc/templateMeta.h Normal file
View File

@@ -0,0 +1,120 @@
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/** C++ Template meta programming helpers
*/
#ifndef TEMPLATEMETA_H
#define TEMPLATEMETA_H
// gently nudge the compiler to inline our wrappers
// Warning: Only use this when the template body is *small*.
// You have been warned!
#if defined(__GNUC__) && __GNUC__>=3
# define FORCE_INLINE __attribute__((always_inline)) inline
#elif defined(_MSC_VER)
# define FORCE_INLINE __forceinline
#else
# define FORCE_INLINE inline
#endif
namespace epics { namespace pvData {
namespace meta {
/** If needed, add the 'const' qualifier to the provided type.
*
* Avoids adding the const qualifier twice (aka 'const const int')
@code
assert(typeid(decorate_const<int>::type)==typeid(const int));
assert(typeid(decorate_const<const int>::type)==typeid(const int));
@endcode
*/
template<typename T> struct decorate_const { typedef const T type; };
template<typename T> struct decorate_const<const T> { typedef const T type; };
/** Remove the 'const' qualifier if present
@code
assert(typeid(strip_const<int>::type)==typeid(int));
assert(typeid(strip_const<const int>::type)==typeid(int));
@endcode
*/
template<typename T> struct strip_const { typedef T type; };
template<typename T> struct strip_const<const T> { typedef T type; };
/** test to allow specialization only when A!=B
*
@code
template<typename A, typename B, class Enable = void>
struct myTemp {...};
// specialization when A==B
template<typename T>
struct myTemp<T,T> {...};
// specialization for A is 'int',
// enabler needed to remove ambiguity when B is 'int'.
template<typename B>
struct myTemp<int, B, typename meta::not_same_type<int,B>::type>
{...};
@endcode
*/
template<typename A, typename B, typename R = void>
struct not_same_type {typedef R type;};
template<typename A>
struct not_same_type<A,A> {};
//! Select if both A and B have the same root type (excluding const qualifier)
template<typename A, typename B, class R = void> struct same_root {};
template<typename T, class R> struct same_root<T,T,R> { typedef R type; };
template<typename T, class R> struct same_root<const T,T,R> { typedef R type; };
template<typename T, class R> struct same_root<T,const T,R> { typedef R type; };
namespace detail {
struct _const_yes {};
struct _const_no {};
template<typename T> struct _has_const { typedef _const_no type; };
template<typename T> struct _has_const<const T> { typedef _const_yes type; };
template<typename A, typename B, class R = void> struct _same_type {};
template<typename T, class R> struct _same_type<T,T,R> { typedef R type; };
} // namespace detail
//! Check if both A and B are either const or non-const.
template<typename A, typename B, class R = void>
struct same_const :
public detail::_same_type<typename detail::_has_const<A>::type,
typename detail::_has_const<B>::type,
R>
{};
/** test if provided type is 'void' or 'const void'
*
* Avoid having to explicitly specialize for both
@code
template<typename A, class Enable = void>
struct myTemp {...};
// specialization when A is 'void' or 'const void'
template<typename A>
struct myTemp<A, typename meta::is_void<A>::type> {...};
@endcode
*/
template<typename T, class R = void> struct is_void {};
template<class R> struct is_void<void,R> { typedef R type; };
template<class R> struct is_void<const void,R> { typedef R type; };
//! Inverse of is_void<T>
template<typename T, class R = void> struct is_not_void { typedef R type; };
template<> struct is_not_void<void> {};
template<> struct is_not_void<const void> {};
//! Enabler to ensure that both conditions A and B are true
template<typename A, typename B, class EnableA = void, class EnableB = void, class R = void>
struct _and {};
template<typename A, typename B, class R>
struct _and<A,B, typename A::type, typename B::type, R> { typedef R type; };
}}}
#endif // TEMPLATEMETA_H

Some files were not shown because too many files have changed in this diff Show More