406 Commits

Author SHA1 Message Date
Andrew Johnson
07afe3887b Reset DEVELOPMENT_FLAG for 7.0.0 release 2017-12-14 18:27:26 -06:00
Andrew Johnson
25434ba84f Insert missing release note entries
Most of these changes were only committed on the release branch and
never pulled onto the master branch. Don't want to lose history.
2017-12-14 18:23:51 -06:00
Michael Davidsaver
9787dbd14f anyscalar.h ensure that storage really is large enough
correct failure on cygwin x86 where apparently
sizeof(double) > sizeof(std::string)
2017-12-11 21:08:59 -06:00
Michael Davidsaver
fd9081c80e minor 2017-12-11 21:08:59 -06:00
Michael Davidsaver
e79c49019d quiet warning 2017-12-11 21:08:59 -06:00
Michael Davidsaver
5bc081a3af skip unnecessary inclusion of localStaticLock.h 2017-12-11 21:08:59 -06:00
Andrew Johnson
5976eb5186 Include <top>/../RELEASE.<host>.local 2017-12-06 20:37:27 -06:00
Andrew Johnson
b194bc05b1 Unify .gitignore files 2017-11-30 12:03:33 -06:00
Andrew Johnson
18207fd79e Use 'make test-results' in travis-build script 2017-11-29 16:36:39 -06:00
Andrew Johnson
7c1e0a51eb Fixes needed for older VxWorks GCC 2017-11-29 16:35:22 -06:00
Ralph Lange
7196658166 jenkins: remove microbench option from CB build 2017-11-15 17:28:05 +01:00
Michael Davidsaver
187fe67ffa fixup debugPtr 2017-11-14 17:13:43 -06:00
Andrew Johnson
7136098c3c Suppress unnecessary deprecation warnings
Disable warnings when compiling the implementations of
deprecated classes and functions.

Removes the unused USAGE_DEPRECATED and USAGE_ERROR macros
from pvData.h which aren't visible outside of it anyway.
2017-11-07 22:19:56 -06:00
Andrew Johnson
7979238029 Let's make timeStamp constants actually const 2017-11-07 11:46:36 -06:00
Michael Davidsaver
fc38dff3b0 testPVData: clarify getSubField() by index on sub-struct 2017-11-07 08:18:12 -06:00
Michael Davidsaver
c590204cf9 add epics::auto_ptr<T> and epics::swap()
Avoid the flood of auto_ptr deprecation warnings
in the common cases of using auto_ptr
to automatically delete.
2017-11-06 12:30:40 -06:00
Michael Davidsaver
284e49c807 add EPICS_NOT_COPYABLE()
More localize (my preference), and avoids
warning spam with windows builds.
2017-11-06 11:29:59 -06:00
Michael Davidsaver
43fcd3d1e2 debugPtr use libCom instead of std::
cross-builds of mingw claim c++11 but don't have std::mutex
2017-11-05 14:49:45 -06:00
Michael Davidsaver
a9f2d7df40 reftrack: remove inline operator[]
Use of class static member 'zero'
in an inline'd method is causing DLL confusion
in dependent modules.
2017-11-02 10:08:07 -05:00
Michael Davidsaver
21a03d2b85 rename configure/CONFIG_PVDATA_VERSION 2017-11-01 11:20:14 -05:00
Michael Davidsaver
f123b8654a update ignore 2017-11-01 09:40:42 -05:00
Michael Davidsaver
51cbe538e8 handle yajl 2.1.0 API changes 2017-10-31 19:34:30 -05:00
Marty Kraimer
e247a2c4eb Merge pull request #48 from mrkraimer/master
pvAlarm, pvTimeStamp, pvControl, pvDisplay: only put to fields that h…
2017-10-17 14:52:54 -04:00
Michael Davidsaver
490b6684ac more createRequest tests 2017-10-17 10:15:00 -05:00
mrkraimer
6fdeadf171 pvAlarm, pvTimeStamp, pvControl, pvDisplay: only put to fields that have changed 2017-10-16 10:00:22 -04:00
Michael Davidsaver
a88d491012 win64 one more time, move explicit instantiations after all definitions. 2017-10-06 11:06:23 +02:00
Michael Davidsaver
fd34d68933 another win64 attempt, explicitly instanciate 2017-10-05 16:24:45 +02:00
Michael Davidsaver
215e3aab7b one more attempt to appease win64 2017-10-05 15:32:31 +02:00
Michael Davidsaver
cd4feb3bab install CONFIG_PVD 2017-10-05 14:02:05 +02:00
Michael Davidsaver
6b0af421dd another attempt to appease msvc win64 2017-10-05 11:24:23 +02:00
Michael Davidsaver
9aeb4f2a96 attempt to fix win64 linking error 2017-10-05 10:39:47 +02:00
Michael Davidsaver
9b1e789e62 PVUnion: get() const propagation, add guess(), and inline trival 2017-09-30 13:43:50 -05:00
Michael Davidsaver
406b163bcc factory methods avoid creating unnecessary temporaries
Avoid some ref. counter activity (still have global mutex...)
2017-09-30 11:09:52 -05:00
Michael Davidsaver
6f2cae95e1 PVField: getParent() const propagation and inline trival 2017-09-30 11:00:37 -05:00
Michael Davidsaver
594a29b2db add PVScalar::putFrom/getAs variants for AnyScalar 2017-09-30 10:04:31 -05:00
Michael Davidsaver
0d12464e30 add AnyScalar 2017-09-29 17:22:43 -05:00
Michael Davidsaver
ccd9ab70ee pvUnitTest.h const-ness 2017-09-29 16:12:01 -05:00
Michael Davidsaver
27f2f87e29 reftrack class Field 2017-09-29 15:30:50 -05:00
Michael Davidsaver
635eb9d36d Status: inline trival and add maximize() w/ shorthand operator |= 2017-09-29 13:37:20 -05:00
Ralph Lange
f3e7f9bb8f travis-ci: consolidate travis configuration 2017-09-28 15:10:49 +02:00
Ralph Lange
2f69665056 travis-ci: fix RTEMS/qemu builds 2017-09-22 16:10:21 +02:00
Michael Davidsaver
559f7bc1b7 travis-ci: remove non-functional RTEMS builds 2017-09-21 16:13:18 -05:00
Michael Davidsaver
693f00caf5 Merge remote-tracking branch 'origin/master'
* origin/master:
  ci: changes for EPICS 7 Base structure

# Conflicts:
#	.travis.yml
2017-09-21 15:07:21 -05:00
Michael Davidsaver
822173979c FieldBuilder::add() ignore exact duplicates 2017-09-21 13:41:11 -05:00
Michael Davidsaver
9bce66f307 FieldBuilder edit union/structureArray/unionArray
Allow appending fields to existing types
to allow structure-like types
2017-09-21 13:41:11 -05:00
Michael Davidsaver
7a71e758b1 pvUnitTest.h multi-line prints 2017-09-21 13:41:11 -05:00
Michael Davidsaver
72fe0ca3e7 minor 2017-09-21 13:41:11 -05:00
Michael Davidsaver
fd0570f0c9 travis-ci fix c++11 builds 2017-09-21 13:41:11 -05:00
Ralph Lange
e0037a0c8b ci: changes for EPICS 7 Base structure 2017-09-21 16:14:02 +02:00
Michael Davidsaver
c7c83282ee parseJSON() more forgiving scalar array handling
Allow eg. to initialize array of integers with [1.0, 2.0]
2017-09-07 15:55:21 -05:00
Michael Davidsaver
8f98d9792b add typemap.h
helper for switch() over DBF or PVD scalar type codes
2017-09-07 15:53:40 -05:00
Michael Davidsaver
111f7bd15e parseJSON() track modified fields 2017-09-07 11:53:54 -05:00
Michael Davidsaver
787af8de18 BitSet building convenience
Allow set()/clear()/flip() to be chained.
Support c++11 initializer lists.
2017-09-07 11:49:07 -05:00
Michael Davidsaver
db6ebfe71b parseJSON() assign union with scalar value 2017-09-06 18:34:00 -05:00
Michael Davidsaver
1cb490039f remove another broken no-arg ctors 2017-08-30 17:55:04 -05:00
Michael Davidsaver
a152a64f1c RefSnapshot operator
move into class definition to hopefully appease MSVC
2017-08-30 17:04:02 -05:00
Michael Davidsaver
08f50e56ac win32 doesn't have ssize_t 2017-08-30 14:20:10 -05:00
Michael Davidsaver
9ae221ca0c apply reftrack to PVField 2017-08-30 11:13:10 -05:00
Michael Davidsaver
aca8da5891 remove broken no-arg ctors
Non-useful bypass of factory which leaves
private pointers undefined (eg. parent field).
2017-08-30 11:11:47 -05:00
Michael Davidsaver
34896560ea add reftrack.h
Add global Reference Counter tracker
2017-08-30 11:11:47 -05:00
Michael Davidsaver
3597fbe382 avoid unnecessary temp shared_ptr
avoid some extra ref. counter operations.
2017-08-16 17:49:17 +02:00
Michael Davidsaver
0b262baf97 fix getSubField() by index 2017-08-16 16:29:06 +02:00
Michael Davidsaver
78b51ebe59 c++98 compatible, but still reduced, number of getSubField() specializations 2017-08-16 11:22:42 +02:00
Michael Davidsaver
08a92468fe PVStructure::getSubField() const propagation 2017-08-15 18:35:54 +02:00
Michael Davidsaver
b84ed964f9 reduce # of PVStructure::getSubField overloads 2017-08-15 18:35:54 +02:00
Michael Davidsaver
8bfe7b6b9d debugPtr compat
Fails for newer RTEMS w/ c++11 but no backtrace()
2017-08-15 18:35:54 +02:00
Michael Davidsaver
dbae173399 don't import/export inline classes 2017-07-18 14:32:42 +02:00
Michael Davidsaver
4d4dbcda4d expose const void* form of PVScalar::putFrom() 2017-07-18 14:28:11 +02:00
Michael Davidsaver
fd4584a49d resolve ambiguity 2017-07-18 11:12:44 +02:00
Michael Davidsaver
ceb9f795cb whitespace: quiet gcc6 indentation warning 2017-07-17 16:25:00 +02:00
Michael Davidsaver
443c254d46 no C99 initializers
because MSVC doesn't support this...
2017-07-17 15:58:04 +02:00
Michael Davidsaver
87fa150ced 3.14 compat 2017-07-13 19:14:52 +02:00
Michael Davidsaver
4cfdb8233f more import/export 2017-07-13 18:49:32 +02:00
Michael Davidsaver
5e42cf76eb import/export fix 2017-07-13 18:35:38 +02:00
Michael Davidsaver
dccf6193da more doc 2017-07-13 18:25:25 +02:00
Michael Davidsaver
ee4fdf3f39 json print/parse from/to PVStructure 2017-07-13 18:02:10 +02:00
Michael Davidsaver
918b7f96db valueBuilder: support scalar array fields 2017-07-12 18:33:20 +02:00
Michael Davidsaver
ef55345665 pvUnitTest: compare array fields 2017-07-12 18:26:43 +02:00
Michael Davidsaver
0a41dbb443 ScalarTypeFunc::allocArray missing export 2017-07-12 15:46:01 +02:00
Michael Davidsaver
934ad32e52 debugPtr import/export 2017-07-12 15:29:34 +02:00
Michael Davidsaver
b582f0f880 createRequest clean message before each run 2017-07-12 15:28:09 +02:00
Michael Davidsaver
face3de44a more doc 2017-07-12 14:29:31 +02:00
Michael Davidsaver
8a7b9d776f requester.h moves to pvAccessCPP 2017-07-12 13:13:44 +02:00
Michael Davidsaver
a8c5d1095d remove MessageQueue 2017-07-12 13:07:36 +02:00
Michael Davidsaver
9fa5028f6c PVStructure::getStructure() avoid creation of temporary
avoid some ref-counter activity
2017-07-07 14:39:25 +02:00
Michael Davidsaver
0de3c089d2 testByteBuffer always test both byte orders 2017-07-07 11:21:00 +02:00
Michael Davidsaver
919bc0138a add pvUnitTest.h 2017-07-06 17:05:30 +02:00
Michael Davidsaver
a0210af5c6 remove unnecessary 'typename' 2017-07-06 13:23:24 +02:00
Michael Davidsaver
888291db9a move destroyable.h to pvAccessCPP 2017-07-05 11:59:22 +02:00
Michael Davidsaver
4fce663795 travis-ci 2017-07-04 15:54:29 +02:00
Michael Davidsaver
fc3384fb95 remove raw html in favor of generated
reformat release notes.
2017-07-04 15:33:43 +02:00
Michael Davidsaver
f9a30ca08e update doc 2017-07-04 15:08:01 +02:00
Michael Davidsaver
cbbe691f70 ValueBuilder dllexport 2017-07-04 12:22:04 +02:00
Michael Davidsaver
afbf0809c3 more travis-ci 2017-07-03 18:36:59 +02:00
Michael Davidsaver
db8d4b4347 fix # of tests 2017-07-03 18:35:57 +02:00
Michael Davidsaver
904ee7dfec travis-ci test mingw/win32 dll/static builds 2017-07-03 18:21:10 +02:00
Michael Davidsaver
bef616632c add ValueBuilder 2017-07-03 17:34:38 +02:00
Michael Davidsaver
1d2e5d182e oops 2017-06-26 19:26:59 +02:00
Michael Davidsaver
568ee1fa85 add debugPtr.h to troubleshoot shared_ptr problems
A wrapper around shared_ptr which tracks backwards references
to help untangle complicated ownership situations (aka. ref loop
waiting to happen).
2017-06-26 15:59:45 +02:00
Michael Davidsaver
66633a7728 test cleanup
remove compile time "debug" flag from from tests.
use testDiag() instead
2017-06-26 15:16:43 +02:00
Michael Davidsaver
18283b44b2 more sharedPtr 2017-06-19 14:15:06 +02:00
Michael Davidsaver
278696b28e more sharedPtr compat 2017-06-15 18:23:20 +02:00
Michael Davidsaver
26efd09d45 doxygen 2017-06-14 17:06:38 +02:00
Michael Davidsaver
ec9aba79ae fix warning about missing override w/ c++11 2017-06-14 16:21:51 +02:00
Michael Davidsaver
07e42d81f4 travis-ci 2017-06-14 14:20:44 +02:00
Michael Davidsaver
d272afc128 fixup sharedPtr 2017-06-14 13:59:02 +02:00
Michael Davidsaver
6cf9fa2208 fix "hides overloaded virtual function" warning 2017-06-14 13:22:06 +02:00
Michael Davidsaver
a72451cdbe Add Destroyable::cleaner to help w/ shared_ptr<> wrapping 2017-06-06 18:38:55 +02:00
Michael Davidsaver
e82489b158 Timer: actually join thread 2017-06-02 11:03:46 +02:00
Michael Davidsaver
e4c7fa6a1c move monitor.h to pvAccessCPP 2017-05-24 17:45:41 -04:00
Michael Davidsaver
48ed24dabf remove no-op monitor.cpp 2017-05-24 16:33:16 -04:00
Michael Davidsaver
9ef060a2f2 remove deprecated monitorPlugin.h 2017-05-24 16:31:26 -04:00
Michael Davidsaver
255c41607f remove deprecated monitorPlugin.h 2017-05-24 16:06:00 -04:00
Michael Davidsaver
22da026888 deprecate unused Queue, MessageQueue, Executor, and TimeFunction 2017-05-15 15:12:28 -04:00
Michael Davidsaver
def0a63008 Queue remove nullElement
avoid potential 0=1 situation.
2017-05-15 14:53:54 -04:00
Michael Davidsaver
6e62e123e8 FieldBuilder allow append to Structure
Helpful to allow a new definition to be created
as an extension of an existing definition.
2017-05-15 12:46:32 -04:00
Michael Davidsaver
262df56024 testFieldBuilder: cleanup 2017-05-12 14:26:18 -04:00
Michael Davidsaver
81cdf071a8 FieldBuilder detect duplicate field names 2017-05-12 13:24:37 -04:00
Michael Davidsaver
c5ce75888e Merge remote-tracking branch 'md/overhaulbytebuf'
* md/overhaulbytebuf:
  overhaul byteBuffer implementation
2017-05-10 15:36:49 -04:00
Michael Davidsaver
fb232896a8 avoid unnecessary globals 2017-05-10 15:00:55 -04:00
Michael Davidsaver
5efa462f19 add c++11 override/final 2017-05-10 15:00:55 -04:00
Michael Davidsaver
225f3ab125 Remove hidden sub-class
collapse Base* and Default* classes
into parents.
2017-05-10 15:00:55 -04:00
Michael Davidsaver
664fbfeb6e pvCopy: remove unnecessary globals 2017-05-07 20:17:26 -04:00
Michael Davidsaver
66f8ca0501 simpler createRequest()
A single function which throws exceptions on error
2017-05-07 20:07:01 -04:00
Michael Davidsaver
e977d63f08 add pvdVersion.h 2017-04-15 17:26:18 -04:00
Michael Davidsaver
08fc3cab38 update testPVUnion 2017-04-15 16:19:23 -04:00
Michael Davidsaver
a01885536c PVUnion fixups
select(int32)

throw for variant w/ other than UNDEFINED_INDEX.
Now same behavior for variant and discriminating,
which is to clear contents.
Fix selector range check.

set(int32)

Fix set(UNDEFINED_INDEX, NULL) for discriminating.
Fix selector range check.
2017-04-15 16:19:23 -04:00
Michael Davidsaver
f7343674ee make PVUnion::UNDEFINED_INDEX const 2017-04-15 16:19:23 -04:00
Michael Davidsaver
fc2adf98ba Status: add helpers
so that

epics::pvData::Status(epics::pvData::Status::STATUSTYPE_WARNING, msg)

can become

epics::pvData::Status::warn(msg)
2017-04-15 16:19:23 -04:00
Michael Davidsaver
a3c57a5077 bitSet: add logical_and()/_or()
Basic logical operations for tests
where a temporary can be avoided.
2017-04-15 16:19:15 -04:00
Michael Davidsaver
28b5dd0163 shared_ptr: further simplify static_shared_vector<>() 2017-04-15 16:06:01 -04:00
Michael Davidsaver
c0b69e4e6f add monitor buffer statistics
to help answer the question of why no monitorEvent()s
are happening.
2017-04-15 16:05:26 -04:00
Michael Davidsaver
a9111d78d3 overhaul byteBuffer implementation
align(n) now fills skipped bytes with '\0'.

align(n,f) to choose a different fill value.

No other changes intended

Use intrinsic byte order swapping builtins for gcc, clang, and msvc.

use assert() to check pre/post conditions.

Remove unused condition macros and unreachable code.

Add tests of byte swapping primitives and
test the correctness of unaligned operations.

add illustrations of flip() and rewind()
2017-04-07 15:09:47 -04:00
Dave Hickin
cc91e22038 testThread: Namespace qualify Thread
Fixes build error with latest RTEMS (Thread ambiguous).
2016-09-16 21:22:33 +01:00
Andrew Johnson
4555f69733 #include <algorithm> required for MSVS 2015 2016-09-14 16:23:32 -05:00
Michael Davidsaver
da8ba56dd1 testTypeCast: mangle values to be printable
print  (u)int8 as integer instead of character
2016-09-07 15:29:58 -04:00
Michael Davidsaver
4d6d5620b0 Revert "testTypeCast: Escape non-printing characters"
This reverts commit f7cad98f3e.
2016-09-07 15:28:48 -04:00
Dave Hickin
f7cad98f3e testTypeCast: Escape non-printing characters 2016-09-07 14:40:16 +01:00
Dave Hickin
d978c4c3bf Fix for MinGW
Fixes #42
2016-09-07 10:45:39 +01:00
Dave Hickin
1c4b7810b1 jenkins: Remove COPYRIGHT from tar 2016-07-22 16:07:35 +01:00
Dave Hickin
a6ec43f81c SHRLIB: Set version to 6.1 2016-07-22 16:05:32 +01:00
Dave Hickin
d258acfc49 SHRLIB: Set version to 6.0 2016-07-22 16:02:21 +01:00
Dave Hickin
d9072402db Update source boilerplate for new LICENSE file 2016-07-22 15:56:43 +01:00
Dave Hickin
1a706e3842 Remove COPYRIGHT file
Copyright is now in LICENSE file
2016-07-22 15:33:50 +01:00
Dave Hickin
a227897504 Update LICENSE to new version 2016-07-22 15:33:20 +01:00
Ralph Lange
0833d68e91 jenkins: fix installE4 logic, add pvCommon dependency 2016-07-22 14:59:48 +02:00
Dave Hickin
99bab6796c Fix windows dynamic build error
Fix error introduced by #40. #include epicsThread.h in timer.cpp
before #defining epicsExportSharedSymbols. Avoids multiply-defined
symbols.
2016-07-20 15:33:20 +01:00
dhickin
0544187057 Merge pull request #40 from anjohnson/master
Resolve github #37 without cacheing epicsExportSharedSymbols
2016-07-20 14:39:25 +01:00
Andrew Johnson
e12e7b4d76 Resolve github #37 without cacheing epicsExportSharedSymbols 2016-07-19 18:40:58 -05:00
Ralph Lange
7609ac6f1e jenkins: fix syntax in local declaration 2016-07-19 22:09:03 +02:00
Ralph Lange
3c946a91e8 jenkins: use install functions, add BRANCH variable to doc script 2016-07-19 22:00:34 +02:00
Ralph Lange
2389ebd87e jenkins: fix CloudBees jobs (paths) 2016-07-12 19:39:50 +02:00
Ralph Lange
90ad497a6f Use environment variables; default Base = 3.15.4; new artifact paths 2016-07-12 15:45:30 +02:00
Ralph Lange
1bb0b6fe03 Use environment variables; new default version of Base 2016-07-12 14:53:21 +02:00
dhickin
c16c1df6fd Merge pull request #39 from dhickin/use_template_getSubField
Replace template getSubField with template version
2016-07-05 15:19:58 +01:00
dhickin
e460641711 Merge pull request #38 from dhickin/getSubField_overload
Add char* overload for non-template getSubField
2016-07-05 15:18:46 +01:00
Dave Hickin
1e980651a9 Use template getSubField when type known
Replace non-template getSubField with template version when PVField is
of a known, derived type.
2016-07-04 17:03:07 +01:00
Dave Hickin
028076e79c Add char* overload for non-template getSubField 2016-07-04 14:59:56 +01:00
dhickin
e5b6a88551 Merge pull request #30 from mdavidsaver/requestermsg
Default implementation for Requester::message()
2016-04-12 16:01:45 +01:00
Andrew Johnson
b18b4f236f Make the PVScalarValue explicit specializations inline
Microsoft's compiler seems to prefer this when building a static library.
2016-04-11 17:16:43 -05:00
Andrew Johnson
605d4e99b9 Remove remaining 'undef epicsExportSharedSymbols' stuff 2016-04-11 15:24:46 -05:00
Andrew Johnson
ad00b6465a Fix VxWorks build, add explanatory comments 2016-04-11 11:33:05 -05:00
dhickin
537ebd05f2 Merge pull request #36 from anjohnson/master
Support for additional Windows targets
2016-04-11 10:06:54 +01:00
Andrew Johnson
2ee8769752 Prevent redefinition of NOMINMAX
While this protection is not strictly necessary here, if someone
does a cut-and-paste into a header file it should be included.
2016-04-06 15:29:30 -05:00
Andrew Johnson
8d7f534d54 VxWorks fix in parseToPOD.cpp 2016-03-28 17:11:25 -05:00
Andrew Johnson
47bb62b051 Disable another useless MSVC warning 2016-03-28 16:41:29 -05:00
Andrew Johnson
50b8213781 Fix NEED_OLL_FUNCS for windows-x64 and Base-3.15 2016-03-28 16:41:29 -05:00
Andrew Johnson
fd1fe53b49 Use the EPICS_DEPRECATED macro from Base.
Neither USAGE_DEPRECATED nor USAGE_ERROR are currently used
in the V4 code-base.
2016-03-28 16:41:28 -05:00
Andrew Johnson
378def0a58 Fix logic for when to define strtoll() and strtoull()
Needed for MinGW and VxWorks when built against Base-3.15
2016-03-28 16:41:28 -05:00
Andrew Johnson
ed5f48b353 EPICS sources use vxWorks for arch-detection 2016-03-28 16:41:28 -05:00
Andrew Johnson
fa6c2c7683 EPICS sources use _MINGW for arch-detection 2016-03-28 16:41:28 -05:00
Andrew Johnson
3fadc9b481 Remove unnecessary includes from epicsException.h
Fix up byteBuffer.h and epicsException.cpp to match.
2016-03-28 16:41:28 -05:00
Andrew Johnson
c3d7fa0d26 Declare explicit specializations
Resolves duplicate symbol build error on MinGW.
2016-03-28 16:41:28 -05:00
Andrew Johnson
5c16357fe2 Don't redefine NOMINMAX (clean up MinGW warnings) 2016-03-28 16:41:28 -05:00
Andrew Johnson
ef2e6079ba Wrap WIN32 #pragma warning(disable) inside push/pop
Exclude from MinGW, G++ doesn't understand these pragmas.
2016-03-28 16:41:28 -05:00
Dave Hickin
18633288fb Documentation: Remove maturity and date comment 2016-03-18 21:48:06 +00:00
Dave Hickin
67daef7bcc Documentation: Remove old versions 2016-03-18 21:43:09 +00:00
Dave Hickin
5eb29dcfc4 Documentation: Change to release-based versioning
Replace dated documentation scheme by one using release version.
2016-03-18 21:41:33 +00:00
Michael Davidsaver
d2fc922ee7 remove unnecessary const_cast 2016-03-18 14:53:24 -04:00
Michael Davidsaver
d35010c1cb Status: remove m_emptyStringtring
No reason to have a global for this.
2016-03-18 14:53:10 -04:00
dhickin
bd4b65225c Merge pull request #28 from mdavidsaver/overhaulbitset
bitSet: macros and vector storage
2016-03-17 14:20:20 +00:00
dhickin
be95a62965 Merge pull request #31 from mdavidsaver/deprecatemonitiorplugin
Deprecate monitorPlugin.h
2016-03-15 14:46:53 +00:00
dhickin
4336d524af Merge pull request #33 from msekoranja/master
Minor Win32 compilation fix
2016-03-07 12:02:03 +00:00
Matej Sekoranja
ae7976fc01 Merge remote-tracking branch 'epics-base/master' 2016-03-06 21:33:43 +01:00
Matej Sekoranja
72f9dc4c7c win32 compilation fix 2016-03-06 21:29:04 +01:00
dhickin
84760648fe Merge pull request #29 from mdavidsaver/fixsharedvector 2016-03-02 13:56:06 +00:00
Michael Davidsaver
b0df40d9a6 testSharedVector more PG locals 2016-03-01 13:25:20 -05:00
Michael Davidsaver
139217914d deprecate monitorPlugin.h 2016-02-26 12:17:12 -05:00
Michael Davidsaver
efa5795193 Default implementation for Requester::message()
This is what many sub-classes do (or should)
so lets prepare to remove some boilerplate.
2016-02-26 12:16:28 -05:00
Michael Davidsaver
4f499aed01 remove PVField::notImplemented
An unused waste of space in every instance...
2016-02-26 12:13:23 -05:00
Michael Davidsaver
a8ba831f5e fix freeze() of shared_vector<void> 2016-02-26 12:13:23 -05:00
Michael Davidsaver
a90405c25a shared_vector update doc 2016-02-26 12:13:23 -05:00
Michael Davidsaver
4546fda8e9 note shared_vector casts which should fail 2016-02-26 12:13:23 -05:00
Michael Davidsaver
b02f771146 shared_vector: vtype lost when freeze/thaw untyped
The vtype code is not copied for freeze/thaw
of shared_vector<void> to/from shared_vector<const void>.
2016-02-26 12:13:23 -05:00
Michael Davidsaver
dc94b26e50 fix static_shared_vector_cast<>() no-op casting
Turns out that Enablers as typically used for
member functions don't work to select
constructors.

Move this selection logic to
struct detail::static_shared_vector_caster<>
to correctly allow no-op casts (eg. void to void).
Previously this would not compile.

Allows PVScalarArray getAs() and putFrom() using
shared_vector<const void>.
2016-02-26 12:13:23 -05:00
Michael Davidsaver
4c32f37ede bitSet: macros and vector storage
use std::vector<uint64> to manage storage.
Make some global variable "constants" into macros.
add swap()
2016-02-18 18:39:32 -05:00
Dave Hickin
336a8b3bc2 Fix win32 deserialization test fail 2016-02-18 18:56:04 +00:00
Dave Hickin
faecea39c8 Merge branch 'master' of github.com:msekoranja/pvDataCPP 2016-02-18 15:35:36 +00:00
Michael Davidsaver
d08d5362be testBitSet: forgot to update test count 2016-02-17 10:53:32 -05:00
Michael Davidsaver
d4292d81f2 BitSet: truncation in or_and
For "this |= set1 & set2" the result size
should be "max(this, min(set1, set2))" while
at present it is "min(set1, set2)" resulting
in truncation if the LHS is longer than the
RHS.
2016-02-17 10:17:21 -05:00
Michael Davidsaver
62893e33e9 testBitSet: demo bug in BitSet::or_and
Incorrect handling of wordsInUse truncates if
RHS (b1 & b2) is shorter than LHS (b3).
2016-02-17 10:17:16 -05:00
Michael Davidsaver
5b07ecbd01 testBitSet more diag output 2016-02-17 10:17:04 -05:00
Ralph Lange
b5c1b9178d jenkins: switch to Base 3.15.3 2016-02-16 10:18:41 +01:00
Matej Sekoranja
65ff7ab1c3 fixed bitSet serialization 2016-02-12 19:35:44 +01:00
Dave Hickin
35fd991fdc Improve directSerialize/Deserialize() documentation
Add explanation of returned values and more description of the methods.
2016-02-11 10:51:43 +00:00
Michael Davidsaver
57e1acba79 add missing epicsShareFunc 2016-02-10 11:22:07 -05:00
Michael Davidsaver
620d351946 current_function.h not executable 2016-02-10 14:43:58 +00:00
Michael Davidsaver
de3c2656ef INC += pv/ 2016-02-10 14:40:29 +00:00
Michael Davidsaver
3b2e9b2485 move all headers to pv/ 2016-02-10 14:40:29 +00:00
dhickin
75a3005d74 Merge pull request #17 from mdavidsaver/sertovector
add serializeToVector()
2016-02-10 14:04:01 +00:00
Michael Davidsaver
448f606054 update comments 2016-02-09 19:17:39 -05:00
Michael Davidsaver
e35c6f29fb add deserializeFrom* helpers 2016-02-05 18:34:16 -05:00
Michael Davidsaver
85a1a48b00 add serializeToVector 2016-01-27 11:25:09 -05:00
dhickin
45427d3202 Merge pull request #21 from mdavidsaver/getfieldnull
getSubField -> getSubFieldT to avoid potential NULL de-ref.
2016-01-26 22:14:53 +00:00
Michael Davidsaver
93c7a05dac remove redundant getSubField 2016-01-25 13:15:15 -05:00
Michael Davidsaver
a34c38c9b9 getSubField -> getSubFieldT to avoid potential NULL de-ref. 2016-01-25 12:12:06 -05:00
Michael Davidsaver
3100b77a1a Merge remote-tracking branch 'origin/master'
* origin/master:
  missing buffer capacity check in PVUnion::serialize
  byteBuffer throw invalid_argument when ctor w/ NULL
  revert incorrect doc string
  byteBuffer check for alloc failure and const
  new Thread::Config
2016-01-25 12:05:32 -05:00
Michael Davidsaver
c8429069a3 SONAME in src/Makefile 2016-01-25 11:49:05 -05:00
Michael Davidsaver
01172217dc Merge remote-tracking branch 'md/threadconfig'
* md/threadconfig:
  new Thread::Config
2015-12-29 18:34:18 -05:00
Michael Davidsaver
14b0e409f2 missing buffer capacity check in PVUnion::serialize
Allows a buffer overflow in PVUnionArray::serialize().
2015-12-28 18:16:01 -05:00
Michael Davidsaver
2107bae8dd set SHRLIB_VERSION 2015-12-18 16:07:09 -05:00
Michael Davidsaver
433676226c byteBuffer throw invalid_argument when ctor w/ NULL 2015-12-17 16:45:56 -05:00
Michael Davidsaver
f0c88234a0 revert incorrect doc string 2015-12-15 10:26:31 -05:00
Michael Davidsaver
393d711e5f byteBuffer check for alloc failure and const
Ensure that bad_alloc is thrown if allocations fail, presently unchecked.

Also add const qualifier where possible.
2015-12-14 13:25:42 -05:00
Michael Davidsaver
cb24bd9c2c Merge remote-tracking branch 'md/validatefieldnames'
* md/validatefieldnames:
  fix testCreateRequest
  field names may not begin with a digit
  fail zero length field names
  validate field names
2015-11-30 20:55:16 -05:00
Michael Davidsaver
abc5c5a374 new Thread::Config 2015-11-23 15:21:21 -05:00
Michael Davidsaver
54c94f181a add global namespace so these macros work anywhere 2015-11-23 15:21:21 -05:00
Michael Davidsaver
6641e7f5d1 fix testCreateRequest
field names may not begin with a digit
2015-11-23 14:33:43 -05:00
Michael Davidsaver
f4a00f2b0f field names may not begin with a digit
Enforce C identifer syntax

[A-Za-z_][A-Za-z0-9_]*
2015-11-23 14:31:27 -05:00
Dave Hickin
05d41f81e4 Minor correction to README 2015-10-15 10:37:12 +01:00
Dave Hickin
fdc289d888 Add new README
Replace out of date HTML README with a new markdown one
2015-10-15 09:16:20 +01:00
Dave Hickin
0a2243e033 Update TODO 2015-10-15 07:46:40 +01:00
Dave Hickin
9d877d764f Doxgen fixes and enhancements
Change &param to @param. Add missing parameter.
Add more doxygen comments in SerializeHelper.
2015-10-15 07:12:42 +01:00
Dave Hickin
f5df29cf34 Doxygen: remove @code when code block not wanted
@code produces a separate code block, rather than just displaying
contents as code.

Mostly replaced use with @c tag when block not wanted.
2015-10-15 06:50:26 +01:00
Dave Hickin
8008823ea5 Fix doxygen warnings 2015-10-14 23:01:28 +01:00
Dave Hickin
6515de4bc0 Add release notes for 5.0 2015-10-08 15:24:14 +01:00
Ralph Lange
8c5f535b79 jenkins: fix CloudBees doc job 2015-09-28 15:29:39 +02:00
Michael Davidsaver
3714be4f16 fail zero length field names 2015-09-24 13:04:49 -04:00
Michael Davidsaver
f24f565e58 validate field names
check for invalid characters in field names (eg '.').

Restrict character set to ascii alpha numeric and '_'.
2015-09-23 15:32:46 -04:00
Ralph Lange
036186fc12 jenkins: adapt doc script to new CloudBees jenkins job 2015-09-14 16:48:15 +02:00
Dave Hickin
d3853bd4e9 Ignore target-specific RELEASE and CONFIG_SITE in git
Tell gir to ignore configuration files such as RELEASE.win32-x86.Common
or CONFIG_SITE.linux-x86_64.Common.
2015-09-02 16:36:26 +01:00
Dave Hickin
7253bac48a Updated copyright notice and license
Updated copyright notice using the one in normativeTypesCPP. Added
Diamond and BNL. Added legal discalimers for Diamond and BNL to license.
Added dates to copyright notice. "All rights reserved" added to
copyright.
2015-09-02 14:04:29 +01:00
dhickin
973fbeeba5 Merge pull request #8 from dhickin/move_getSubFieldT_def_from_class_body
Move getSubFieldT definitions out of class body
2015-09-01 17:03:14 +01:00
dhickin
f22cefba97 Merge pull request #11 from anjohnson/fix-mac-build
Fix build problem on Mac
2015-09-01 17:00:58 +01:00
Ralph Lange
a5abc37b17 Add QtCreator pattern to .gitignore 2015-08-18 16:11:33 +02:00
Ralph Lange
b95fa7be56 jenkins: remove hgweb job; split doc and build jobs; update EPICS Base version 2015-08-18 16:11:05 +02:00
Andrew Johnson
f6cf87a52d Fix build problem on Mac
../../testApp/pv/testPVData.cpp:549:14: error: use of overloaded operator '!='
      is ambiguous (with operand types 'PVIntPtr' (aka 'shared_ptr<PVInt>') and
      'long')
    testOk1(a!=NULL);
            ~^ ~~~~
2015-08-12 15:06:46 -05:00
dhickin
51f36b2281 Merge pull request #10 from dhickin/remove_deprecated_getDerivedTypeField
Remove deprecated PVStructure::get*Field Functions
2015-07-29 12:29:08 +01:00
Dave Hickin
ddebd494c6 Remove deprecated PVStructure::get*Field Functions
Remove the deprecated functions such as getIntField in PVStructure,
whose usage has been replaced by that of the template getSubField
function and which are now no longer called anywhere.
2015-07-28 17:45:26 +01:00
dhickin
d0a8d2b1cd Merge pull request #9 from dhickin/replace_calls_getScalarArrayField
Replace calls of deprecated PVStructure::getScalarArrayField
2015-07-28 17:07:50 +01:00
Dave Hickin
1731a0daf6 USAGE_DEPRECATED macro used for getScalarArrayField 2015-07-24 16:56:49 +01:00
Dave Hickin
3487b3ee9e Remove unused argument in testPVScalarArray 2015-07-24 11:22:50 +01:00
Dave Hickin
5834efb709 Remove calls of deprecated getScalarArrayField 2015-07-24 11:21:58 +01:00
Dave Hickin
52bc6d060d Move getSubFieldT definitions out of class body
Move definitions of 2 getSubFieldT overloads:
shared_ptr<PVT> PVStructure::getSubFieldT(const char *name) const
shared_ptr<PVT> PVStructure::getSubFieldT(size_t fieldOffset) const
out of class body so not implicitly inlined.
2015-07-15 11:34:44 +01:00
dhickin
35ca5f3aed Merge pull request #7 from dhickin/getSubFieldT
GetSubFieldT
2015-07-14 16:19:38 +01:00
Dave Hickin
ac2b6ea8db Make getSubFieldT return shared pointer
Signed-off-by: Dave Hickin <david.hickin@diamond.ac.uk>
2015-07-13 12:48:05 +01:00
Dave Hickin
9827caa3e3 Make overloads of getSubField and getSubFieldT match
For each getSubField overload a throwing getSubFieldT has been added and
vice versa. These have been documented in doxygen and in the module
documentation.

Signed-off-by: Dave Hickin <david.hickin@diamond.ac.uk>
2015-07-13 12:41:47 +01:00
Dave Hickin
ebe2d6196c Rename getAs getSubFieldT
Signed-off-by: Dave Hickin <david.hickin@diamond.ac.uk>
2015-07-13 12:34:15 +01:00
Dave Hickin
e4689dd3f8 Added unit tests for functions for getting subfields
Signed-off-by: Dave Hickin <david.hickin@diamond.ac.uk>
2015-07-13 12:07:54 +01:00
Dave Hickin
1dba611b8e Improve exception messages when getting PVStructure subfield
Signed-off-by: Dave Hickin <david.hickin@diamond.ac.uk>
2015-07-13 11:47:21 +01:00
Dave Hickin
97cbea6f4d Implement getSubField functions without using exceptions
Implementation of getSubField (and getScalarArrayField) introduced in
the getAs pull request throws an exception then catches it to return a
null pointer. Implement without throwing.

Signed-off-by: Dave Hickin <david.hickin@diamond.ac.uk>
2015-07-13 02:16:08 +01:00
Dave Hickin
d9963b0631 Add test for getAs when mid-field not structure
Signed-off-by: Dave Hickin <david.hickin@diamond.ac.uk>
2015-07-09 13:22:42 +01:00
Dave Hickin
8418303ce2 Fix bug in new PVStructure::getAs function
Fix seg fault when getAs is called with a string of the form x.y (or
x_1. ... x_n.y) where x or (x1. ... .x_i) is not a structure field.

Signed-off-by: Dave Hickin <david.hickin@diamond.ac.uk>
2015-07-09 13:21:45 +01:00
Dave Hickin
40952df965 Corrected spelling in test and exception messages
Signed-off-by: Dave Hickin <david.hickin@diamond.ac.uk>
2015-07-08 18:19:53 +01:00
Dave Hickin
4f2c51c480 Correct spelling and typos in doxygen and comments
Signed-off-by: Dave Hickin <david.hickin@diamond.ac.uk>
2015-07-08 18:18:37 +01:00
Marty Kraimer
fd31a0d6b0 Merge pull request #6 from mdavidsaver/dropprinter
remove unused PrinterPlain
2015-06-27 07:00:15 -04:00
Michael Davidsaver
9ad725a272 remove unused PrinterPlain 2015-06-25 16:51:04 -04:00
Marty Kraimer
2b6172ba63 Merge pull request #5 from mrkraimer/master
document new PVStructure::getAs method
2015-06-23 10:12:10 -04:00
Marty Kraimer
c521f9299d document new PVStructure::getAs method 2015-06-23 08:24:54 -04:00
Marty Kraimer
1e646f8df1 Merge pull request #4 from mdavidsaver/getasfield
Add PVStructure::getAs<>()
2015-06-23 07:24:30 -04:00
Marty Kraimer
b5a436c1b7 Merge pull request #3 from mdavidsaver/getdeprecate
Deprecated PVStructure::get*Field methods trigger a warning
2015-06-23 07:17:38 -04:00
Michael Davidsaver
4f25c7a3ea remove findSubField 2015-06-22 18:14:23 -04:00
Michael Davidsaver
eadb8ff65b add PVStructure::getAs<>() for field access w/o NULL 2015-06-22 18:14:23 -04:00
Michael Davidsaver
6a80e941a0 replace use of depercated methods 2015-06-22 14:36:27 -04:00
Michael Davidsaver
7fc9b42b3a PVStructure: compiler warning when deprecated methods are used 2015-06-22 14:27:44 -04:00
Dave Hickin
0d857999bf Make default type ID strings const.
Signed-off-by: Dave Hickin <david.hickin@diamond.ac.uk>
2015-06-17 14:51:07 +01:00
Marty Kraimer
8ba71b048e Merge pull request #1 from mdavidsaver/errmsg
Friendlier exception messages w/ stack trace during Field creation
2015-06-15 06:41:34 -04:00
Michael Davidsaver
e07f6c1703 Friendlier exception messages w/ stack trace during Field creation 2015-06-12 13:54:03 -04:00
Marty Kraimer
e4f38121d2 remove qtcreator file 2015-06-10 10:31:08 -04:00
Marty Kraimer
255ee3f151 clean up conversion from hg to got; remove qtcreator files 2015-06-09 08:43:41 -04:00
dhickin
e72dbaabe1 Add some doxygen 2015-06-08 10:06:06 +01:00
dhickin
b39662450f Fix for windows static build static initialisation errors. 2015-06-08 04:58:04 +01:00
dhickin
98da0c0bec Add template getField member functions which return specific field types to Structure and Union. 2015-03-30 09:05:59 +01:00
dhickin
45dde325fd Change the printing of structure array and union array fields of structure introspection objects. Removes superfluous information and brings it in line with pvData meta language. 2015-03-20 17:23:32 +00:00
dhickin
2967a8f798 Declare the one argument constructors of PVField and its derived classes explicit. 2015-03-06 21:05:50 +00:00
Matej Sekoranja
d4bdc73948 documentation/RELEASE_NOTES.md updated 2015-02-18 14:26:19 +01:00
Matej Sekoranja
37c2f6bb17 merge 2015-02-18 10:11:15 +01:00
Matej Sekoranja
a8e4d749e3 flow: Merged <feature> 'copy_refactoring' to <develop> ('default'). 2015-02-18 10:02:17 +01:00
Matej Sekoranja
3df16ee449 flow: Closed <feature> 'copy_refactoring'. 2015-02-18 10:02:17 +01:00
Matej Sekoranja
332c2f959b added copy() method back to convert, since it is usually used by external modules; marked as DEPRECATED 2015-02-17 22:36:28 +01:00
Matej Sekoranja
a1b89c9a3b PVScalar::copy made public; copy tests 2015-02-17 21:54:35 +01:00
Matej Sekoranja
d6921fdac0 removal of some methods from convert 2015-02-17 20:22:37 +01:00
Matej Sekoranja
4cb3c22221 update code to the new method, removed copy from convert 2015-02-17 18:56:56 +01:00
Matej Sekoranja
cc1536b6e1 moved operators to pvData/pvIntrospect, added copy/copyUnchecked methods 2015-02-17 13:59:15 +01:00
Matej Sekoranja
92a178cbf9 flow: Created branch 'feature/copy_refactoring'. 2015-02-17 09:36:44 +01:00
dhickin
fbebce0a49 Make sure postPut is called precisely once and after put in Convert::copyUnion. 2015-02-11 22:17:45 +00:00
Matej Sekoranja
b13bb9819a updated testPlan(0) to actual value 2015-02-11 20:56:38 +01:00
Matej Sekoranja
bb505b8ed9 win32: new operators were missing exports 2015-02-11 15:41:12 +01:00
dhickin
cf030bc711 Call postPut() in Convert::copyUnion(). 2015-02-11 14:04:15 +00:00
Marty Kraimer
6cb95c5cfc fixed possible SEGFAULT in ceateRequest; new stream operator for Field and PVField 2015-02-11 07:26:04 -05:00
Matej Sekoranja
a277a4fdd5 copy schematic 2015-02-11 11:30:39 +01:00
Matej Sekoranja
388799d39d monitors: minor monitor API doc update 2015-02-01 00:46:55 +01:00
Matej Sekoranja
4acf7edf95 non-copy (by reference) retrival of getFields()/getPVFields()/getFieldNames() 2015-01-30 11:35:43 +01:00
Matej Sekoranja
e39346d51e missing swap templates for unsigned types 2015-01-21 20:19:23 +01:00
Ralph Lange
5ae6de4f1d jenkins: fix cloudbees script (commands must return 0) 2014-12-19 14:01:13 +01:00
Ralph Lange
e0f1427af7 jenkins: create and update documentation in only one build configuration 2014-12-19 13:18:52 +01:00
Ralph Lange
69297bdb58 jenkins: make EPICS base a parameter in jenkins job 2014-12-12 09:49:01 +01:00
Marty Kraimer
0fa2f2c2ff merge branch release/4.0 2014-12-11 14:11:54 -05:00
Marty Kraimer
9efce46fff work on doxygen 2014-12-11 09:47:20 -05:00
dhickin
c356ecb402 make local RELEASE.local files take precedence over those in TOP/.. 2014-12-09 13:45:56 +00:00
dhickin
4c6887e7ec Added tag 4.0.3 for changeset 8543734dbf6e 2014-12-05 11:30:03 +00:00
Marty Kraimer
6d338cab15 merge branch release/4.0 2014-12-04 08:30:26 -05:00
dhickin
354fdd412f make "local" *.local files take precedence over those in TOP/.. 2014-12-03 16:55:27 +00:00
dhickin
f3f6141e6a include CONFIG_SITE.local instead of CONFIG.local at top-level. 2014-12-03 16:10:25 +00:00
Matej Sekoranja
f2b43b704c rtems compilation warnings (int32 != int) 2014-11-26 14:12:09 +01:00
Matej Sekoranja
de1478d7ba Event test added 2014-11-25 10:43:07 +01:00
Marty Kraimer
b9592eeb8c Added tag 4.0.2 for changeset af82285f71aa 2014-11-24 06:55:18 -05:00
Marty Kraimer
6a62f9c082 catch std::exception and return NULL PVStructurePtr 2014-11-24 06:54:28 -05:00
Matej Sekoranja
2e4a8b2e23 Structure/Union: bound check access for getFieldName(int)/getField(int) 2014-11-13 18:32:50 +01:00
Marty Kraimer
c5112ffa11 Added tag 4.0.1 for changeset b0d39d12d743 2014-11-11 07:05:19 -05:00
Matej Sekoranja
7b9fda4e81 merge 2014-11-10 21:33:47 +01:00
Matej Sekoranja
278e531806 PVUnion copy allways shallow 2014-11-10 21:30:48 +01:00
Marty Kraimer
047de40642 change date, this version, and previous version 2014-11-10 09:06:35 -05:00
Matej Sekoranja
4e671a1c21 win32 indent problem: local static DLL saga 2014-11-06 22:18:58 +01:00
Matej Sekoranja
f36c8ce280 testByteOrder: use MAIN instead of main 2014-11-06 14:28:49 +01:00
Matej Sekoranja
e77f2c91d7 fixed undeterministic serialization test on clang 2014-11-06 13:03:59 +01:00
Matej Sekoranja
82b0d5ce5f merge 2014-11-06 12:50:04 +01:00
Matej Sekoranja
6117035863 null element handling for structure/union array 2014-11-06 12:48:57 +01:00
Matej Sekoranja
c86e31ad99 vxWorks: type cast fixes 2014-11-06 12:38:01 +01:00
Matej Sekoranja
f506fe1c0e int/int32 compilation fix; now all test spass on RTEMS-i386 2014-11-05 14:05:28 +01:00
Matej Sekoranja
554dc06eda ScalarTypeID mapping fixed in case 'int' == 'long', e.g. RTEMS-i386 2014-11-05 13:52:10 +01:00
Matej Sekoranja
80e1dfd142 removed forces NE2K card or non i386 builds 2014-11-03 13:51:21 +01:00
Matej Sekoranja
6db5cf60dc removing file should not have been commited 2014-11-03 12:41:09 +01:00
Matej Sekoranja
63d181a0ac RTEMS QEMU tests 2014-11-03 12:37:12 +01:00
Matej Sekoranja
73c4896cce tests: VxWorks tests are now ready to be run 2014-10-31 17:49:10 -04:00
Matej Sekoranja
5b1b5ab904 tests: refactored test building so that one test object can be created for VxWorks and RTEMS 2014-10-31 18:29:55 +01:00
Matej Sekoranja
80a537bc4c vxWork tests for all subtests; still need to combine them all to one 2014-10-31 07:57:20 -04:00
Matej Sekoranja
2a8a1d3736 tests: PROD_HOST to TESTPROD_HOST; VxWorks tests for testApp/pv PASSES 2014-10-31 06:42:52 -04:00
Matej Sekoranja
61fbfa0684 Added tag 4.0.0 for changeset f9f187685032 2014-10-29 12:59:39 +01:00
Matej Sekoranja
f06a6bfe7b merge to default branch 2014-10-28 19:37:34 +01:00
Matej Sekoranja
587f81f511 win32 in vs2013 compilation fix 2014-10-28 19:36:57 +01:00
Matej Sekoranja
435ca63d1b ev4 to epics URI 2014-10-28 18:53:11 +01:00
Marty Kraimer
64bb660f44 Added tag 4.0.0 for changeset 9c62aaa83b9d 2014-10-15 14:47:48 -04:00
Marty Kraimer
8bf24de0b3 removed pvArray.html and pvDataDiscussion.html; good ideas now implemented 2014-10-08 15:03:52 -04:00
Marty Kraimer
943ea633a4 more work on pvDataCPP.html; minor changes to examples 2014-10-08 14:48:30 -04:00
dhickin
b1d5f7d7e5 Corrected NTUnio to NTUnion 2014-10-07 15:32:26 +01:00
dhickin
188b94ce19 Corrected spelling of synchrotron in licence. 2014-10-04 02:45:53 +01:00
dhickin
515282abfe Spelling and typos. 2014-10-04 01:33:59 +01:00
dhickin
efbdb722e7 Made sub-field/subfield consistent by changing to subfield. 2014-10-04 01:28:19 +01:00
dhickin
e980823294 Corrected NTUnio->NTUnion. 2014-10-04 00:22:46 +01:00
dhickin
3692f4fb3c Correctly produce <> for templates in code samples for PVUnionArray in pvDataCPP.html. 2014-10-03 15:58:55 +01:00
dhickin
3e645f3c79 Corrected spelling in pvDataCPP.html. 2014-10-03 15:24:20 +01:00
Marty Kraimer
6127763302 Added tag 4.0.0 for changeset 1348c22b1258 2014-09-30 16:59:37 -04:00
Marty Kraimer
19a181b38f change ev4:nt: to 3v4:nt/ 2014-09-30 15:26:23 -04:00
Marty Kraimer
2818b0384c flow: Created branch 'release/4.0'. 2014-09-30 15:06:43 -04:00
Marty Kraimer
36faf8c2ea change URI naming 2014-09-30 15:05:18 -04:00
Marty Kraimer
a208171250 change uri:ev4:nt/2012 to uri:ev4:nt/2014 2014-09-23 14:34:21 -04:00
Marty Kraimer
b8a2b7cff6 get documantation ready for pre release 2014-09-03 09:01:15 -04:00
Marty Kraimer
2a08cbc1a0 add static 2014-08-25 08:09:28 -04:00
Matej Sekoranja
62bc6c1fb1 PVControl::minStep implemented 2014-08-22 22:22:38 +02:00
Matej Sekoranja
1098650421 clang fix 2014-08-20 21:42:29 +02:00
Marty Kraimer
15d85c2f87 fix misspelled field names: nanoSecond => nanosecond; hystersis=>hysteresis 2014-08-20 06:27:24 -04:00
Matej Sekoranja
16fb3f0339 clang fixes 2014-08-19 20:58:12 +02:00
Matej Sekoranja
37f6dff065 bounded string 2014-08-19 20:42:15 +02:00
Marty Kraimer
baf8832fc9 allow record[] field() getField() putField() 2014-08-19 09:15:06 -04:00
Marty Kraimer
b558e11ede major changes to CreateRequest; now compatible with Java version 2014-08-19 08:25:38 -04:00
Matej Sekoranja
103cdabff1 fixed clang std::tr1 import by adding include 2014-08-13 21:53:15 +02:00
Matej Sekoranja
57e33c8f7d clang porting 2014-08-13 09:36:37 +02:00
Matej Sekoranja
da0f65c2d3 fixed size array serialization test 2014-08-12 13:20:00 +02:00
Matej Sekoranja
6535c075f3 fixed sized arrays 2014-08-12 13:17:17 +02:00
Matej Sekoranja
f3c0b9544c dumpValue for boolean fix 2014-08-11 22:09:46 +02:00
Matej Sekoranja
3609fd4745 fixed testCreateRequest, still fails 2014-07-30 21:49:52 +02:00
Matej Sekoranja
622e140622 Fixed/bounded scalar array impl. 2014-07-30 21:41:08 +02:00
Marty Kraimer
a4954c3825 fixed bug in createRequest.cpp 2014-07-30 06:50:22 -04:00
Matej Sekoranja
b6e1b9c203 reuse existing PVField instance on PVUnion::deserialize 2014-07-28 23:23:01 +02:00
Matej Sekoranja
34a35c2658 fixed/bounded array introspection data serialization 2014-07-28 23:05:49 +02:00
Marty Kraimer
90b7c9a17c change in TODO.md; add RELEASE_NOTES.html and TODO.html 2014-07-22 08:49:02 -04:00
Marty Kraimer
c72297020b update documentation 2014-07-10 13:17:26 -04:00
Matej Sekoranja
f07b601dce merge 2014-07-07 20:55:49 +02:00
Matej Sekoranja
63c62a2aae Union::dump indentification fixed 2014-07-07 20:54:38 +02:00
Matej Sekoranja
6888a9d340 Added tag 3.1.0 for changeset 260f35b9c6ca 2014-07-02 00:09:01 +02:00
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
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
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
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
225 changed files with 20492 additions and 34818 deletions

21
.ci/travis-build.sh Executable file
View File

@@ -0,0 +1,21 @@
#!/bin/sh
set -e -x
# set RTEMS to eg. "4.9" or "4.10"
# requires qemu, bison, flex, texinfo, install-info
if [ -n "$RTEMS" ]
then
# find local qemu-system-i386
export PATH="$HOME/.cache/qemu/usr/bin:$PATH"
echo -n "Using QEMU: "
type qemu-system-i386 || echo "Missing qemu"
EXTRA=RTEMS_QEMU_FIXUPS=YES
fi
make -j2 $EXTRA
if [ "$TEST" != "NO" ]
then
make tapfiles
make -s test-results
fi

138
.ci/travis-prepare.sh Executable file
View File

@@ -0,0 +1,138 @@
#!/bin/sh
set -e -x
CURDIR="$PWD"
QDIR="$HOME/.cache/qemu"
if [ -n "$RTEMS" -a "$TEST" = "YES" ]
then
git clone --quiet --branch vme --depth 10 https://github.com/mdavidsaver/qemu.git "$HOME/.build/qemu"
cd "$HOME/.build/qemu"
HEAD=`git log -n1 --pretty=format:%H`
echo "HEAD revision $HEAD"
[ -e "$HOME/.cache/qemu/built" ] && BUILT=`cat "$HOME/.cache/qemu/built"`
echo "Cached revision $BUILT"
if [ "$HEAD" != "$BUILT" ]
then
echo "Building QEMU"
git submodule --quiet update --init
install -d "$HOME/.build/qemu/build"
cd "$HOME/.build/qemu/build"
"$HOME/.build/qemu/configure" --prefix="$HOME/.cache/qemu/usr" --target-list=i386-softmmu --disable-werror
make -j2
make install
echo "$HEAD" > "$HOME/.cache/qemu/built"
fi
fi
cd "$CURDIR"
cat << EOF > configure/RELEASE.local
EPICS_BASE=$HOME/.source/epics-base
EOF
install -d "$HOME/.source"
cd "$HOME/.source"
add_base_module() {
MODULE=$1
BRANCH=$2
( cd epics-base/modules && \
git clone --quiet --depth 5 --branch "$MODULE"/"$BRANCH" https://github.com/${REPOBASE:-epics-base}/epics-base.git "$MODULE" && \
cd "$MODULE" && git log -n1 )
}
if [ "$BRBASE" ]
then
git clone --quiet --depth 5 --branch "$BRBASE" https://github.com/${REPOBASE:-epics-base}/epics-base.git epics-base
(cd epics-base && git log -n1 )
else
git clone --quiet --depth 5 --branch core/"${BRCORE:-master}" https://github.com/${REPOBASE:-epics-base}/epics-base.git epics-base
( cd epics-base && git log -n1 )
add_base_module libcom "${BRLIBCOM:-master}"
fi
EPICS_HOST_ARCH=`sh epics-base/startup/EpicsHostArch`
# requires wine and g++-mingw-w64-i686
if [ "$WINE" = "32" ]
then
echo "Cross mingw32"
sed -i -e '/CMPLR_PREFIX/d' epics-base/configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw
cat << EOF >> epics-base/configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw
CMPLR_PREFIX=i686-w64-mingw32-
EOF
cat << EOF >> epics-base/configure/CONFIG_SITE
CROSS_COMPILER_TARGET_ARCHS+=win32-x86-mingw
EOF
fi
if [ "$STATIC" = "YES" ]
then
echo "Build static libraries/executables"
cat << EOF >> epics-base/configure/CONFIG_SITE
SHARED_LIBRARIES=NO
STATIC_BUILD=YES
EOF
fi
case "$CMPLR" in
clang)
echo "Host compiler is clang"
cat << EOF >> epics-base/configure/os/CONFIG_SITE.Common.$EPICS_HOST_ARCH
GNU = NO
CMPLR_CLASS = clang
CC = clang
CCC = clang++
EOF
# hack
sed -i -e 's/CMPLR_CLASS = gcc/CMPLR_CLASS = clang/' epics-base/configure/CONFIG.gnuCommon
clang --version
;;
*)
echo "Host compiler is default"
gcc --version
;;
esac
cat <<EOF >> epics-base/configure/CONFIG_SITE
USR_CPPFLAGS += $USR_CPPFLAGS
USR_CFLAGS += $USR_CFLAGS
USR_CXXFLAGS += $USR_CXXFLAGS
EOF
# set RTEMS to eg. "4.9" or "4.10"
# requires qemu, bison, flex, texinfo, install-info
if [ -n "$RTEMS" ]
then
echo "Cross RTEMS${RTEMS} for pc386"
install -d /home/travis/.cache
curl -L "https://github.com/mdavidsaver/rsb/releases/download/travis-20160306-2/rtems${RTEMS}-i386-trusty-20190306-2.tar.gz" \
| tar -C /home/travis/.cache -xj
sed -i -e '/^RTEMS_VERSION/d' -e '/^RTEMS_BASE/d' epics-base/configure/os/CONFIG_SITE.Common.RTEMS
cat << EOF >> epics-base/configure/os/CONFIG_SITE.Common.RTEMS
RTEMS_VERSION=$RTEMS
RTEMS_BASE=/home/travis/.cache/rtems${RTEMS}-i386
EOF
cat << EOF >> epics-base/configure/CONFIG_SITE
CROSS_COMPILER_TARGET_ARCHS+=RTEMS-pc386
EOF
# find local qemu-system-i386
export PATH="$HOME/.cache/qemu/usr/bin:$PATH"
echo -n "Using QEMU: "
type qemu-system-i386 || echo "Missing qemu"
EXTRA=RTEMS_QEMU_FIXUPS=YES
fi
make -j2 -C epics-base $EXTRA

17
.gitignore vendored Normal file
View File

@@ -0,0 +1,17 @@
/cfg/
/bin/
/lib/
/db/
/dbd/
/html/
/include/
/templates/
/configure/*.local
/configure/RELEASE.*
/configure/CONFIG_SITE.*
O.*/
/QtC-*
envPaths
*.orig
*.log
.*.swp

View File

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

View File

@@ -1,11 +0,0 @@
^QtC-
^bin/
^lib/
^doc/
^include/
^db/
^dbd/
^documentation/html
envPaths
configure/.*\.local
/O\..*

11
.hgtags
View File

@@ -1,11 +0,0 @@
459f10877e5628241704f31437b4cbd342df0798 test1
6e8a22d01e824702088195c08bf50bfb6f293de5 1.0-BETA
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

29
.travis.yml Normal file
View File

@@ -0,0 +1,29 @@
sudo: false
dist: trusty
language: c++
compiler:
- gcc
addons:
apt:
packages:
- libreadline6-dev
- libncurses5-dev
- perl
- clang
- g++-mingw-w64-i686
install:
- ./.ci/travis-prepare.sh
script:
- ./.ci/travis-build.sh
env:
- BRCORE=master BRLIBCOM=master
- CMPLR=clang
- USR_CXXFLAGS=-std=c++11
- CMPLR=clang USR_CXXFLAGS=-std=c++11
- WINE=32 TEST=NO STATIC=YES
- WINE=32 TEST=NO STATIC=NO
- RTEMS=4.10 TEST=NO
- RTEMS=4.9 TEST=NO
- BRBASE=3.16
- BRBASE=3.15
- BRBASE=3.14

View File

@@ -1,12 +0,0 @@
/****************************************************
Copyright (c) 2008 All rights reserved
Copyright (c) 2008 Martin R. Kraimer
Copyright (c) 2006 The University of Chicago, as Operator of Argonne
National Laboratory.
Deutsches Elektronen-Synchroton, Member of the Helmholtz Association,
(DESY), HAMBURG, GERMANY,
BERLINER SPEICHERRING GESELLSCHAFT FUER SYNCHROTRONSTRAHLUNG M.B.H.
(BESSY), BERLIN, GERMANY.
COSYLAB (Control System Laboratory)
(Cosylab) Ljubljana Slovenia
*************************************************** */

2343
Doxyfile

File diff suppressed because it is too large Load Diff

77
LICENSE
View File

@@ -1,12 +1,17 @@
Copyright and License Terms
---------------------------
Copyright (c) 2008 Martin R. Kraimer
Copyright (c) 2006 The University of Chicago, as Operator of Argonne
Copyright (c) 2006-2016 Martin R. Kraimer
Copyright (c) 2006-2016 UChicago Argonne LLC, as Operator of Argonne
National Laboratory.
Copyright (c) 2006 Deutsches Elektronen-Synchroton,
Copyright (c) 2006 Deutsches Elektronen-Synchrotron,
Member of the Helmholtz Association, (DESY), HAMBURG, GERMANY.
Copyright (c) 2007 Control System Laboratory,
Copyright (c) 2007-2016 Control System Laboratory,
(COSYLAB) Ljubljana Slovenia
Copyright (c) 2010-2016 Brookhaven Science Associates, as Operator
of Brookhaven National Laboratory
Copyright (c) 2011-2016 Diamond Light Source Limited,
(DLS) Didcot, United Kingdom
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
@@ -31,48 +36,30 @@ OTHER DEALINGS IN THE SOFTWARE.
________________________________________________________________________
This software is in part copyrighted by the University of Chicago (UofC)
Additional Disclaimers
----------------------
In no event shall UofC be liable to any party for direct, indirect,
special, incidental, or consequential damages arising out of the use of
this software, its documentation, or any derivatives thereof, even if
UofC has been advised of the possibility of such damage.
This software is copyright in part by these institutions:
UofC specifically disclaims any warranties, including, but not limited
to, the implied warranties of merchantability, fitness for a particular
purpose, and non-infringement. This software is provided on an "as is"
basis, and UofC has no obligation to provide maintenance, support,
updates, enhancements, or modifications.
* Brookhaven Science Associates, as Operator of Brookhaven
National Laboratory, New York, USA
* Control System Laboratory, Ljubljana, Slovenia
* Deutsches Elektronen-Synchroton, Member of the Helmholtz
Association, Hamburg, Germany
* Diamond Light Source Limited, Didcot, United Kingdom
* Helmholtz-Zentrum Berlin fuer Materialien und Energie m.b.H.,
Berlin, Germany.
* UChicage Argonne LLC, as Operator of Argonne National Laboratory,
Illinois, USA
________________________________________________________________________
In no event shall these institutions be liable to any party for direct,
indirect, special, incidental, or consequential damages arising out of
the use of this software, its documentation, or any derivatives thereof,
even if advised of the possibility of such damage.
This software is in part copyrighted by the BERLINER SPEICHERRING
GESELLSCHAFT FUER SYNCHROTRONSTRAHLUNG M.B.H. (BESSY), BERLIN, GERMANY.
These institutions specifically disclaim any warranties, including, but
not limited to, the implied warranties of merchantability, fitness for a
particular purpose, and non-infringement. This software is provided on
an "as is" basis, and these institutions have no obligation to provide
maintenance, support, updates, enhancements, or modifications.
In no event shall BESSY be liable to any party for direct, indirect,
special, incidental, or consequential damages arising out of the use of
this software, its documentation, or any derivatives thereof, even if
BESSY has been advised of the possibility of such damage.
BESSY specifically disclaims any warranties, including, but not limited
to, the implied warranties of merchantability, fitness for a particular
purpose, and non-infringement. This software is provided on an "as is"
basis, and BESSY has no obligation to provide maintenance, support,
updates, enhancements, or modifications.
________________________________________________________________________
This software is in part copyrighted by the Deutsches Elektronen-Synchroton,
Member of the Helmholtz Association, (DESY), HAMBURG, GERMANY.
In no event shall DESY be liable to any party for direct, indirect,
special, incidental, or consequential damages arising out of the use of
this software, its documentation, or any derivatives thereof, even if
DESY has been advised of the possibility of such damage.
DESY specifically disclaims any warranties, including, but not limited
to, the implied warranties of merchantability, fitness for a particular
purpose, and non-infringement. This software is provided on an "as is"
basis, and DESY has no obligation to provide maintenance, support,
updates, enhancements, or modifications.
________________________________________________________________________

View File

@@ -11,4 +11,7 @@ src_DEPEND_DIRS = configure
DIRS += testApp
testApp_DEPEND_DIRS = src
DIRS += examples
examples_DEPEND_DIRS = src
include $(TOP)/configure/RULES_TOP

View File

@@ -1,82 +0,0 @@
<?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 pvData C++</title>
</head>
<body>
<h1 style="text-align: center">EPICS pvData C++<br />
Overview<br />
2010.08.10</h1>
CONTENTS
<hr />
<h2 style="text-align: center">Introduction</h2>
<hr />
<p>This project has the begining of the C++ implementation of pvData. The
following is done:</p>
<dl>
<dt>introspection interfaces</dt>
<dd>The introspection interfaces for clients are described.</dd>
<dt>introspection implementation</dt>
<dd>The following have been implemented: Type, ScalarType, Field,
Scalar</dd>
<dt>test</dt>
<dd>A test of Scalar.</dd>
<dt>As mentioned below there are problems with the current
implementation.</dt>
</dl>
<hr />
<h2 style="text-align: center">Building</h2>
<hr />
<p>The project is structured as an epics base client application. Edit
configure/RELEASE so that it references your EPICS base and then just
type:</p>
<pre> make</pre>
<p>At the top. Then execute the test in the bin directory.</p>
<p>pvDataApp has the following sub directories:</p>
<dl>
<dt>pv</dt>
<dd>pvData.h has the interface descriptions for client code.</dd>
<dt>factory</dt>
<dd>FieldCreateFactory.cpp has the current implementation</dd>
<dt>test</dt>
<dd>Has a test for the current implementation.</dd>
</dl>
<hr />
<h2 style="text-align: center">Questions about Classes</h2>
<hr />
<p>The pure virtual classes defined in pvData.h now work. But there are still
some things that are not so nice. Amoung these are:</p>
<ul>
<li>In FieldCreateFactory.cpp look for "WHY DO I". It asks why the derived
class must also define methods defined in the base class. If it does not
then a compilation error occurs. WHY??? </li>
<li>The toString methods have an argument of "std::string &amp;buf" instead
of "std::string *". Does this seem correct?</li>
<li>Can arguments and return descriptions be defined better?</li>
<li>Is const present everywhere it should be? Remember that introspection
classes are immutable.</li>
<li>The code is NOT thread safe. When we decide for sure what thread/lock
support to choose I will fix this.</li>
</ul>
<p>HELP WILL BE GREATLY APPRECIATED. because I am still coming up to speed
with c++</p>
<hr />
<h2 style="text-align: center">Garbage Collection</h2>
<hr />
<p>Not yet implemented. Lets get class structure correct first.</p>
</body>
</html>

57
README.md Normal file
View File

@@ -0,0 +1,57 @@
pvaDataCPP
==========
pvDataCPP is a set of data types and utilities that form part of the EPICS V4 project.
Further Info
------------
Consult the documents in the documentation directory, in particular
* pvDataCPP.html
* RELEASE_NOTES.md
Also see the [EPICS Version 4 website](http://epics-pvdata.sourceforge.net)
Prerequisites
-------------
The pvDataCPP requires recent versions of the following software:
1. EPICS Base (v3.14.12.3 or later)
2. EPICS4 pvCommonCPP (4.1.0 or later)
(pvCommonCPP may not be needed depending on host/compiler.)
Building
--------
Building uses the make utility and the EPICS base build system.
The build system needs the location of the prerequisites, e.g. by placing the
lines of the form
PVCOMMON = /home/install/epicsV4/pvCommonCPP
EPICS_BASE = /home/install/epics/base
pointing to the locations in a file called RELEASE.local
in the configure directory or the parent directory of pvDataCPP.
With this in place, to build type make
make
To perform a clean build type
make clean uninstall
To run the unit tests type
make runtests
For more information on the EPICS build system consult the
[Application Development guide](http://www.aps.anl.gov/epics/base/R3-14/12-docs/AppDevGuide.pdf).

View File

@@ -0,0 +1,4 @@
EPICS_PVD_MAJOR_VERSION = 7
EPICS_PVD_MINOR_VERSION = 0
EPICS_PVD_MAINTENANCE_VERSION = 0
EPICS_PVD_DEVELOPMENT_FLAG = 0

View File

@@ -20,8 +20,8 @@ CHECK_RELEASE = YES
# INSTALL_LOCATION here.
#INSTALL_LOCATION=</path/name/to/install/top>
-include $(TOP)/../CONFIG_SITE.local
-include $(TOP)/configure/CONFIG_SITE.local
-include $(TOP)/../CONFIG.local
ifdef WITH_COVERAGE
USR_CPPFLAGS += --coverage

View File

@@ -2,6 +2,8 @@ TOP=..
include $(TOP)/configure/CONFIG
CFG += CONFIG_PVDATA_VERSION
TARGETS = $(CONFIG_TARGETS)
CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS)))

View File

@@ -1,25 +1,39 @@
# pvDataCPP RELEASE - Location of external support modules
# RELEASE - Location of external support modules
#
# IF YOU CHANGE this file or any file it includes you must
# subsequently do a "gnumake rebuild" in the application's
# top level directory.
# IF YOU CHANGE ANY PATHS in this file or make API changes to
# any modules it refers to, you should do a "make rebuild" in
# this application's top level directory.
#
# 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.
# The EPICS build process does not check dependencies against
# any files from outside the application, so it is safest to
# rebuild it completely if any modules it depends on change.
#
# 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)
# 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
# This file is parsed by both GNUmake and an EPICS Perl script,
# so it may ONLY contain definititions of paths to other support
# modules, variable definitions that are used in module paths,
# and include statements that pull in other RELEASE files.
# Variables may be used before their values have been set.
# Build variables that are NOT used in paths should be set in
# the CONFIG_SITE file.
-include $(TOP)/configure/RELEASE.local
# Variables and paths to dependent modules:
#MODULES = /path/to/modules
#MYMODULE = $(MODULES)/my-module
# If building the EPICS modules individually, set these:
#EPICS_LIBCOM = $(MODULES)/libcom-3.17.0
#EPICS_BASE = $(MODULES)/core-7.0.1
# Set RULES here if you want to use build rules from elsewhere:
#RULES = $(MODULES)/build-rules
# These allow developers to override the RELEASE variable settings
# without having to modify the configure/RELEASE file itself.
-include $(TOP)/../RELEASE.local
-include $(TOP)/../RELEASE.$(EPICS_HOST_ARCH).local
-include $(TOP)/configure/RELEASE.local

3
documentation/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
*.tag
*.db
html/

File diff suppressed because it is too large Load Diff

13
documentation/Makefile Normal file
View File

@@ -0,0 +1,13 @@
all: gen
clean:
rm -rf doxygen_sqlite3.db html
gen:
doxygen
commit: gen
touch html/.nojekyll
./commit-gh.sh documentation/html/ html/.nojekyll html/*.* html/search/*.*
.PHONY: all clean gen commit

14
documentation/TODO.md Normal file
View File

@@ -0,0 +1,14 @@
TODO
===========
doxygen
-------
There is a lot of public code that does not have doxygen tags.
valueAlarm
---------
normativeTypes.html describes valueAlarm only for a value field that has type
double.
The implementation also supports all the numeric scalar types.

45
documentation/commit-gh.sh Executable file
View File

@@ -0,0 +1,45 @@
#!/bin/sh
set -e -x
# Usage: commit-gh <sub-directory-prefix> <files...>
#
# Creates a commit containing only the files in the sub-directory provided as an argument
#
# Does not disturb the working copy or index
prefix="$1"
shift
# Commit to this branch
BRANCH=refs/heads/gh-pages
# Use the main branch description as the gh-pages commit message
MSG=`git describe --tags --always`
# Scratch space
TDIR=`mktemp -d -p $PWD`
# Automatic cleanup of scratch space
trap 'rm -rf $TDIR' INT TERM QUIT EXIT
export GIT_INDEX_FILE="$TDIR/index"
# Add listed files to a new (empty) index
git update-index --add "$@"
# Write the index into the repo, get tree hash
TREE=`git write-tree --prefix="$prefix"`
echo "TREE $TREE"
git cat-file -p $TREE
# Create a commit with our new tree
# Reference current branch head as parent (if any)
CMT=`git commit-tree -m "$MSG" $TREE`
echo "COMMIT $CMT"
git cat-file -p $CMT
# Update the branch with the new commit tree hash
git update-ref $BRANCH $CMT
echo "Done"

BIN
documentation/examples.zip Normal file

Binary file not shown.

58
documentation/mainpage.h Normal file
View File

@@ -0,0 +1,58 @@
#ifndef MAINPAGE_H
#define MAINPAGE_H
/**
@mainpage pvDataCPP documentation
- [Download](https://sourceforge.net/projects/epics-pvdata/files/)
- @htmlonly <a href="modules.html">API components</a> @endhtmlonly
- @ref release_notes
The epics::pvData namespace.
See pv/pvData.h header.
@code
#include <pv/pvData.h>
#include <pv/createRequest.h>
@endcode
- Type description epics::pvData::Field and sub-classes
- Value container epics::pvData::PVField and sub-classes
- POD array handling epics::pvData::shared_vector
- pvRequest parsing epics::pvData::createRequest()
Define a structure type and create a container with default values.
@code
epics::pvData::StructureConstPtr stype; // aka std::tr1::shared_ptr<const epics::pvData::Structure>
stype = epics::pvData::getFieldCreate()->createFieldBuilder()
->add("fld1", epics::pvData::pvInt)
->addNestedStructure("sub")
->add("fld2", epics::pvData::pvString)
->endNested()
->createStructure();
epics::pvData::PVStructuretPtr value; // aka std::tr1::shared_ptr<epics::pvData::PVStructure>
value = epics::pvData::getPVDataCreate()->createPVStructure(stype);
value->getSubField<epics::pvData::PVInt>("fld1")->put(4); // store integer 4
value->getSubField<epics::pvData::PVScalar>("sub.fld2")->putFrom(4.2); // convert and store string "4.2"
@endcode
is equivalent to the following pseudo-code.
@code
struct stype {
epics::pvData::int32 fld1;
struct {
std::string fld2;
} sub;
};
stype value;
value.fld1 = 4;
value.fld2 = epics::pvData::castUnsafe<std::string>(4.2);
@endcode
*/
#endif /* MAINPAGE_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,179 +0,0 @@
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.)
PVStructure::const_shared_pointer enum_t =
getFieldCreate()->createFieldBuilder()->
setId("enum_t")->
add("index", pvInt)->
addArray("choices", pvString)->
createStructure();
// create a structure (cntd.)
PVStructure::const_shared_pointer 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);

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,792 +0,0 @@
<?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(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 {
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">String toString();</font>
}
<font color = "blue">
// new interface
interface FieldToString {
String toString(Field field);
}</font>
interface Scalar extends Field {
ScalarType getScalarType();
}
interface ScalarArray extends Field {
ScalarType getElementType();
}
interface Structure extends Field {
Field getField(String fieldName);
int getFieldIndex(String fieldName);
Field[] getFields();
Field getField(int fieldIndex);
String[] getFieldNames();
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(String[] fieldNames, Field[] field);
Structure createStructure(String id,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,String fieldName, Field field);</font>
<font color = "red">Structure appendFields(Structure structure,String[] fieldNames, Field[] fields);</font>
}
</pre>
<h3>Data Interfaces</h3>
<pre>
interface PVField extends Requester, Serializable {
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(String newName);</font>
<font color = "red">void toString(StringBuilder buf);</font>
<font color = "red">void toString(StringBuilder buf,int indentLevel);</font>
<font color = "red">String toString();</font>
}
<font color = "blue">
// The following is a new interface
interface PVFieldToString {
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(String fieldName);
PVField getSubField(int fieldOffset);
// The following are convenience methods
PVBoolean getBooleanField(String fieldName);
PVByte getByteField(String fieldName);
PVShort getShortField(String fieldName);
PVInt getIntField(String fieldName);
PVLong getLongField(String fieldName);
PVFloat getFloatField(String fieldName);
PVDouble getDoubleField(String fieldName);
PVString getStringField(String fieldName);
PVScalarArray getScalarArrayField(String fieldName);
PVStructureArray getStructureArrayField(String fieldName);
PVStructure getStructureField(String fieldName);
PVArray getArrayField(String fieldName,ScalarType elementType);
// following will be removed
<font color = "red"> void appendPVField(String fieldName,PVField pvField);</font>
<font color = "red"> void appendPVFields(String[] fieldNames,PVField[] pvFields);</font>
<font color = "red"> void removePVField(String fieldName);</font>
<font color = "red"> void replacePVField(PVField oldPVField,PVField newPVField);</font>
<font color = "red"> String getExtendsStructureName();</font>
<font color = "red"> boolean putExtendsStructureName(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(String[] fieldNames,Field[] fields);
PVStructure createPVStructure(PVStructure structToClone);
// following will be removed
<font color = "red">PVField[] flattenPVStructure(PVStructure pvStructure);</font>
}
</pre>
<h3>PVFieldToString</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 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 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 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(String const &amp; fieldName) const;
FieldConstPtr getField(std::size_t index) const;
std::size_t getFieldIndex(String const &amp;fieldName) const;
FieldConstPtrArray const &amp; getFields() const {return fields;}
StringArray const &amp; getFieldNames() const;
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,String const &amp;newName);
virtual void toString(StringBuilder buf,int indentLevel) const;
virtual 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 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 (
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,
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 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(String message,MessageType messageType);
void replacePVField(const PVFieldPtr&amp; newPVField);
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(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 PVFieldToString {
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;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;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(String const &amp;fieldName) const;
PVFieldPtr getSubField(std::size_t fieldOffset) const;
PVBooleanPtr getBooleanField(String const &amp;fieldName) ;
PVBytePtr getByteField(String const &amp;fieldName) ;
PVShortPtr getShortField(String const &amp;fieldName) ;
PVIntPtr getIntField(String const &amp;fieldName) ;
PVLongPtr getLongField(String const &amp;fieldName) ;
PVUBytePtr getUByteField(String const &amp;fieldName) ;
PVUShortPtr getUShortField(String const &amp;fieldName) ;
PVUIntPtr getUIntField(String const &amp;fieldName) ;
PVULongPtr getULongField(String const &amp;fieldName) ;
PVFloatPtr getFloatField(String const &amp;fieldName) ;
PVDoublePtr getDoubleField(String const &amp;fieldName) ;
PVStringPtr getStringField(String const &amp;fieldName) ;
PVStructurePtr getStructureField(String const &amp;fieldName) ;
PVScalarArrayPtr getScalarArrayField(
String const &amp;fieldName,ScalarType elementType) ;
PVStructureArrayPtr getStructureArrayField(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(
String const &amp;fieldName,
PVFieldPtr const &amp; pvField);
void appendPVFields(
StringArray const &amp; fieldNames,
PVFieldPtrArray const &amp; pvFields);
void removePVField(String const &amp;fieldName);
virtual void setImmutable();
String getExtendsStructureName() const;
bool putExtendsStructureName(
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>

View File

@@ -0,0 +1,378 @@
/**
@page release_notes Release Notes
Release 7.0 (XYZ 2017)
======================
- Removals
- Remove requester.h, monitor.h, and destroyable.h.. Migrated to the pvAccessCPP module.
- Previously deprecated monitorPlugin.h is removed.
- Remove pv/messageQueue.h and epics::pvData::MessageQueue
- Deprecate the following utility classes, to be removed in 8.0.
- epics::pvData::Queue
- epics::pvData::Executor
- epics::pvData::TimeFunction
- Additions
- Add pv/pvdVersion.h which is included by pv/pvIntrospect.h
- Add epics::pvData::createRequest() function. Alternative to epics::pvData::CreateRequest class which throws on error.
- epics::pvData::FieldBuilder allow Structure defintion to be changed/appended
- Add epics::pvData::ValueBuilder like FieldBuilder also sets initial values.
- Can also be constructed using an existing PVStructure to allow "editing".
- Add debugPtr.h wrapper with reference tracking to assist in troubleshooting shared_ptr related ref. loops.
- Add @ref pvjson utilities
Release 6.0.1
=============
The changes since release 6.0.0 are:
* Fix "Problem building pvDataCPP for win32-x86-mingw" (issue #42)
* In src/misc/bitSet.cpp #include "algorithm" required for MSVS 2015
* In testApp/misc/testTypeCast.cpp print (u)int8 values as integers
* Minor documentation updates
Release 6.0.0 (Aug. 2016)
=======================
The main changes since release 5.0.4 are:
* Linux shared library version added
* Headers have been moved into pv directories
* Bitset functions declared const where possible
* Bitset::swap added
* Requester::message has default implementation
* Serialization/deserialization helpers added
* Non-template getSubField char* overload added
* MonitorPlugin deprecated
* Field name validation performed
* Now builds for Cygwin and MinGW targets
* Fix for debug build issue.
* New license file replaces LICENSE and COPYRIGHT
Shared library version added
----------------------------
Linux shared library version numbers have been added by setting SHRLIB_VERSION
(to 6.0 in this case). So shared object will be libpvData.so.6.0 instead of
libpvData.so.
Headers have been moved into pv directories
-------------------------------------------
E.g. src/property/alarm.h -> src/property/pv/alarm.h
This facilitates using some IDEs such as Qt Creator.
Requester::message has default implementation
---------------------------------------------
Requester::message is no longer pure virtual. Default implementation sends
string to std::cerr.
Serialization/deserialization helpers added
-------------------------------------------
A helper function, serializeToVector, has been added which serializes a
Serializable object into a standard vector of UInt8s.
Similarly a function deserializeFromVector deserializes a standard vector into
a Deserializable object.
A function deserializeFromBuffer deserializes a ByteBuffer into a
Deserializable object.
Field name validation performed
-------------------------------
On creating a Structure or Union the field names are now validated.
Valid characters for a field name are upper or lowercase letters, numbers and
underscores and intial numbers are invalid, i.e. names must be of the form
[A-Za-z_][A-Za-z0-9_]*.
Now builds for Cygwin and MinGW targets
---------------------------------------
Includes cross-compiling MinGW on Linux.
Release 5.0.4
=============
The changes since release 5.0.3 are:
* Fixed bitset serialization (issue #24)
* Fixed truncation in BitSet::or_and (issue #27)
Fixed bitset serialization (issue #24)
--------------------------------------
C++ bitset serialization was not consistent with the C++ deserialization and
Java code in some instances (depending on the endianness of the serializer and
deserializer) when the number of bits was 56-63 modulo 64. C++ serialization
has been fixed.
Fix exposed issue in deserialization on 32-bit platforms which
has also been corrected.
Fixed truncation in BitSet::or_and (issue #27)
----------------------------------------------
If n, n1 and n2 words are used to store the values of the bitsets bitset,
bitset1 and bitset2 respectively then max(n, min(n1,n2)) words are needed
to store bitset.or_(bitset1, bitset2).
Previously min(n1,n2) words were used and the result would be truncated in
some instances. This has been fixed.
Release 5.0.3
=============
The only change since release 5.0.2 is:
Fixed buffer overflow in PVUnion::serialize() (issue #20)
---------------------------------------------------------
A PVUnion whose stored value was null was serialized without checking
whether the buffer had sufficient capacity. This has been fixed by calling
ensureBuffer().
Release 5.0.2 (Sep. 2015)
=========================
The main changes since release 4.0 are:
- Deprecated getXXXField() methods have been removed from PVStructure
- Convert copy methods and equals operators (re)moved
- Convert::copyUnion now always copies between subfields.
- New method getSubFieldT, like getSubField except it throws an exception
- findSubField method removed from PVStructure
- New stream operators for Field and PVField are provided
- New template versions of Structure::getField
- Fixes for static initialisation order issues
- CreateRequest prevents a possible SEGFAULT
Deprecated getXXXField methods have been removed from PVStructure
-------------------------------------------------------------------
The following methods have been removed from PVStructure
- getBooleanField
- getByteField, getShortField, getIntField, getLongField
- getUByteField, getUShortField, getUIntField, getULongField
- getStringField
- getStructureField, getUnionField
- getScalarArrayField, getStructureArrayField, getUnionArrayField
Use template getSubField instead, e.g. use
getSubField< PVInt >(fieldName)
in place of
getIntField(fieldName)
Convert copy methods and equals operators
-----------------------------------------
Convert copy methods where moved and replaced with methods
on PVField classes, i.e.
PVField::copy(const PVField& from)
Methods
PVField::copyUnchecked(const PVField& from)
were added to allow unchecked copies, to gain performance
where checked are not needed (anymore).
In addition:
- isCompatibleXXX methods were removed in favour of Field::operator==.
- equals methods were remove in favour of PVField::operator==.
- operator== methods where moved to pvIntrospect.h and pvData.h
Convert::copyUnion
-----------------
Before this method, depending on types for to and from,
sometimes did a shallow copy, i.e. just made to shared_ptr for to
share the same data as from.
Now it always copies between the subfield of to and from.
New method getSubFieldT, like getSubField except it throws an exception
--------------------
PVStructure has a new template member
getSubFieldT(std::string const &fieldName)
that is like `getSubField()` except that it throws a runtime_error
instead of returning null.
findSubField method removed from PVStructure
--------------------------------------------
This was mainly used in the implementation of getSubField. With a change to
the latter, findSubField was removed.
New stream operators
--------------------
New steam operators are available for Field and PVField.
Before to print a Field (or any extension) or a PVField (or any extension)
it was necessary to have code like:
void print(StructureConstPtr struc, PVStructurePtr pv)
{
if(struc) {
cout << *struc << endl;
} else {
cout << "nullptr\n"
}
if(pv) {
cout << *.struc << endl;
} else {
cout << "nullptr\n"
}
}
Now it can be done as follows:
void print(StructureConstPtr struc, PVStructurePtr pv)
{
cout << struc << endl;
cout << pv << endl;
}
New template version of Structure::getField
--------------------------------------------
A new template getField method has been added to Structure
template<typename FT >
std::tr1::shared_ptr< const FT > getField(std::string const &fieldName) const
Can be used, for example, as follows:
StructurePtr tsStruc = struc->getField<Structure>("timeStamp");
Fixes for static initialisation order issues
--------------------------------------------
Certain static builds (in particular Windows builds) of applications using
pvData had issues due to PVStructure::DEFAULT_ID being used before being initialised. This has been fixed.
CreateRequest change
--------------------
createRequest could cause a SEGFAULT if passed a bad argument.
This has been changed so the it returns a null pvStructure
and provides an error.
Release 4.0.3
=============
The main changes since release 3.0.2 are:
- array semantics now enforce Copy On Write.
- String no longer defined.
- timeStamp and valueAlarm name changes
- toString replaced by stream I/O
- 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.
String no longer defined
---------
This is replaced by std::string.
timeStamp and valueAlarm name changes
--------------
In timeStamp nanoSeconds is changed to nanoseconds.
In valueAlarm hysteresis is changed to hysteresis
toString replaced by stream I/O
---------
pvData.h and pvIntrospect no longer defines toString
Instead they have stream support.
pvIntrospect uses method dump and pvData uses dumpValue.
For example:
PVDoublePtr pvValue;
String buffer;
pvValue->toString(&buffer);
cout << buffer << endl;
buffer.clear();
pvValue->getField()->toString(&buffer);
cout << buffer << evdl;
is replaced by
PVDoublePtr pvValue;
cout << *pvValue << endl
cout << *pvValue->getField() << endl;
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:
- *variant union* The field can have any type.
- *union* 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.
This is prototype and is subject to debate.
Release 3.0.2
==========
This was the starting point for RELEASE_NOTES
*/

14
examples/Makefile Normal file
View File

@@ -0,0 +1,14 @@
# Makefile for the examples
# make sure they compile
TOP = ..
include $(TOP)/configure/CONFIG
PROD_LIBS += pvData Com
TESTPROD_HOST += unittest
unittest_SRCS += unittest.cpp
include $(TOP)/configure/RULES

30
examples/unittest.cpp Normal file
View File

@@ -0,0 +1,30 @@
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/* c++ unittest skeleton */
#include <stdexcept>
#include <testMain.h>
#include <pv/pvUnitTest.h>
#include <pv/epicsException.h>
namespace {
void testCase1() {
testEqual(1+1, 2);
}
} // namespace
MAIN(testUnitTest)
{
testPlan(1);
try {
testCase1();
}catch(std::exception& e){
PRINT_EXCEPTION(e); // print stack trace if thrown with THROW_EXCEPTION()
testAbort("Unhandled exception: %s", e.what());
}
return testDone();
}

View File

@@ -4,10 +4,33 @@
# 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>
# Author: Ralph Lange <ralph.lange@gmx.de>
# Copyright (C) 2013 Helmholtz-Zentrum Berlin für Materialien und Energie GmbH
# Copyright (C) 2014-2016 ITER Organization.
# All rights reserved. Use is subject to license terms.
installTool () {
local module=$1
local version=$2
wget -nv https://openepics.ci.cloudbees.com/job/${module}-${version}_Build/lastSuccessfulBuild/artifact/${module,,}-${version}.CB-dist.tar.gz
tar -xzf ${module,,}-${version}.CB-dist.tar.gz
}
installE4 () {
local module=$1
local branch=$2
wget -nv https://openepics.ci.cloudbees.com/job/e4-cpp-${module}-${branch}-build/BASE=${BASE}/lastSuccessfulBuild/artifact/${module}.CB-dist.tar.gz
tar -xzf ${module}.CB-dist.tar.gz
}
###########################################
# Defaults for EPICS Base
DEFAULT_BASE=3.15.4
BASE=${BASE:-${DEFAULT_BASE}}
###########################################
# Fetch and unpack dependencies
@@ -17,10 +40,8 @@ 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
installTool Boost 1.61.0
installTool Base ${BASE}
###########################################
# Build
@@ -37,20 +58,13 @@ 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
tar czf pvData.CB-dist.tar.gz lib include LICENSE

74
jenkins/cloudbees_doc Normal file
View File

@@ -0,0 +1,74 @@
# pvData C++ implementation
# Jenkins @ Cloudbees documentation generation and deployment
#
# 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
# Copyright (C) 2014-2016 ITER Organization.
# All rights reserved. Use is subject to license terms.
installTool () {
local module=$1
local version=$2
wget -nv https://openepics.ci.cloudbees.com/job/${module}-${version}_Build/lastSuccessfulBuild/artifact/${module,,}-${version}.CB-dist.tar.gz
tar -xzf ${module,,}-${version}.CB-dist.tar.gz
}
installE4 () {
local module=$1
local branch=$2
# If microbench version does not exist, try without
if [ "${MB}" = "WITH_MICROBENCH" ]; then
if ! wget -nv https://openepics.ci.cloudbees.com/job/e4-cpp-${module}-${branch}-build/BASE=${BASE},MB=WITH_MICROBENCH/lastSuccessfulBuild/artifact/${module}.CB-dist.tar.gz; then
wget -nv https://openepics.ci.cloudbees.com/job/e4-cpp-${module}-${branch}-build/BASE=${BASE},MB=NO_MICROBENCH/lastSuccessfulBuild/artifact/${module}.CB-dist.tar.gz
fi
else
wget -nv https://openepics.ci.cloudbees.com/job/e4-cpp-${module}-${branch}-build/BASE=${BASE},MB=NO_MICROBENCH/lastSuccessfulBuild/artifact/${module}.CB-dist.tar.gz
fi
tar -xzf ${module}.CB-dist.tar.gz
}
###########################################
# Defaults for EPICS Base and parameters
BASE=3.15.4
PUBLISH=${PUBLISH:-NO}
BRANCH=${BRANCH:-master}
MB=NO_MICROBENCH
###########################################
# Fetch and unpack dependencies
export STUFF=/tmp/stuff
rm -fr ${STUFF}
mkdir -p ${STUFF}
cd ${STUFF}
installTool Doxygen 1.8.11
###########################################
# Generate
cd ${WORKSPACE}
installE4 pvData ${BRANCH}
export PATH=${STUFF}/bin:${PATH}
doxygen
###########################################
# Publish
if [ "${PUBLISH}" != "NO" ]; then
# Upload explicit dummy to ensure target directory exists
echo "Created by CloudBees Jenkins upload job. Should be deleted as part of the job." > DUMMY
rsync -q -e ssh DUMMY epics-jenkins@web.sourceforge.net:/home/project-web/epics-pvdata/htdocs/docbuild/pvDataCPP/${PUBLISH}/
rsync -aqP --delete -e ssh documentation epics-jenkins@web.sourceforge.net:/home/project-web/epics-pvdata/htdocs/docbuild/pvDataCPP/${PUBLISH}/
fi

View File

@@ -1,20 +0,0 @@
# 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 +0,0 @@
// ADD PREDEFINED MACROS HERE!

View File

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

View File

@@ -1,211 +0,0 @@
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

View File

@@ -1,6 +0,0 @@
/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

View File

@@ -3,21 +3,34 @@
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
include $(PVDATA_SRC)/json/Makefile
LIBRARY = pvData
pvData_LIBS += Com
EXPANDVARS += EPICS_PVD_MAJOR_VERSION
EXPANDVARS += EPICS_PVD_MINOR_VERSION
EXPANDVARS += EPICS_PVD_MAINTENANCE_VERSION
EXPANDVARS += EPICS_PVD_DEVELOPMENT_FLAG
EXPANDFLAGS += $(foreach var,$(EXPANDVARS),-D$(var)="$(strip $($(var)))")
# shared library ABI version.
SHRLIB_VERSION = $(EPICS_PVD_MAJOR_VERSION).$(EPICS_PVD_MINOR_VERSION).$(EPICS_PVD_MAINTENANCE_VERSION)
include $(TOP)/configure/RULES
# Can't use EXPAND as generated headers must appear
# in O.Common, but EXPAND emits rules for O.$(T_A)
../O.Common/pv/pvdVersionNum.h: ../pv/pvdVersionNum.h@
$(MKDIR) $(COMMON_DIR)/pv
$(EXPAND_TOOL) $(EXPANDFLAGS) $($@_EXPANDFLAGS) $< $@

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 += pv/createRequest.h
INC += pv/pvCopy.h
LIBSRCS += createRequest.cpp
LIBSRCS += pvCopy.cpp

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

@@ -0,0 +1,486 @@
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
#include <string>
#include <sstream>
#include <epicsMutex.h>
#define epicsExportSharedSymbols
#include <pv/pvData.h>
#include <pv/lock.h>
#include <pv/createRequest.h>
using namespace epics::pvData;
using std::ostringstream;
using std::tr1::static_pointer_cast;
using std::cout;
using std::endl;
using std::string;
using std::vector;
namespace {
using namespace epics::pvData;
static PVDataCreatePtr pvDataCreate = getPVDataCreate();
static FieldCreatePtr fieldCreate = getFieldCreate();
struct CreateRequestImpl {
struct Node
{
string name;
vector<Node> nodes;
Node(string name)
: name(name)
{}
};
struct OptionPair
{
string name;
string value;
OptionPair(string name,string value)
: name(name),
value(value)
{}
};
vector<OptionPair> optionList;
string fullFieldName;
CreateRequestImpl() {}
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){
throw std::runtime_error(request + " mismatched {}");
}
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) {
throw std::runtime_error(request + " mismatched []");
}
return i;
}
}
throw std::runtime_error(request + " missing ]");
}
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(request[ind]=='.') {
++ind;
continue;
}
if(ind>=maxind) break;
++ind;
}
return request.size();
}
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;
}
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;
}
Node createRequestOptions(
string const & request)
{
if(request.length()<=1) {
throw std::runtime_error("logic error empty options");
}
vector<Node> top;
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('=');
if(equals==string::npos || equals==0) {
throw std::runtime_error(item + " illegal option " + request);
}
top.push_back(Node(item.substr(0,equals)));
string name = fullFieldName + "._options." + item.substr(0,equals);
string value = item.substr(equals+1);
optionList.push_back(OptionPair(name,value));
}
Node node("_options");
node.nodes = top;
return node;
}
void createSubNode(Node &node,string const & crequest)
{
string request = crequest;
size_t end = 0;
for(size_t i=0; i<request.size(); ++i) {
if(request[i]=='[') { end = i; break;}
if(request[i]=='.') { end = i; break;}
if(request[i]=='{') { end = i; break;}
if(request[i]==',') { end = i; break;}
}
char chr = request[end];
Node optionNode("");
if(chr=='[') {
string saveFullName = fullFieldName;
fullFieldName += "." + request.substr(0,end);
size_t endBracket = findMatchingBracket(request,end);
string options = request.substr(end+1,endBracket -end -1);
optionNode = createRequestOptions(options);
fullFieldName = saveFullName;
size_t next = endBracket+1;
if(next<request.size()) {
request = request.substr(0, end) + request.substr(endBracket+1);
} else {
request = request.substr(0, end);
}
end = 0;
for(size_t i=0; i<request.size(); ++i) {
if(request[i]=='.') { end = i; break;}
if(request[i]=='{') { end = i; break;}
if(request[i]==',') { end = i; break;}
}
chr = request[end];
}
if(end==0) end = request.size();
string name = request.substr(0,end);
if(name.size()<1) {
throw std::runtime_error("null field name " + request);
}
string saveFullName = fullFieldName;
fullFieldName += "." + name;
if(end==request.size()) {
Node subNode(name);
if(optionNode.name.size()>0) subNode.nodes.push_back(optionNode);
node.nodes.push_back(subNode);
fullFieldName = saveFullName;
return;
}
if(chr==',') {
Node subNode(name);
if(optionNode.name.size()>0) subNode.nodes.push_back(optionNode);
node.nodes.push_back(subNode);
string rest = request.substr(end+1);
fullFieldName = saveFullName;
createSubNode(node,rest);
return;
}
if(chr=='.') {
request = request.substr(end+1);
if(request.size()==string::npos || request.size()<1) {
throw std::runtime_error("null field name " + request);
}
Node subNode(name);
if(optionNode.name.size()>0) subNode.nodes.push_back(optionNode);
size_t endField = findEndField(request);
string subRequest = request.substr(0, endField);
createSubNode(subNode,subRequest);
node.nodes.push_back(subNode);
size_t next = endField+1;
if(next>=request.size()) {
fullFieldName = saveFullName;
return;
}
request = request.substr(next);
fullFieldName = saveFullName;
createSubNode(node,request);
return;
}
if(chr=='{') {
size_t endBrace = findEndField(request);
if((end+1)>=(endBrace-1)) {
throw std::runtime_error("illegal syntax " + request);
}
string subRequest = request.substr(end+1,endBrace-1 -end -1);
if(subRequest.size()<1) {
throw std::runtime_error("empty {} " + request);
}
Node subNode(name);
if(optionNode.name.size()>0) subNode.nodes.push_back(optionNode);
createSubNode(subNode,subRequest);
node.nodes.push_back(subNode);
size_t next = endBrace + 1;
if(next>=request.size()) {
fullFieldName = saveFullName;
return;
}
request = request.substr(next);
fullFieldName = saveFullName;
createSubNode(node,request);
return;
}
throw std::runtime_error("logic error");
}
FieldConstPtr createSubStructure(vector<Node> & nodes)
{
size_t num = nodes.size();
StringArray names(num);
FieldConstPtrArray fields(num);
for(size_t i=0; i<num; ++i) {
Node node = nodes[i];
names[i] = node.name;
if(node.name.compare("_options")==0) {
fields[i] = createOptions(node.nodes);
} else {
vector<Node> subNode = node.nodes;
if(subNode.empty()) {
fields[i] = fieldCreate->createStructure();
} else {
fields[i] = createSubStructure(subNode);
}
}
}
StructureConstPtr structure = fieldCreate->createStructure(
names, fields);
return structure;
}
StructureConstPtr createOptions(vector<Node> &nodes)
{
size_t num = nodes.size();
StringArray names(num);
FieldConstPtrArray fields(num);
for(size_t i=0; i<num; ++i) {
Node node = nodes[i];
names[i] = node.name;
fields[i] = fieldCreate->createScalar(pvString);
}
StructureConstPtr structure = fieldCreate->createStructure(names, fields);
return structure;
}
PVStructurePtr createRequest(
string const & crequest)
{
{
string request = crequest;
if (!request.empty()) removeBlanks(request);
if (request.empty())
{
return pvDataCreate->createPVStructure(fieldCreate->createStructure());
}
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(" + request + ")";
offsetField = request.find("field(");
}
int numParan = 0;
int numBrace = 0;
int numBracket = 0;
for(size_t i=0; i< request.length() ; ++i) {
char chr = request[i];
if(chr=='(') numParan++;
if(chr==')') numParan--;
if(chr=='{') numBrace++;
if(chr=='}') numBrace--;
if(chr=='[') numBracket++;
if(chr==']') numBracket--;
}
if(numParan!=0) {
ostringstream oss;
oss << "mismatched () " << numParan;
throw std::runtime_error(oss.str());
}
if(numBrace!=0) {
ostringstream oss;
oss << "mismatched {} " << numBrace;
throw std::runtime_error(oss.str());
}
if(numBracket!=0) {
ostringstream oss;
oss << "mismatched [] " << numBracket;
throw std::runtime_error(oss.str());
}
vector<Node> top;
try {
if(offsetRecord!=string::npos) {
fullFieldName = "record";
size_t openBracket = request.find('[', offsetRecord);
size_t closeBracket = request.find(']', openBracket);
if(closeBracket==string::npos) {
throw std::runtime_error(request.substr(offsetRecord) +
"record[ does not have matching ]");
}
if(closeBracket-openBracket > 3) {
Node node("record");
Node optNode = createRequestOptions(
request.substr(openBracket+1,closeBracket-openBracket-1));
node.nodes.push_back(optNode);
top.push_back(node);
}
}
if(offsetField!=string::npos) {
fullFieldName = "field";
Node node("field");
size_t openParan = request.find('(', offsetField);
size_t closeParan = request.find(')', openParan);
if(closeParan==string::npos) {
throw std::runtime_error(request.substr(offsetField)
+ " field( does not have matching )");
}
if(closeParan>openParan+1) {
createSubNode(node,request.substr(openParan+1,closeParan-openParan-1));
}
top.push_back(node);
}
if(offsetGetField!=string::npos) {
fullFieldName = "getField";
Node node("getField");
size_t openParan = request.find('(', offsetGetField);
size_t closeParan = request.find(')', openParan);
if(closeParan==string::npos) {
throw std::runtime_error(request.substr(offsetField)
+ " getField( does not have matching )");
}
if(closeParan>openParan+1) {
createSubNode(node,request.substr(openParan+1,closeParan-openParan-1));
}
top.push_back(node);
}
if(offsetPutField!=string::npos) {
fullFieldName = "putField";
Node node("putField");
size_t openParan = request.find('(', offsetPutField);
size_t closeParan = request.find(')', openParan);
if(closeParan==string::npos) {
throw std::runtime_error(request.substr(offsetField)
+ " putField( does not have matching )");
}
if(closeParan>openParan+1) {
createSubNode(node,request.substr(openParan+1,closeParan-openParan-1));
}
top.push_back(node);
}
} catch (std::exception &e) {
throw std::runtime_error(std::string("while creating Structure exception ")+e.what());
}
size_t num = top.size();
StringArray names(num);
FieldConstPtrArray fields(num);
for(size_t i=0; i<num; ++i) {
Node node = top[i];
names[i] = node.name;
vector<Node> subNode = node.nodes;
if(subNode.empty()) {
fields[i] = fieldCreate->createStructure();
} else {
fields[i] = createSubStructure(subNode);
}
}
StructureConstPtr structure = fieldCreate->createStructure(names, fields);
if(!structure) throw std::invalid_argument("bad request " + crequest);
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(structure);
for(size_t i=0; i<optionList.size(); ++i) {
OptionPair pair = optionList[i];
string name = pair.name;
string value = pair.value;
PVStringPtr pvField = pvStructure->getSubField<PVString>(name);
if(!pvField) throw std::invalid_argument("bad request " + crequest);
pvField->put(value);
}
optionList.clear();
return pvStructure;
}
}
};
} // namespace
namespace epics {namespace pvData {
CreateRequest::shared_pointer CreateRequest::create()
{
CreateRequest::shared_pointer createRequest(new CreateRequest());
return createRequest;
}
PVStructure::shared_pointer CreateRequest::createRequest(std::string const & request)
{
message.clear();
try {
return ::createRequest(request);
} catch(std::exception& e) {
message = e.what();
return PVStructure::shared_pointer();
}
}
PVStructure::shared_pointer createRequest(std::string const & request)
{
CreateRequestImpl I;
return I.createRequest(request);
}
}} // namespace

View File

@@ -0,0 +1,67 @@
/*createRequest.h*/
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the 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 {
/**
* @brief Create pvRequest structure for Channel methods.
*
* Many methods of the Channel class of pvAccess have an
* argument <b>PVStructurePtr const * pvRequest</b>.
* This class provides a method that creates a valid pvRequest.
*
*/
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();
~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.
* @return The request PVStructure if a valid request was given.
* If a NULL PVStructure is returned then getMessage will return
* the reason.
*/
PVStructure::shared_pointer createRequest(std::string const & request);
/**
* Get the error message of createRequest returns NULL
* return the error message
*/
std::string getMessage() {return message;}
protected:
CreateRequest() {}
std::string message;
};
/** Parse and build pvRequest structure.
*
@params request the Request string to be parsed. eg. "field(value)"
@returns The resulting strucuture. Never NULL
@throws std::exception for various parsing errors
*/
epicsShareExtern
PVStructure::shared_pointer createRequest(std::string const & request);
}}
#endif /* CREATEREQUEST_H */

232
src/copy/pv/pvCopy.h Normal file
View File

@@ -0,0 +1,232 @@
/* pvCopy.h */
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the 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;
/**
* @brief 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;
/**
* @brief Support for subset of fields in a pvStructure.
*
* 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 structure for which a copy of
* an arbitrary 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(){}
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 an offset in the copy get the corresponding field in pvMaster.
* @param structureOffset 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 corresponding 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 corresponding 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 fieldOffset 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 */

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

@@ -0,0 +1,649 @@
/* pvCopy.cpp */
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author Marty Kraimer
* @date 2013.04
*/
#include <string>
#include <stdexcept>
#include <memory>
#include <sstream>
#include <epicsThread.h>
#define epicsExportSharedSymbols
#include <pv/thread.h>
#include <pv/pvCopy.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 {
/**
* Convenience method for implementing dump.
* It generates a newline and inserts blanks at the beginning of the newline.
* @param builder The std::string * being constructed.
* @param indentLevel Indent level, Each level is four spaces.
*/
static void newLine(string *buffer, int indentLevel)
{
*buffer += "\n";
*buffer += string(indentLevel*4, ' ');
}
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->getSubField<PVStructure>(structureName);
if(!pvStructure) return PVCopyPtr();
}
} else if(pvStructure->getSubField<PVStructure>("field")) {
pvStructure = pvRequest->getSubField<PVStructure>("field");
}
PVCopyPtr pvCopy(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) {
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 PVStructurePtr();
}
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 PVStructurePtr();
}
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) 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) 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) {
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;
}
bool isEqual = (*copyPVField == *pvField);
if(!isEqual) {
copyPVField->copyUnchecked(*pvField);
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)
{
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) {
newLine(builder,indentLevel +1);
// TODO !!! ugly
std::ostringstream oss;
oss << *options;
*builder += oss.str();
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) {
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) {
pvOptions = pvRequest->getSubField<PVStructure>("_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) 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 StructureConstPtr();
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) 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 StructureConstPtr();
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) 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 = pvFromRequest->getSubField<PVStructure>(fieldName);
PVStructurePtr pvSubFieldOptions = requestPVStructure->getSubField<PVStructure>("_options");
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) 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) {
bool isEqual = (*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;
pvCopy->copyUnchecked(*pvMaster);
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->getSubFieldT(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;
}
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) {
pvCopy->copyUnchecked(*pvMasterField);
} else {
pvMasterField->copyUnchecked(*pvCopy);
}
}
}
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) return masterNode;
}
}
return CopyMasterNodePtr();
}
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 CopyMasterNodePtr();
}
}}

View File

@@ -1,22 +1,23 @@
/**
* 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.
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author mes
*/
#define epicsExportSharedSymbols
#include <pv/convert.h>
#include <algorithm>
#include <iterator>
#include <sstream>
#define epicsExportSharedSymbols
#include <pv/pvData.h>
using std::string;
namespace epics { namespace pvData {
// Introspection object comparision
// Introspection object comparison
/** Field equality conditions:
* 1) same instance
@@ -60,7 +61,7 @@ bool operator==(const Field& a, const Field& b)
return A==B;
}
default:
throw std::logic_error("Invalid Field type in comparision");
throw std::logic_error("Invalid Field type in comparison");
}
}
@@ -89,14 +90,14 @@ bool operator==(const Structure& a, const Structure& b)
return false;
// std::equals does not work, since FieldConstPtrArray is an array of shared_pointers
FieldConstPtrArray af = a.getFields();
FieldConstPtrArray bf = b.getFields();
FieldConstPtrArray const & af = a.getFields();
FieldConstPtrArray const & 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();
StringArray const & an = a.getFieldNames();
StringArray const & bn = b.getFieldNames();
return std::equal( an.begin(), an.end(), bn.begin() );
}
@@ -116,14 +117,14 @@ bool operator==(const Union& a, const Union& b)
return false;
// std::equals does not work, since FieldConstPtrArray is an array of shared_pointers
FieldConstPtrArray af = a.getFields();
FieldConstPtrArray bf = b.getFields();
FieldConstPtrArray const & af = a.getFields();
FieldConstPtrArray const & 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();
StringArray const & an = a.getFieldNames();
StringArray const & bn = b.getFieldNames();
return std::equal( an.begin(), an.end(), bn.begin() );
}
@@ -132,6 +133,13 @@ bool operator==(const UnionArray& a, const UnionArray& b)
return *(a.getUnion().get())==*(b.getUnion().get());
}
bool operator==(const BoundedString& a, const BoundedString& b)
{
if(&a==&b)
return true;
return a.getMaximumLength()==b.getMaximumLength();
}
// PVXXX object comparison
namespace {
@@ -202,7 +210,7 @@ bool compareField(const PVScalarArray* left, const PVScalarArray* right)
OP(pvLong, int64);
OP(pvFloat, float);
OP(pvDouble, double);
OP(pvString, String);
OP(pvString, string);
#undef OP
}
throw std::logic_error("PVScalarArray with invalid element type!");
@@ -242,7 +250,13 @@ bool compareField(const PVStructureArray* left, const PVStructureArray* right)
lit!=lend;
++lit, ++rit)
{
if(**lit != **rit)
// element can be null
if (!(*lit) || !(*rit))
{
if (*lit || *rit)
return false;
}
else if (**lit != **rit)
return false;
}
return true;
@@ -257,7 +271,7 @@ bool compareField(const PVUnion* left, const PVUnion* right)
if (ls->isVariant())
{
PVFieldPtr lval = left->get();
const PVField::const_shared_pointer& lval = left->get();
if (lval.get() == 0)
return right->get().get() == 0;
else
@@ -295,7 +309,13 @@ bool compareField(const PVUnionArray* left, const PVUnionArray* right)
lit!=lend;
++lit, ++rit)
{
if(**lit != **rit)
// element can be null
if (!(*lit) || !(*rit))
{
if (*lit || *rit)
return false;
}
else if (**lit != **rit)
return false;
}
return true;

View File

@@ -1,8 +1,7 @@
/* 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.
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author mrk
@@ -13,46 +12,47 @@
#include <stdexcept>
#include <typeinfo>
#include <epicsMutex.h>
#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;
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;
string::size_type pos = commaSeparatedList.find(',',index);
if(pos==string::npos) break;
numValues++;
index = pos +1;
}
std::vector<String> valueList(numValues,"");
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);
string value = commaSeparatedList.substr(index,pos);
valueList[i] = value;
index = pos +1;
}
return valueList;
}
void Convert::getString(StringBuilder buf,PVField const *pvField,int /*indentLevel*/)
void Convert::getString(string *buf,PVField const *pvField,int /*indentLevel*/)
{
// TODO indextLevel ignored
std::ostringstream strm;
PrinterPlain p;
p.setStream(strm);
p.print(*pvField);
pvField->dumpValue(strm);
strm << std::endl;
strm.str().swap(*buf);
}
@@ -87,9 +87,9 @@ size_t Convert::fromString(PVStructurePtr const &pvStructure, StringArray const
}
else {
// union, structureArray, unionArray not supported
String message("Convert::fromString unsupported fieldType ");
TypeFunc::toString(&message,type);
throw std::logic_error(message);
std::ostringstream oss;
oss << "Convert::fromString unsupported fieldType " << type;
throw std::logic_error(oss.str());
}
}
}
@@ -97,13 +97,13 @@ size_t Convert::fromString(PVStructurePtr const &pvStructure, StringArray const
return processed;
}
size_t Convert::fromString(PVScalarArrayPtr const &pv, String from)
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));
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;
@@ -128,7 +128,7 @@ size_t Convert::fromStringArray(PVScalarArrayPtr const &pv,
data.begin());
PVStringArray::const_svector temp(freeze(data));
pv->putFrom<String>(temp);
pv->putFrom<string>(temp);
return length;
} else {
@@ -142,7 +142,7 @@ size_t Convert::toStringArray(PVScalarArrayPtr const & pv,
StringArray &to, size_t toOffset)
{
PVStringArray::const_svector data;
pv->getAs<String>(data);
pv->getAs<string>(data);
data.slice(offset, length);
if(toOffset+data.size() > to.size())
to.resize(toOffset+data.size());
@@ -150,374 +150,6 @@ size_t Convert::toStringArray(PVScalarArrayPtr const & pv,
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
copy(fromValue, to->select(from->getSelectedIndex()));
}
}
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(StringBuilder buffer, int indentLevel)
{
*buffer += "\n";
*buffer += String(indentLevel*4, ' ');
}
ConvertPtr Convert::getConvert()
{
static ConvertPtr convert;

File diff suppressed because it is too large Load Diff

View File

@@ -2,10 +2,9 @@
SRC_DIRS += $(PVDATA_SRC)/factory
INC += factory.h
INC += pv/factory.h
LIBSRCS += TypeFunc.cpp
LIBSRCS += FieldCreateFactory.cpp
LIBSRCS += PVAuxInfoImpl.cpp
LIBSRCS += PVField.cpp
LIBSRCS += PVScalar.cpp
LIBSRCS += PVArray.cpp

View File

@@ -1,8 +1,7 @@
/*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.
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author mrk

View File

@@ -1,86 +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>
#define epicsExportSharedSymbols
#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,14 +1,13 @@
/*PVDataCreateFactory.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.
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author mrk
*/
#ifdef _WIN32
#if defined(_WIN32) && !defined(NOMINMAX)
#define NOMINMAX
#endif
@@ -17,16 +16,19 @@
#include <string>
#include <cstdio>
#include <epicsMutex.h>
#define epicsExportSharedSymbols
#include <pv/lock.h>
#include <pv/pvIntrospect.h>
#include <pv/pvData.h>
#include <pv/convert.h>
#include <pv/factory.h>
#include <pv/serializeHelper.h>
#include <pv/reftrack.h>
using std::tr1::static_pointer_cast;
using std::size_t;
using std::string;
using std::min;
namespace epics { namespace pvData {
@@ -43,7 +45,7 @@ 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 PVScalarValue<string>::typeCode = pvString;
template<> const ScalarType PVBooleanArray::typeCode = pvBoolean;
template<> const ScalarType PVByteArray::typeCode = pvByte;
@@ -58,125 +60,62 @@ 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>
class BasePVScalar : public PVScalarValue<T> {
public:
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
BasePVScalar(ScalarConstPtr const & scalar);
virtual ~BasePVScalar();
virtual T get() const ;
virtual void put(T val);
virtual void serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher) const;
virtual void deserialize(ByteBuffer *pbuffer,
DeserializableControl *pflusher);
private:
T value;
};
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)
PVScalarValue<T>::~PVScalarValue() {}
template<typename T>
BasePVScalar<T>::~BasePVScalar() {}
template<typename T>
T BasePVScalar<T>::get() const { return value;}
template<typename T>
void BasePVScalar<T>::put(T val)
{
value = val;
PVField::postPut();
}
template<typename T>
void BasePVScalar<T>::serialize(ByteBuffer *pbuffer,
void PVScalarValue<T>::serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher) const {
pflusher->ensureBuffer(sizeof(T));
pbuffer->put(value);
pbuffer->put(storage.value);
}
template<>
void PVScalarValue<std::string>::serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher) const {
SerializeHelper::serializeString(storage.value, pbuffer, pflusher);
}
template<typename T>
void BasePVScalar<T>::deserialize(ByteBuffer *pbuffer,
void PVScalarValue<T>::deserialize(ByteBuffer *pbuffer,
DeserializableControl *pflusher)
{
pflusher->ensureData(sizeof(T));
value = pbuffer->GET(T);
storage.value = pbuffer->GET(T);
}
typedef BasePVScalar<boolean> BasePVBoolean;
typedef BasePVScalar<int8> BasePVByte;
typedef BasePVScalar<int16> BasePVShort;
typedef BasePVScalar<int32> BasePVInt;
typedef BasePVScalar<int64> BasePVLong;
typedef BasePVScalar<uint8> BasePVUByte;
typedef BasePVScalar<uint16> BasePVUShort;
typedef BasePVScalar<uint32> BasePVUInt;
typedef BasePVScalar<uint64> BasePVULong;
typedef BasePVScalar<float> BasePVFloat;
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;
BasePVString(ScalarConstPtr const & scalar);
virtual ~BasePVString();
virtual String get() const ;
virtual void put(String val);
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:
String value;
};
BasePVString::BasePVString(ScalarConstPtr const & scalar)
: PVString(scalar),value()
{}
BasePVString::~BasePVString() {}
String BasePVString::get() const { return value;}
void BasePVString::put(String val)
{
value = val;
postPut();
}
void BasePVString::serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher) const
{
SerializeHelper::serializeString(value, pbuffer, pflusher);
}
void BasePVString::deserialize(ByteBuffer *pbuffer,
template<>
void PVScalarValue<std::string>::deserialize(ByteBuffer *pbuffer,
DeserializableControl *pflusher)
{
value = SerializeHelper::deserializeString(pbuffer, pflusher);
storage.value = SerializeHelper::deserializeString(pbuffer, pflusher);
// TODO: check for violations of maxLength?
}
void BasePVString::serialize(ByteBuffer *pbuffer,
PVString::PVString(ScalarConstPtr const & scalar)
: PVScalarValue<std::string>(scalar)
{
BoundedStringConstPtr boundedString = std::tr1::dynamic_pointer_cast<const BoundedString>(scalar);
if (boundedString.get())
storage.maxLength = boundedString->getMaximumLength();
else
storage.maxLength = 0;
}
/* mixing overrides (virtual functions) and overloads (different argument lists) is fun...
* we override all overloads to avoid the "hides overloaded virtual function" warning from clang.
* In this case we don't need/want to, so just delegate to the base class.
*/
void PVString::serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher) const
{PVScalarValue<std::string>::serialize(pbuffer, pflusher);}
void PVString::serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher, size_t offset, size_t count) const
{
// check bounds
const size_t length = /*(value == null) ? 0 :*/ value.length();
const size_t length = storage.value.length();
/*if (offset < 0) offset = 0;
else*/ if (offset > length) offset = length;
//if (count < 0) count = length;
@@ -186,103 +125,102 @@ void BasePVString::serialize(ByteBuffer *pbuffer,
count = maxCount;
// write
SerializeHelper::serializeSubstring(value, offset, count, pbuffer, pflusher);
SerializeHelper::serializeSubstring(storage.value, offset, count, pbuffer, pflusher);
}
/** Default storage for arrays
*/
template<typename T>
class DefaultPVArray : public PVValueArray<T> {
public:
typedef T* pointer;
typedef const T* const_pointer;
typedef std::vector<T> vector;
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 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:
const_svector value;
};
template<typename T>
DefaultPVArray<T>::DefaultPVArray(ScalarArrayConstPtr const & scalarArray)
: PVValueArray<T>(scalarArray),
value()
{ }
template<typename T>
DefaultPVArray<T>::~DefaultPVArray()
{ }
template<typename T>
void DefaultPVArray<T>::setCapacity(size_t capacity)
void PVArray::checkLength(size_t len) const
{
if(this->isCapacityMutable()) {
value.reserve(capacity);
Array::ArraySizeType type = getArray()->getArraySizeType();
if (type != Array::variable)
{
size_t size = getArray()->getMaximumCapacity();
if (type == Array::fixed && len != size)
throw std::invalid_argument("invalid length for a fixed size array");
else if (type == Array::bounded && len > size)
throw std::invalid_argument("new array capacity too large for a bounded size array");
}
}
template<typename T>
void DefaultPVArray<T>::setLength(size_t length)
PVValueArray<T>::PVValueArray(ScalarArrayConstPtr const & scalarArray)
:base_t(scalarArray)
,value()
{}
PVValueArray<PVStructurePtr>::PVValueArray(StructureArrayConstPtr const & structureArray)
:base_t(structureArray)
,structureArray(structureArray)
{}
PVValueArray<PVUnionPtr>::PVValueArray(UnionArrayConstPtr const & unionArray)
:base_t(unionArray)
,unionArray(unionArray)
{}
template<typename T>
void PVValueArray<T>::setCapacity(size_t capacity)
{
if(this->isCapacityMutable()) {
this->checkLength(capacity);
value.reserve(capacity);
}
else
THROW_EXCEPTION2(std::logic_error, "capacity immutable");
}
template<typename T>
void PVValueArray<T>::setLength(size_t length)
{
if(this->isImmutable())
THROW_EXCEPTION2(std::logic_error,"Immutable");
if(length == value.size())
THROW_EXCEPTION2(std::logic_error, "immutable");
if (length == value.size())
return;
else if(length < value.size())
this->checkLength(length);
if (length < value.size())
value.slice(0, length);
else
value.resize(length);
}
template<typename T>
void DefaultPVArray<T>::replace(const const_svector& next)
void PVValueArray<T>::replace(const const_svector& next)
{
this->checkLength(next.size());
value = next;
this->postPut();
}
template<typename T>
void DefaultPVArray<T>::swap(const_svector &other)
void PVValueArray<T>::swap(const_svector &other)
{
if(this->isImmutable())
THROW_EXCEPTION2(std::logic_error,"Immutable");
if (this->isImmutable())
THROW_EXCEPTION2(std::logic_error, "immutable");
// no checkLength call here
value.swap(other);
}
template<typename T>
void DefaultPVArray<T>::serialize(ByteBuffer *pbuffer,
void PVValueArray<T>::serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher) const {
serialize(pbuffer, pflusher, 0, this->getLength());
}
template<typename T>
void DefaultPVArray<T>::deserialize(ByteBuffer *pbuffer,
void PVValueArray<T>::deserialize(ByteBuffer *pbuffer,
DeserializableControl *pcontrol) {
size_t size = SerializeHelper::readSize(pbuffer, pcontrol);
size_t size = this->getArray()->getArraySizeType() == Array::fixed ?
this->getArray()->getMaximumCapacity() :
SerializeHelper::readSize(pbuffer, pcontrol);
svector nextvalue(thaw(value));
nextvalue.resize(size); // TODO: avoid copy of stuff we will then overwrite
@@ -320,12 +258,13 @@ void DefaultPVArray<T>::deserialize(ByteBuffer *pbuffer,
remaining -= n2read;
}
value = freeze(nextvalue);
// TODO !!!
// inform about the change?
PVField::postPut();
}
template<typename T>
void DefaultPVArray<T>::serialize(ByteBuffer *pbuffer,
void PVValueArray<T>::serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher, size_t offset, size_t count) const
{
//TODO: avoid incrementing the ref counter...
@@ -333,7 +272,11 @@ void DefaultPVArray<T>::serialize(ByteBuffer *pbuffer,
temp.slice(offset, count);
count = temp.size();
SerializeHelper::writeSize(temp.size(), pbuffer, pflusher);
ArrayConstPtr array = this->getArray();
if (array->getArraySizeType() != Array::fixed)
SerializeHelper::writeSize(count, pbuffer, pflusher);
else if (count != array->getMaximumCapacity())
throw std::length_error("fixed array cannot be partially serialized");
const T* cur = temp.data();
@@ -362,12 +305,15 @@ void DefaultPVArray<T>::serialize(ByteBuffer *pbuffer,
}
}
// specializations for String
// specializations for string
template<>
void DefaultPVArray<String>::deserialize(ByteBuffer *pbuffer,
void PVValueArray<string>::deserialize(ByteBuffer *pbuffer,
DeserializableControl *pcontrol) {
size_t size = SerializeHelper::readSize(pbuffer, pcontrol);
size_t size = this->getArray()->getArraySizeType() == Array::fixed ?
this->getArray()->getMaximumCapacity() :
SerializeHelper::readSize(pbuffer, pcontrol);
svector nextvalue(thaw(value));
@@ -378,7 +324,7 @@ void DefaultPVArray<String>::deserialize(ByteBuffer *pbuffer,
nextvalue.slice(0, size);
String * pvalue = nextvalue.data();
string * pvalue = nextvalue.data();
for(size_t i = 0; i<size; i++) {
pvalue[i] = SerializeHelper::deserializeString(pbuffer,
pcontrol);
@@ -389,33 +335,22 @@ void DefaultPVArray<String>::deserialize(ByteBuffer *pbuffer,
}
template<>
void DefaultPVArray<String>::serialize(ByteBuffer *pbuffer,
void PVValueArray<string>::serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher, size_t offset, size_t count) const {
const_svector temp(value);
temp.slice(offset, count);
SerializeHelper::writeSize(temp.size(), pbuffer, pflusher);
// TODO if fixed count == getArray()->getMaximumCapacity()
if (this->getArray()->getArraySizeType() != Array::fixed)
SerializeHelper::writeSize(temp.size(), pbuffer, pflusher);
const String * pvalue = temp.data();
const string * pvalue = temp.data();
for(size_t i = 0; i<temp.size(); i++) {
SerializeHelper::serializeString(pvalue[i], pbuffer, pflusher);
}
}
typedef DefaultPVArray<boolean> DefaultPVBooleanArray;
typedef DefaultPVArray<int8> BasePVByteArray;
typedef DefaultPVArray<int16> BasePVShortArray;
typedef DefaultPVArray<int32> BasePVIntArray;
typedef DefaultPVArray<int64> BasePVLongArray;
typedef DefaultPVArray<uint8> BasePVUByteArray;
typedef DefaultPVArray<uint16> BasePVUShortArray;
typedef DefaultPVArray<uint32> BasePVUIntArray;
typedef DefaultPVArray<uint64> BasePVULongArray;
typedef DefaultPVArray<float> BasePVFloatArray;
typedef DefaultPVArray<double> BasePVDoubleArray;
typedef DefaultPVArray<String> BasePVStringArray;
// Factory
PVDataCreate::PVDataCreate()
@@ -472,7 +407,7 @@ PVFieldPtr PVDataCreate::createPVField(PVFieldPtr const & fieldToClone)
PVStructurePtr pvStructure
= static_pointer_cast<PVStructure>(fieldToClone);
StringArray const & fieldNames = pvStructure->getStructure()->getFieldNames();
PVFieldPtrArray pvFieldPtrArray = pvStructure->getPVFields();
PVFieldPtrArray const & pvFieldPtrArray = pvStructure->getPVFields();
return createPVStructure(fieldNames,pvFieldPtrArray);
}
case structureArray:
@@ -482,7 +417,7 @@ PVFieldPtr PVDataCreate::createPVField(PVFieldPtr const & fieldToClone)
StructureArrayConstPtr structureArray = from->getStructureArray();
PVStructureArrayPtr to = createPVStructureArray(
structureArray);
getConvert()->copyStructureArray(from, to);
to->copyUnchecked(*from);
return to;
}
case union_:
@@ -497,7 +432,7 @@ PVFieldPtr PVDataCreate::createPVField(PVFieldPtr const & fieldToClone)
= static_pointer_cast<PVUnionArray>(fieldToClone);
UnionArrayConstPtr unionArray = from->getUnionArray();
PVUnionArrayPtr to = createPVUnionArray(unionArray);
getConvert()->copyUnionArray(from, to);
to->copyUnchecked(*from);
return to;
}
}
@@ -509,29 +444,29 @@ PVScalarPtr PVDataCreate::createPVScalar(ScalarConstPtr const & scalar)
ScalarType scalarType = scalar->getScalarType();
switch(scalarType) {
case pvBoolean:
return PVScalarPtr(new BasePVBoolean(scalar));
return PVScalarPtr(new PVBoolean(scalar));
case pvByte:
return PVScalarPtr(new BasePVByte(scalar));
return PVScalarPtr(new PVByte(scalar));
case pvShort:
return PVScalarPtr(new BasePVShort(scalar));
return PVScalarPtr(new PVShort(scalar));
case pvInt:
return PVScalarPtr(new BasePVInt(scalar));
return PVScalarPtr(new PVInt(scalar));
case pvLong:
return PVScalarPtr(new BasePVLong(scalar));
return PVScalarPtr(new PVLong(scalar));
case pvUByte:
return PVScalarPtr(new BasePVUByte(scalar));
return PVScalarPtr(new PVUByte(scalar));
case pvUShort:
return PVScalarPtr(new BasePVUShort(scalar));
return PVScalarPtr(new PVUShort(scalar));
case pvUInt:
return PVScalarPtr(new BasePVUInt(scalar));
return PVScalarPtr(new PVUInt(scalar));
case pvULong:
return PVScalarPtr(new BasePVULong(scalar));
return PVScalarPtr(new PVULong(scalar));
case pvFloat:
return PVScalarPtr(new BasePVFloat(scalar));
return PVScalarPtr(new PVFloat(scalar));
case pvDouble:
return PVScalarPtr(new BasePVDouble(scalar));
return PVScalarPtr(new PVDouble(scalar));
case pvString:
return PVScalarPtr(new BasePVString(scalar));
return PVScalarPtr(new PVString(scalar));
}
throw std::logic_error("PVDataCreate::createPVScalar should never get here");
}
@@ -547,17 +482,7 @@ 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);
}
pvScalar->copyUnchecked(*scalarToClone);
return pvScalar;
}
@@ -566,29 +491,29 @@ PVScalarArrayPtr PVDataCreate::createPVScalarArray(
{
switch(scalarArray->getElementType()) {
case pvBoolean:
return PVScalarArrayPtr(new DefaultPVBooleanArray(scalarArray));
return PVScalarArrayPtr(new PVBooleanArray(scalarArray));
case pvByte:
return PVScalarArrayPtr(new BasePVByteArray(scalarArray));
return PVScalarArrayPtr(new PVByteArray(scalarArray));
case pvShort:
return PVScalarArrayPtr(new BasePVShortArray(scalarArray));
return PVScalarArrayPtr(new PVShortArray(scalarArray));
case pvInt:
return PVScalarArrayPtr(new BasePVIntArray(scalarArray));
return PVScalarArrayPtr(new PVIntArray(scalarArray));
case pvLong:
return PVScalarArrayPtr(new BasePVLongArray(scalarArray));
return PVScalarArrayPtr(new PVLongArray(scalarArray));
case pvUByte:
return PVScalarArrayPtr(new BasePVUByteArray(scalarArray));
return PVScalarArrayPtr(new PVUByteArray(scalarArray));
case pvUShort:
return PVScalarArrayPtr(new BasePVUShortArray(scalarArray));
return PVScalarArrayPtr(new PVUShortArray(scalarArray));
case pvUInt:
return PVScalarArrayPtr(new BasePVUIntArray(scalarArray));
return PVScalarArrayPtr(new PVUIntArray(scalarArray));
case pvULong:
return PVScalarArrayPtr(new BasePVULongArray(scalarArray));
return PVScalarArrayPtr(new PVULongArray(scalarArray));
case pvFloat:
return PVScalarArrayPtr(new BasePVFloatArray(scalarArray));
return PVScalarArrayPtr(new PVFloatArray(scalarArray));
case pvDouble:
return PVScalarArrayPtr(new BasePVDoubleArray(scalarArray));
return PVScalarArrayPtr(new PVDoubleArray(scalarArray));
case pvString:
return PVScalarArrayPtr(new BasePVStringArray(scalarArray));
return PVScalarArrayPtr(new PVStringArray(scalarArray));
}
throw std::logic_error("PVDataCreate::createPVScalarArray should never get here");
@@ -607,16 +532,6 @@ PVScalarArrayPtr PVDataCreate::createPVScalarArray(
PVScalarArrayPtr pvArray = createPVScalarArray(
arrayToClone->getScalarArray()->getElementType());
pvArray->assign(*arrayToClone.get());
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);
}
return pvArray;
}
@@ -668,7 +583,7 @@ PVStructurePtr PVDataCreate::createPVStructure(
PVStructurePtr PVDataCreate::createPVStructure(PVStructurePtr const & structToClone)
{
FieldConstPtrArray field;
if(structToClone==0) {
if(!structToClone) {
// is this correct?!
FieldConstPtrArray fields(0);
StringArray fieldNames(0);
@@ -677,7 +592,7 @@ PVStructurePtr PVDataCreate::createPVStructure(PVStructurePtr const & structToCl
}
StructureConstPtr structure = structToClone->getStructure();
PVStructurePtr pvStructure(new PVStructure(structure));
getConvert()->copyStructure(structToClone,pvStructure);
pvStructure->copyUnchecked(*structToClone);
return pvStructure;
}
@@ -691,18 +606,41 @@ PVUnionPtr PVDataCreate::createPVUnion(PVUnionPtr const & unionToClone)
// TODO not thread-safe (local static initializers)
// TODO replace with non-locking singleton pattern
PVDataCreatePtr PVDataCreate::getPVDataCreate()
const PVDataCreatePtr& PVDataCreate::getPVDataCreate()
{
static PVDataCreatePtr pvDataCreate;
static Mutex mutex;
Lock xx(mutex);
if(pvDataCreate.get()==0) pvDataCreate = PVDataCreatePtr(new PVDataCreate());
if(pvDataCreate.get()==0) {
registerRefCounter("PVField", &PVField::num_instances);
pvDataCreate = PVDataCreatePtr(new PVDataCreate());
}
return pvDataCreate;
}
PVDataCreatePtr getPVDataCreate() {
return PVDataCreate::getPVDataCreate();
// explicitly instanciate to ensure that windows
// builds emit exported symbols for inline'd methods
template class PVScalarValue<boolean>;
template class PVScalarValue<int8>;
template class PVScalarValue<uint8>;
template class PVScalarValue<int16>;
template class PVScalarValue<uint16>;
template class PVScalarValue<int32>;
template class PVScalarValue<uint32>;
template class PVScalarValue<int64>;
template class PVScalarValue<uint64>;
template class PVScalarValue<float>;
template class PVScalarValue<double>;
template class PVScalarValue<std::string>;
}} // namespace epics::pvData
namespace std{
std::ostream& operator<<(std::ostream& o, const epics::pvData::PVField *ptr)
{
if(ptr) return o << *ptr;
return o << "nullptr";
}
}
}}

View File

@@ -1,8 +1,7 @@
/*PVField.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.
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author mrk
@@ -12,72 +11,35 @@
#include <string>
#include <cstdio>
#include <epicsMutex.h>
#define epicsExportSharedSymbols
#include <pv/lock.h>
#include <pv/pvData.h>
#include <pv/factory.h>
#include <pv/convert.h>
#include <pv/reftrack.h>
using std::tr1::const_pointer_cast;
using std::size_t;
using std::string;
namespace epics { namespace pvData {
size_t PVField::num_instances;
PVField::PVField(FieldConstPtr field)
: notImplemented("not implemented"),
parent(NULL),field(field),
: parent(NULL),field(field),
fieldOffset(0), nextFieldOffset(0),
immutable(false)
{
REFTRACE_INCREMENT(num_instances);
}
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());
}
REFTRACE_DECREMENT(num_instances);
}
void PVField::message(String message,MessageType messageType)
{
PVField::message(message,messageType,"");
}
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
{
@@ -97,61 +59,9 @@ 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;}
void PVField::setImmutable() {immutable = true;}
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.get()!=NULL) postHandler->postPut();
@@ -168,7 +78,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;
@@ -179,68 +89,19 @@ bool PVField::equals(PVField &pv)
return pv==*this;
}
void PVField::toString(StringBuilder buf)
{
toString(buf,0);
}
void PVField::toString(StringBuilder buf,int indentLevel)
{
Convert().getString(buf,this,indentLevel);
if(pvAuxInfo.get()!=NULL) pvAuxInfo->toString(buf,indentLevel);
}
std::ostream& operator<<(std::ostream& o, const PVField& f)
{
std::ostream& ro = f.dumpValue(o);
// TODO I do not want to call getPVAuxInfo() since it lazily creates a new instance of it
//if (f.pvAuxInfo.get()!=NULL) ro << *(f.pvAuxInfo.get());
return ro;
return f.dumpValue(o);
};
namespace format
string PVField::getFullName() const
{
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 << std::string(spaces, ' ');
}
array_at_internal operator<<(std::ostream& str, array_at const& manip)
{
return array_at_internal(manip.index, str);
}
};
String PVField::getFullName() const
{
size_t size=fieldName.size();
for(PVField *fld=getParent(); fld; fld=fld->getParent())
string ret(fieldName);
for(const PVField *fld=getParent(); fld; fld=fld->getParent())
{
size+=fld->fieldName.size()+1;
if(fld->getFieldName().size()==0) break;
ret = fld->getFieldName() + '.' + ret;
}
String ret(size, '.');
size_t pos=size - fieldName.size();
ret.replace(pos, String::npos, fieldName);
for(PVField *fld=getParent(); fld; fld=fld->getParent())
{
const String& nref = fld->fieldName;
assert(pos >= nref.size()+1);
pos -= nref.size()+1;
ret.replace(pos, String::npos, nref);
}
assert(pos==0);
return ret;
}
@@ -259,7 +120,7 @@ void PVField::computeOffset(const PVField * pvField) {
}
size_t offset = 0;
size_t nextOffset = 1;
PVFieldPtrArray pvFields = pvTop->getPVFields();
const PVFieldPtrArray & pvFields = pvTop->getPVFields();
for(size_t i=0; i < pvTop->getStructure()->getNumberFields(); i++) {
offset = nextOffset;
PVField *pvField = pvFields[i].get();
@@ -291,7 +152,7 @@ void PVField::computeOffset(const PVField * pvField,size_t offset) {
size_t beginOffset = offset;
size_t nextOffset = offset + 1;
const PVStructure *pvStructure = static_cast<const PVStructure *>(pvField);
const PVFieldPtrArray pvFields = pvStructure->getPVFields();
const PVFieldPtrArray & pvFields = pvStructure->getPVFields();
for(size_t i=0; i < pvStructure->getStructure()->getNumberFields(); i++) {
offset = nextOffset;
PVField *pvSubField = pvFields[i].get();
@@ -318,4 +179,117 @@ void PVField::computeOffset(const PVField * pvField,size_t offset) {
xxx->nextFieldOffset = nextOffset;
}
void PVField::copy(const PVField& from)
{
if(isImmutable())
throw std::invalid_argument("destination is immutable");
if (getField()->getType() != from.getField()->getType())
throw std::invalid_argument("field types do not match");
switch(getField()->getType())
{
case scalar:
{
const PVScalar* fromS = static_cast<const PVScalar*>(&from);
PVScalar* toS = static_cast<PVScalar*>(this);
toS->copy(*fromS);
break;
}
case scalarArray:
{
const PVScalarArray* fromS = static_cast<const PVScalarArray*>(&from);
PVScalarArray* toS = static_cast<PVScalarArray*>(this);
toS->copy(*fromS);
break;
}
case structure:
{
const PVStructure* fromS = static_cast<const PVStructure*>(&from);
PVStructure* toS = static_cast<PVStructure*>(this);
toS->copy(*fromS);
break;
}
case structureArray:
{
const PVStructureArray* fromS = static_cast<const PVStructureArray*>(&from);
PVStructureArray* toS = static_cast<PVStructureArray*>(this);
toS->copy(*fromS);
break;
}
case union_:
{
const PVUnion* fromS = static_cast<const PVUnion*>(&from);
PVUnion* toS = static_cast<PVUnion*>(this);
toS->copy(*fromS);
break;
}
case unionArray:
{
const PVUnionArray* fromS = static_cast<const PVUnionArray*>(&from);
PVUnionArray* toS = static_cast<PVUnionArray*>(this);
toS->copy(*fromS);
break;
}
default:
{
throw std::logic_error("PVField::copy unknown type");
}
}
}
void PVField::copyUnchecked(const PVField& from)
{
switch(getField()->getType())
{
case scalar:
{
const PVScalar* fromS = static_cast<const PVScalar*>(&from);
PVScalar* toS = static_cast<PVScalar*>(this);
toS->copyUnchecked(*fromS);
break;
}
case scalarArray:
{
const PVScalarArray* fromS = static_cast<const PVScalarArray*>(&from);
PVScalarArray* toS = static_cast<PVScalarArray*>(this);
toS->copyUnchecked(*fromS);
break;
}
case structure:
{
const PVStructure* fromS = static_cast<const PVStructure*>(&from);
PVStructure* toS = static_cast<PVStructure*>(this);
toS->copyUnchecked(*fromS);
break;
}
case structureArray:
{
const PVStructureArray* fromS = static_cast<const PVStructureArray*>(&from);
PVStructureArray* toS = static_cast<PVStructureArray*>(this);
toS->copyUnchecked(*fromS);
break;
}
case union_:
{
const PVUnion* fromS = static_cast<const PVUnion*>(&from);
PVUnion* toS = static_cast<PVUnion*>(this);
toS->copyUnchecked(*fromS);
break;
}
case unionArray:
{
const PVUnionArray* fromS = static_cast<const PVUnionArray*>(&from);
PVUnionArray* toS = static_cast<PVUnionArray*>(this);
toS->copyUnchecked(*fromS);
break;
}
default:
{
throw std::logic_error("PVField::copy unknown type");
}
}
}
}}

View File

@@ -1,8 +1,7 @@
/*PVScalar.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.
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author mrk
@@ -29,16 +28,4 @@ namespace epics { namespace pvData {
{
return static_pointer_cast<const Scalar>(PVField::getField());
}
template<>
std::ostream& PVScalarValue<int8>::dumpValue(std::ostream& o) const
{
return o << static_cast<int>(get());
}
template<>
std::ostream& PVScalarValue<uint8>::dumpValue(std::ostream& o) const
{
return o << static_cast<unsigned int>(get());
}
}}

View File

@@ -1,8 +1,7 @@
/*PVScalarArray.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.
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author mrk

View File

@@ -1,8 +1,7 @@
/*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.
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author mrk
@@ -16,51 +15,27 @@
#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);
FieldConstPtrArray const & fields = structurePtr->getFields();
StringArray const & fieldNames = structurePtr->getFieldNames();
pvFields.reserve(numberFields);
PVDataCreatePtr pvDataCreate = getPVDataCreate();
for(size_t i=0; i<numberFields; i++) {
pvFields.push_back(pvDataCreate->createPVField(fields[i]));
pvFields.push_back(pvDataCreate->createPVField(fields[i]));
}
for(size_t i=0; i<numberFields; i++) {
pvFields[i]->setParentAndName(this,fieldNames[i]);
@@ -75,7 +50,7 @@ PVStructure::PVStructure(StructureConstPtr const & structurePtr,
extendsStructureName("")
{
size_t numberFields = structurePtr->getNumberFields();
StringArray fieldNames = structurePtr->getFieldNames();
StringArray const & fieldNames = structurePtr->getFieldNames();
pvFields.reserve(numberFields);
for(size_t i=0; i<numberFields; i++) {
pvFields.push_back(pvs[i]);
@@ -99,7 +74,7 @@ void PVStructure::setImmutable()
PVField::setImmutable();
}
StructureConstPtr PVStructure::getStructure() const
const StructureConstPtr& PVStructure::getStructure() const
{
return structurePtr;
}
@@ -109,249 +84,147 @@ const PVFieldPtrArray & PVStructure::getPVFields() const
return pvFields;
}
PVFieldPtr PVStructure::getSubField(String const &fieldName) const
PVFieldPtr PVStructure::getSubFieldImpl(size_t fieldOffset, bool throws) const
{
return findSubField(fieldName,this);
}
const PVStructure *current = 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);
recurse:
// we don't permit self lookup
if(fieldOffset<=current->getFieldOffset() || fieldOffset>=current->getNextFieldOffset()) {
if(throws) {
std::stringstream ss;
ss << "Failed to get field with offset "
<< fieldOffset << " (Invalid offset)" ;
throw std::runtime_error(ss.str());
} else {
return PVFieldPtr();
}
}
for(size_t i=0, numFields = current->pvFields.size(); i<numFields; i++) {
const PVFieldPtr& pvField = current->pvFields[i];
if(pvField->getFieldOffset()==fieldOffset) {
return pvField;
} else if(pvField->getNextFieldOffset()<=fieldOffset) {
continue;
} else if(pvField->getField()->getType()==structure) {
current = static_cast<PVStructure *>(pvField.get());
goto recurse;
}
}
// the first test against current->getNextFieldOffset() would avoid this
throw std::logic_error("PVStructure.getSubField: Logic error");
}
void PVStructure::fixParentStructure()
PVFieldPtr PVStructure::getSubFieldImpl(const char *name, bool throws) const
{
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;
const PVStructure *parent = this;
if(!name)
{
if (throws)
throw std::invalid_argument("Failed to get field: (Field name is NULL string)");
else
return PVFieldPtr();
}
const char *fullName = name;
while(true) {
const char *sep=name;
while(*sep!='\0' && *sep!='.' && *sep!=' ') sep++;
if(*sep==' ')
{
if (throws)
{
std::stringstream ss;
ss << "Failed to get field: " << fullName
<< " (No spaces allowed in field name)";
throw std::runtime_error(ss.str());
}
else
return PVFieldPtr();
}
size_t N = sep-name;
if(N==0)
{
if (throws)
{
std::stringstream ss;
ss << "Failed to get field: " << fullName
<< " (Zero-length field name encountered)";
throw std::runtime_error(ss.str());
}
else
return PVFieldPtr();
}
const PVFieldPtrArray& pvFields = parent->getPVFields();
PVField *child = NULL;
for(size_t i=0, n=pvFields.size(); i!=n; i++) {
const PVFieldPtr& fld = pvFields[i];
const std::string& fname = fld->getFieldName();
if(fname.size()==N && memcmp(name, fname.c_str(), N)==0) {
child = fld.get();
break;
}
}
if(!child)
{
if (throws)
{
std::stringstream ss;
ss << "Failed to get field: " << fullName << " ("
<< std::string(fullName, sep) << " not found)";
throw std::runtime_error(ss.str());
}
else
return PVFieldPtr();
}
if(*sep) {
// this is not the requested leaf
parent = dynamic_cast<PVStructure*>(child);
if(!parent)
{
if (throws)
{
std::stringstream ss;
ss << "Failed to get field: " << fullName
<< " (" << std::string(fullName, sep)
<< " is not a structure)";
throw std::runtime_error(ss.str());
}
else
return PVFieldPtr();
}
child = NULL;
name = sep+1; // skip past '.'
// loop around to new parent
} else {
fields[i] = oldFields[i];
return child->shared_from_this();
}
}
FieldConstPtr field = getFieldCreate()->createStructure(
parentStructure->getID(),fieldNames,fields);
parent->replaceField(field);
parent->fixParentStructure();
}
void PVStructure::appendPVField(
String const &fieldName,
PVFieldPtr const & pvField)
void PVStructure::throwBadFieldType(const char *name)
{
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();
std::ostringstream ss;
ss << "Failed to get field: " << name << " (Field has wrong type)";
throw std::runtime_error(ss.str());
}
void PVStructure::appendPVFields(
StringArray const & fieldNames,
PVFieldPtrArray const & pvFields)
void PVStructure::throwBadFieldType(std::size_t fieldOffset)
{
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) {
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)
{
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);
}
String PVStructure::getExtendsStructureName() const
{
return extendsStructureName;
}
bool PVStructure::putExtendsStructureName(
String const &xxx)
{
if(extendsStructureName.length()!=0) return false;
extendsStructureName = xxx;
return true;
std::stringstream ss;
ss << "Failed to get field with offset "
<< fieldOffset << " (Field has wrong type)";
throw std::runtime_error(ss.str());
}
void PVStructure::serialize(ByteBuffer *pbuffer,
@@ -371,9 +244,8 @@ void PVStructure::deserialize(ByteBuffer *pbuffer,
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();
size_t numberFields = this->getNumberFields();
size_t offset = this->getFieldOffset();
int32 next = pbitSet->nextSetBit(static_cast<uint32>(offset));
// no more changes or no changes in this structure
@@ -387,7 +259,7 @@ void PVStructure::serialize(ByteBuffer *pbuffer,
size_t fieldsSize = pvFields.size();
for(size_t i = 0; i<fieldsSize; i++) {
PVFieldPtr pvField = pvFields[i];
PVField* pvField = pvFields[i].get();
offset = pvField->getFieldOffset();
int32 inumberFields = static_cast<int32>(pvField->getNumberFields());
next = pbitSet->nextSetBit(static_cast<uint32>(offset));
@@ -401,8 +273,7 @@ void PVStructure::serialize(ByteBuffer *pbuffer,
if(inumberFields==1) {
pvField->serialize(pbuffer, pflusher);
} else {
PVStructurePtr pvStructure = std::tr1::static_pointer_cast<PVStructure>(pvField);
pvStructure->serialize(pbuffer, pflusher, pbitSet);
static_cast<PVStructure*>(pvField)->serialize(pbuffer, pflusher, pbitSet);
}
}
}
@@ -443,44 +314,9 @@ void PVStructure::deserialize(ByteBuffer *pbuffer,
}
}
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();
String extendsName = getExtendsStructureName();
if(extendsName.length()>0) {
o << " extends " << extendsName;
}
o << std::endl;
{
format::indent_scope s(o);
@@ -501,4 +337,79 @@ std::ostream& PVStructure::dumpValue(std::ostream& o) const
return o;
}
void PVStructure::copy(const PVStructure& from)
{
if(isImmutable())
throw std::invalid_argument("destination is immutable");
if(*getStructure() != *from.getStructure())
throw std::invalid_argument("structure definitions do not match");
copyUnchecked(from);
}
void PVStructure::copyUnchecked(const PVStructure& from)
{
if (this == &from)
return;
PVFieldPtrArray const & fromPVFields = from.getPVFields();
PVFieldPtrArray const & toPVFields = getPVFields();
size_t fieldsSize = fromPVFields.size();
for(size_t i = 0; i<fieldsSize; i++) {
toPVFields[i]->copyUnchecked(*fromPVFields[i]);
}
}
void PVStructure::copyUnchecked(const PVStructure& from, const BitSet& maskBitSet, bool inverse)
{
if (this == &from)
return;
size_t numberFields = from.getNumberFields();
size_t offset = from.getFieldOffset();
int32 next = inverse ?
maskBitSet.nextClearBit(static_cast<uint32>(offset)) :
maskBitSet.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) {
copyUnchecked(from);
return;
}
PVFieldPtrArray const & fromPVFields = from.getPVFields();
PVFieldPtrArray const & toPVFields = getPVFields();
size_t fieldsSize = fromPVFields.size();
for(size_t i = 0; i<fieldsSize; i++) {
PVFieldPtr pvField = fromPVFields[i];
offset = pvField->getFieldOffset();
int32 inumberFields = static_cast<int32>(pvField->getNumberFields());
next = inverse ?
maskBitSet.nextClearBit(static_cast<uint32>(offset)) :
maskBitSet.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) {
toPVFields[i]->copyUnchecked(*pvField);
} else {
PVStructure::shared_pointer fromPVStructure = std::tr1::static_pointer_cast<PVStructure>(pvField);
PVStructure::shared_pointer toPVStructure = std::tr1::static_pointer_cast<PVStructure>(toPVFields[i]);
toPVStructure->copyUnchecked(*fromPVStructure, maskBitSet, inverse);
}
}
}
}}

View File

@@ -1,8 +1,7 @@
/*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.
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author mrk
@@ -14,7 +13,6 @@
#define epicsExportSharedSymbols
#include <pv/pvData.h>
#include <pv/convert.h>
#include <pv/factory.h>
#include <pv/serializeHelper.h>
@@ -25,6 +23,8 @@ namespace epics { namespace pvData {
size_t PVStructureArray::append(size_t number)
{
checkLength(value.size()+number);
svector data(reuse());
data.resize(data.size()+number);
@@ -44,9 +44,11 @@ size_t PVStructureArray::append(size_t number)
bool PVStructureArray::remove(size_t offset,size_t number)
{
if(number==0)
if (number==0)
return true;
else if(offset+number>getLength())
else if (offset+number>getLength())
return false;
else if (getArray()->getArraySizeType() == Array::fixed)
return false;
svector vec(reuse());
@@ -65,6 +67,9 @@ bool PVStructureArray::remove(size_t offset,size_t number)
}
void PVStructureArray::compress() {
if (getArray()->getArraySizeType() == Array::fixed)
return;
svector vec(reuse()); // TODO: check for first NULL before realloc
size_t length = vec.size();
@@ -99,7 +104,8 @@ void PVStructureArray::compress() {
void PVStructureArray::setCapacity(size_t capacity)
{
if(this->isCapacityMutable()) {
if (this->isCapacityMutable()) {
checkLength(capacity);
const_svector value;
swap(value);
if(value.capacity()<capacity) {
@@ -109,17 +115,23 @@ void PVStructureArray::setCapacity(size_t capacity)
}
swap(value);
}
else
THROW_EXCEPTION2(std::logic_error, "capacity immutable");
}
void PVStructureArray::setLength(size_t length)
{
if(this->isImmutable())
THROW_EXCEPTION2(std::logic_error,"Immutable");
THROW_EXCEPTION2(std::logic_error, "immutable");
const_svector value;
swap(value);
if(length == value.size()) {
// nothing
} else if(length < value.size()) {
if (length == value.size())
return;
checkLength(length);
if (length < value.size()) {
value.slice(0, length);
} else {
svector mvalue(thaw(value));
@@ -131,8 +143,10 @@ void PVStructureArray::setLength(size_t length)
void PVStructureArray::swap(const_svector &other)
{
if(this->isImmutable())
THROW_EXCEPTION2(std::logic_error,"Immutable");
if (this->isImmutable())
THROW_EXCEPTION2(std::logic_error, "immutable");
// no checkLength call here
value.swap(other);
}
@@ -146,7 +160,10 @@ void PVStructureArray::deserialize(ByteBuffer *pbuffer,
DeserializableControl *pcontrol) {
svector data(reuse());
size_t size = SerializeHelper::readSize(pbuffer, pcontrol);
size_t size = this->getArray()->getArraySizeType() == Array::fixed ?
this->getArray()->getMaximumCapacity() :
SerializeHelper::readSize(pbuffer, pcontrol);
data.resize(size);
StructureConstPtr structure = structureArray->getStructure();
@@ -160,7 +177,7 @@ void PVStructureArray::deserialize(ByteBuffer *pbuffer,
data[i].reset();
}
else {
if(data[i].get()==NULL) {
if(data[i].get()==NULL || !data[i].unique()) {
data[i] = pvDataCreate->createPVStructure(structure);
}
data[i]->deserialize(pbuffer, pcontrol);
@@ -175,7 +192,11 @@ void PVStructureArray::serialize(ByteBuffer *pbuffer,
const_svector temp(view());
temp.slice(offset, count);
SerializeHelper::writeSize(temp.size(), pbuffer, pflusher);
ArrayConstPtr array = this->getArray();
if (array->getArraySizeType() != Array::fixed)
SerializeHelper::writeSize(temp.size(), pbuffer, pflusher);
else if (count != array->getMaximumCapacity())
throw std::length_error("fixed array cannot be partially serialized");
for(size_t i = 0; i<count; i++) {
if(pbuffer->getRemaining()<1)
@@ -209,9 +230,33 @@ std::ostream& PVStructureArray::dumpValue(std::ostream& o) const
std::ostream& PVStructureArray::dumpValue(std::ostream& o, std::size_t index) const
{
const_svector temp(view());
if(index<temp.size())
o << *temp[index];
if (index<temp.size())
{
if (temp[index])
o << *temp[index];
else
o << format::indent() << "(none)" << std::endl;
}
return o;
}
void PVStructureArray::copy(const PVStructureArray& from)
{
if(isImmutable())
throw std::invalid_argument("destination is immutable");
if(*getStructureArray() != *from.getStructureArray())
throw std::invalid_argument("structureArray definitions do not match");
copyUnchecked(from);
}
void PVStructureArray::copyUnchecked(const PVStructureArray& from)
{
if (this == &from)
return;
replace(from.view());
}
}}

View File

@@ -1,8 +1,7 @@
/*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.
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author mse
@@ -16,17 +15,19 @@
#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;
const int32 PVUnion::UNDEFINED_INDEX = PVUNION_UNDEFINED_INDEX;
PVDataCreatePtr PVUnion::pvDataCreate(getPVDataCreate());
PVUnion::PVUnion(UnionConstPtr const & unionPtr)
: PVField(unionPtr),
@@ -39,38 +40,24 @@ PVUnion::PVUnion(UnionConstPtr const & unionPtr)
#undef PVUNION_UNDEFINED_INDEX
PVUnion::~PVUnion()
{
}
PVUnion::~PVUnion() {}
UnionConstPtr PVUnion::getUnion() const
{
return unionPtr;
}
PVFieldPtr PVUnion::get() const
{
return value;
}
int32 PVUnion::getSelectedIndex() const
{
return selector;
}
String PVUnion::getSelectedFieldName() const
string PVUnion::getSelectedFieldName() const
{
// no name for undefined and for variant unions
if (selector == UNDEFINED_INDEX)
return String();
return string();
else
return unionPtr->getFieldName(selector);
}
PVFieldPtr PVUnion::select(int32 index)
{
if (variant && index != UNDEFINED_INDEX)
throw std::invalid_argument("index out of bounds");
// no change
if (selector == index)
if (selector == index && !variant)
return value;
if (index == UNDEFINED_INDEX)
@@ -79,30 +66,23 @@ PVFieldPtr PVUnion::select(int32 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()))
else if (index < 0 || size_t(index) >= unionPtr->getFields().size())
throw std::invalid_argument("index out of bounds");
FieldConstPtr field = unionPtr->getField(index);
selector = index;
value = getPVDataCreate()->createPVField(field);
value = pvDataCreate->createPVField(field);
return value;
}
PVFieldPtr PVUnion::select(String const & fieldName)
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)
{
@@ -113,28 +93,29 @@ void PVUnion::set(int32 index, PVFieldPtr const & value)
if (index == UNDEFINED_INDEX)
{
// for undefined index we accept only null values
if (value.get())
if (value)
throw std::invalid_argument("non-null value for index == UNDEFINED_INDEX");
}
else if (index < 0 || index > static_cast<int32>(unionPtr->getFields().size()))
else if (index < 0 || size_t(index) >= unionPtr->getFields().size())
throw std::invalid_argument("index out of bounds");
// value type must match
if (value->getField() != unionPtr->getField(index))
else if (!value)
throw std::invalid_argument("Can't set defined index w/ NULL");
else 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)
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);
set(index, value);
}
void PVUnion::serialize(ByteBuffer *pbuffer, SerializableControl *pflusher) const
@@ -142,10 +123,10 @@ void PVUnion::serialize(ByteBuffer *pbuffer, SerializableControl *pflusher) cons
if (variant)
{
// write introspection data
if (value.get() == 0)
if (value.get() == 0) {
pflusher->ensureBuffer(1);
pbuffer->put((int8)-1);
else
{
}else {
pflusher->cachedSerialize(value->getField(), pbuffer);
value->serialize(pbuffer, pflusher);
}
@@ -167,7 +148,9 @@ void PVUnion::deserialize(ByteBuffer *pbuffer, DeserializableControl *pcontrol)
FieldConstPtr field = pcontrol->cachedDeserialize(pbuffer);
if (field.get())
{
value = getPVDataCreate()->createPVField(field);
// try to reuse existing field instance
if (!value.get() || *value->getField() != *field)
value = pvDataCreate->createPVField(field);
value->deserialize(pbuffer, pcontrol);
}
else
@@ -175,11 +158,17 @@ void PVUnion::deserialize(ByteBuffer *pbuffer, DeserializableControl *pcontrol)
}
else
{
int32 previousSelector = selector;
selector = static_cast<int32>(SerializeHelper::readSize(pbuffer, pcontrol));
if (selector != UNDEFINED_INDEX)
{
FieldConstPtr field = unionPtr->getField(selector);
value = getPVDataCreate()->createPVField(field);
if (selector != previousSelector)
{
FieldConstPtr field = unionPtr->getField(selector);
// try to reuse existing field instance
if (!value.get() || *value->getField() != *field)
value = pvDataCreate->createPVField(field);
}
value->deserialize(pbuffer, pcontrol);
}
else
@@ -192,7 +181,7 @@ std::ostream& PVUnion::dumpValue(std::ostream& o) const
o << format::indent() << getUnion()->getID() << ' ' << getFieldName() << std::endl;
{
format::indent_scope s(o);
PVFieldPtr fieldField = get();
const PVField::const_shared_pointer& fieldField = get();
if (fieldField.get() == NULL)
o << format::indent() << "(none)" << std::endl;
else
@@ -207,4 +196,57 @@ std::ostream& PVUnion::dumpValue(std::ostream& o) const
return o;
}
void PVUnion::copy(const PVUnion& from)
{
if(isImmutable())
throw std::invalid_argument("destination is immutable");
if(*getUnion() != *from.getUnion())
throw std::invalid_argument("union definitions do not match");
copyUnchecked(from);
}
void PVUnion::copyUnchecked(const PVUnion& from)
{
const PVField::const_shared_pointer& fromValue = from.get();
if (from.getUnion()->isVariant())
{
if (fromValue.get() == 0)
{
set(PVField::shared_pointer());
}
else
{
PVFieldPtr toValue = get();
if (toValue.get() == 0 || *toValue->getField() != *fromValue->getField())
{
toValue = pvDataCreate->createPVField(fromValue->getField());
toValue->copyUnchecked(*fromValue);
set(toValue);
}
else
{
toValue->copyUnchecked(*fromValue);
postPut();
}
}
}
else
{
if (fromValue.get() == 0)
{
select(PVUnion::UNDEFINED_INDEX);
}
else
{
select(from.getSelectedIndex())->copyUnchecked(*fromValue);
}
postPut();
}
}
}}

View File

@@ -1,8 +1,7 @@
/*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.
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author mrk
@@ -14,7 +13,6 @@
#define epicsExportSharedSymbols
#include <pv/pvData.h>
#include <pv/convert.h>
#include <pv/factory.h>
#include <pv/serializeHelper.h>
@@ -25,6 +23,8 @@ namespace epics { namespace pvData {
size_t PVUnionArray::append(size_t number)
{
checkLength(value.size()+number);
svector data(reuse());
data.resize(data.size()+number);
@@ -44,9 +44,11 @@ size_t PVUnionArray::append(size_t number)
bool PVUnionArray::remove(size_t offset,size_t number)
{
if(number==0)
if (number==0)
return true;
else if(offset+number>getLength())
else if (offset+number>getLength())
return false;
else if (getArray()->getArraySizeType() == Array::fixed)
return false;
svector vec(reuse());
@@ -65,6 +67,9 @@ bool PVUnionArray::remove(size_t offset,size_t number)
}
void PVUnionArray::compress() {
if (getArray()->getArraySizeType() == Array::fixed)
return;
svector vec(reuse()); // TODO: check for first NULL before realloc
size_t length = vec.size();
@@ -100,6 +105,7 @@ void PVUnionArray::compress() {
void PVUnionArray::setCapacity(size_t capacity)
{
if(this->isCapacityMutable()) {
checkLength(capacity);
const_svector value;
swap(value);
if(value.capacity()<capacity) {
@@ -109,17 +115,22 @@ void PVUnionArray::setCapacity(size_t capacity)
}
swap(value);
}
else
THROW_EXCEPTION2(std::logic_error, "capacity immutable");
}
void PVUnionArray::setLength(size_t length)
{
if(this->isImmutable())
THROW_EXCEPTION2(std::logic_error,"Immutable");
THROW_EXCEPTION2(std::logic_error, "immutable");
const_svector value;
swap(value);
if(length == value.size()) {
// nothing
} else if(length < value.size()) {
if (length == value.size())
return;
checkLength(length);
if (length < value.size()) {
value.slice(0, length);
} else {
svector mvalue(thaw(value));
@@ -134,6 +145,8 @@ void PVUnionArray::swap(const_svector &other)
if(this->isImmutable())
THROW_EXCEPTION2(std::logic_error,"Immutable");
// no checkLength call here
value.swap(other);
}
@@ -146,7 +159,10 @@ void PVUnionArray::deserialize(ByteBuffer *pbuffer,
DeserializableControl *pcontrol) {
svector data(reuse());
size_t size = SerializeHelper::readSize(pbuffer, pcontrol);
size_t size = this->getArray()->getArraySizeType() == Array::fixed ?
this->getArray()->getMaximumCapacity() :
SerializeHelper::readSize(pbuffer, pcontrol);
data.resize(size);
UnionConstPtr punion = unionArray->getUnion();
@@ -160,7 +176,7 @@ void PVUnionArray::deserialize(ByteBuffer *pbuffer,
data[i].reset();
}
else {
if(data[i].get()==NULL) {
if(data[i].get()==NULL || !data[i].unique()) {
data[i] = pvDataCreate->createPVUnion(punion);
}
data[i]->deserialize(pbuffer, pcontrol);
@@ -175,7 +191,11 @@ void PVUnionArray::serialize(ByteBuffer *pbuffer,
const_svector temp(view());
temp.slice(offset, count);
SerializeHelper::writeSize(temp.size(), pbuffer, pflusher);
ArrayConstPtr array = this->getArray();
if (array->getArraySizeType() != Array::fixed)
SerializeHelper::writeSize(temp.size(), pbuffer, pflusher);
else if (count != array->getMaximumCapacity())
throw std::length_error("fixed array cannot be partially serialized");
for(size_t i = 0; i<count; i++) {
if(pbuffer->getRemaining()<1)
@@ -209,9 +229,34 @@ std::ostream& PVUnionArray::dumpValue(std::ostream& o) const
std::ostream& PVUnionArray::dumpValue(std::ostream& o, std::size_t index) const
{
const_svector temp(view());
if(index<temp.size())
o << *temp[index];
if (index<temp.size())
{
if (temp[index])
o << *temp[index];
else
o << format::indent() << "(none)" << std::endl;
}
return o;
}
void PVUnionArray::copy(const PVUnionArray& from)
{
if(isImmutable())
throw std::invalid_argument("destination is immutable");
if(*getUnionArray() != *from.getUnionArray())
throw std::invalid_argument("unionArray definitions do not match");
copyUnchecked(from);
}
void PVUnionArray::copyUnchecked(const PVUnionArray& from)
{
if (this == &from)
return;
replace(from.view());
}
}}

View File

@@ -1,8 +1,7 @@
/* StandardField.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.
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author mrk
@@ -11,12 +10,15 @@
#include <cstdio>
#include <stdexcept>
#include <epicsMutex.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 +51,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,11 +59,11 @@ 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) {
@@ -82,19 +84,19 @@ 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;
}
if(type==structure) {
StructureConstPtr structurePtr = static_pointer_cast<const Structure>(field);
StringArray names = structurePtr->getFieldNames();
StringArray const & names = structurePtr->getFieldNames();
if(names.size()==2) {
FieldConstPtrArray fields = structurePtr->getFields();
FieldConstPtrArray const & 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) {
@@ -112,7 +114,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);
@@ -161,7 +163,7 @@ void StandardField::createTimeStamp() {
FieldConstPtrArray fields(num);
StringArray names(num);
names[0] = "secondsPastEpoch";
names[1] = "nanoSeconds";
names[1] = "nanoseconds";
names[2] = "userTag";
fields[0] = fieldCreate->createScalar(pvLong);
fields[1] = fieldCreate->createScalar(pvInt);
@@ -227,7 +229,7 @@ void StandardField::createByteAlarm() {
names[6] = "lowWarningSeverity";
names[7] = "highWarningSeverity";
names[8] = "highAlarmSeverity";
names[9] = "hystersis";
names[9] = "hysteresis";
fields[0] = fieldCreate->createScalar(pvBoolean);
fields[1] = fieldCreate->createScalar(pvByte);
fields[2] = fieldCreate->createScalar(pvByte);
@@ -254,7 +256,7 @@ void StandardField::createShortAlarm() {
names[6] = "lowWarningSeverity";
names[7] = "highWarningSeverity";
names[8] = "highAlarmSeverity";
names[9] = "hystersis";
names[9] = "hysteresis";
fields[0] = fieldCreate->createScalar(pvBoolean);
fields[1] = fieldCreate->createScalar(pvShort);
fields[2] = fieldCreate->createScalar(pvShort);
@@ -281,7 +283,7 @@ void StandardField::createIntAlarm() {
names[6] = "lowWarningSeverity";
names[7] = "highWarningSeverity";
names[8] = "highAlarmSeverity";
names[9] = "hystersis";
names[9] = "hysteresis";
fields[0] = fieldCreate->createScalar(pvBoolean);
fields[1] = fieldCreate->createScalar(pvInt);
fields[2] = fieldCreate->createScalar(pvInt);
@@ -308,7 +310,7 @@ void StandardField::createLongAlarm() {
names[6] = "lowWarningSeverity";
names[7] = "highWarningSeverity";
names[8] = "highAlarmSeverity";
names[9] = "hystersis";
names[9] = "hysteresis";
fields[0] = fieldCreate->createScalar(pvBoolean);
fields[1] = fieldCreate->createScalar(pvLong);
fields[2] = fieldCreate->createScalar(pvLong);
@@ -335,7 +337,7 @@ void StandardField::createUByteAlarm() {
names[6] = "lowWarningSeverity";
names[7] = "highWarningSeverity";
names[8] = "highAlarmSeverity";
names[9] = "hystersis";
names[9] = "hysteresis";
fields[0] = fieldCreate->createScalar(pvBoolean);
fields[1] = fieldCreate->createScalar(pvUByte);
fields[2] = fieldCreate->createScalar(pvUByte);
@@ -362,7 +364,7 @@ void StandardField::createUShortAlarm() {
names[6] = "lowWarningSeverity";
names[7] = "highWarningSeverity";
names[8] = "highAlarmSeverity";
names[9] = "hystersis";
names[9] = "hysteresis";
fields[0] = fieldCreate->createScalar(pvBoolean);
fields[1] = fieldCreate->createScalar(pvUShort);
fields[2] = fieldCreate->createScalar(pvUShort);
@@ -389,7 +391,7 @@ void StandardField::createUIntAlarm() {
names[6] = "lowWarningSeverity";
names[7] = "highWarningSeverity";
names[8] = "highAlarmSeverity";
names[9] = "hystersis";
names[9] = "hysteresis";
fields[0] = fieldCreate->createScalar(pvBoolean);
fields[1] = fieldCreate->createScalar(pvUInt);
fields[2] = fieldCreate->createScalar(pvUInt);
@@ -416,7 +418,7 @@ void StandardField::createULongAlarm() {
names[6] = "lowWarningSeverity";
names[7] = "highWarningSeverity";
names[8] = "highAlarmSeverity";
names[9] = "hystersis";
names[9] = "hysteresis";
fields[0] = fieldCreate->createScalar(pvBoolean);
fields[1] = fieldCreate->createScalar(pvULong);
fields[2] = fieldCreate->createScalar(pvULong);
@@ -443,7 +445,7 @@ void StandardField::createFloatAlarm() {
names[6] = "lowWarningSeverity";
names[7] = "highWarningSeverity";
names[8] = "highAlarmSeverity";
names[9] = "hystersis";
names[9] = "hysteresis";
fields[0] = fieldCreate->createScalar(pvBoolean);
fields[1] = fieldCreate->createScalar(pvFloat);
fields[2] = fieldCreate->createScalar(pvFloat);
@@ -470,7 +472,7 @@ void StandardField::createDoubleAlarm() {
names[6] = "lowWarningSeverity";
names[7] = "highWarningSeverity";
names[8] = "highAlarmSeverity";
names[9] = "hystersis";
names[9] = "hysteresis";
fields[0] = fieldCreate->createScalar(pvBoolean);
fields[1] = fieldCreate->createScalar(pvDouble);
fields[2] = fieldCreate->createScalar(pvDouble);
@@ -499,26 +501,48 @@ 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);
return createProperties("epics:nt/NTScalar:1.0",field,properties);
}
StructureConstPtr StandardField::regUnion(
UnionConstPtr const &field,
string const & properties)
{
return createProperties("epics:nt/NTUnion:1.0",field,properties);
}
StructureConstPtr StandardField::variantUnion(
string const & properties)
{
UnionConstPtr field = fieldCreate->createVariantUnion();
return createProperties("epics:nt/NTUnion:1.0",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);
return createProperties("epics:nt/NTScalarArray:1.0",field,properties);
}
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("epics:nt/NTStructureArray:1.0",field,properties);
}
StructureConstPtr StandardField::unionArray(
UnionConstPtr const & punion,string const &properties)
{
UnionArrayConstPtr field = fieldCreate->createUnionArray(
punion);
return createProperties("epics:nt/NTUnionArray:1.0",field,properties);
}
StructureConstPtr StandardField::enumerated()
@@ -531,13 +555,13 @@ StructureConstPtr StandardField::enumerated()
fields[0] = fieldCreate->createScalar(pvInt);
fields[1] = fieldCreate->createScalarArray(pvString);
return fieldCreate->createStructure("enum_t",names,fields);
// NOTE: if this method is used to get NTEnum wihtout properties the ID will be wrong!
// NOTE: if this method is used to get NTEnum without 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);
return createProperties("epics:nt/NTEnum:1.0",field,properties);
}
StructureConstPtr StandardField::alarm()
@@ -620,7 +644,7 @@ StructureConstPtr StandardField::enumeratedAlarm()
return enumeratedAlarmField;
}
StandardFieldPtr StandardField::getStandardField()
const StandardFieldPtr &StandardField::getStandardField()
{
static StandardFieldPtr standardFieldCreate;
static Mutex mutex;
@@ -634,10 +658,4 @@ StandardFieldPtr StandardField::getStandardField()
return standardFieldCreate;
}
StandardFieldPtr getStandardField() {
return StandardField::getStandardField();
}
}}

View File

@@ -1,8 +1,7 @@
/* StandardPVField.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.
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author mrk
@@ -10,14 +9,17 @@
#include <string>
#include <stdexcept>
#include <epicsMutex.h>
#define epicsExportSharedSymbols
#include <pv/lock.h>
#include <pv/pvIntrospect.h>
#include <pv/pvData.h>
#include <pv/convert.h>
#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,35 +48,39 @@ 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);
PVStringArray::svector cdata(choices.size());
std::copy(choices.begin(), choices.end(), cdata.begin());
static_cast<PVStringArray&>(*pvScalarArray).replace(freeze(cdata));
pvStructure->getSubFieldT<PVStringArray>("choices")->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);
PVStringArray::svector cdata(choices.size());
std::copy(choices.begin(), choices.end(), cdata.begin());
static_cast<PVStringArray&>(*pvScalarArray).replace(freeze(cdata));
pvStructure->getSubFieldT<PVStringArray>("value.choices")->replace(freeze(cdata));
return pvStructure;
}

View File

@@ -1,8 +1,7 @@
/*TypeFunc.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.
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author mrk
@@ -19,6 +18,8 @@
#include "dbDefs.h" // for NELEMENTS
using std::string;
namespace epics { namespace pvData {
namespace TypeFunc {
@@ -30,11 +31,13 @@ namespace TypeFunc {
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) {
@@ -63,7 +66,7 @@ namespace ScalarTypeFunc {
"ubyte", "ushort", "uint", "ulong",
"float", "double", "string",
};
ScalarType getScalarType(const String& pvalue) {
ScalarType getScalarType(const string& pvalue) {
for(size_t i=0; i<NELEMENTS(names); i++)
if(pvalue==names[i])
return ScalarType(i);
@@ -76,10 +79,6 @@ namespace ScalarTypeFunc {
return names[t];
}
void toString(StringBuilder buf,const ScalarType scalarType) {
*buf += name(scalarType);
}
size_t elementSize(ScalarType id)
{
switch(id) {
@@ -95,7 +94,7 @@ namespace ScalarTypeFunc {
OP(pvLong, int64);
OP(pvFloat, float);
OP(pvDouble, double);
OP(pvString, String);
OP(pvString, string);
#undef OP
default:
THROW_EXCEPTION2(std::invalid_argument, "error unknown ScalarType");
@@ -117,7 +116,7 @@ namespace ScalarTypeFunc {
OP(pvLong, int64);
OP(pvFloat, float);
OP(pvDouble, double);
OP(pvString, String);
OP(pvString, string);
#undef OP
default:
throw std::bad_alloc();
@@ -126,4 +125,9 @@ namespace ScalarTypeFunc {
} // namespace ScalarTypeFunc
std::ostream& operator<<(std::ostream& o, const ScalarType& scalarType)
{
return o << ScalarTypeFunc::name(scalarType);
}
}}

View File

@@ -1,18 +0,0 @@
/*factory.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 FACTORY_H
#define FACTORY_H
namespace epics { namespace pvData {
enum DebugLevel{noDebug,lowDebug,highDebug};
}}
#endif /*FACTORY_H */

View File

@@ -1,270 +1,44 @@
/* 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.
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
#include <deque>
#define epicsExportSharedSymbols
#include <pv/printer.h>
#include <pv/pvIntrospect.h>
namespace {
void indentN(std::ostream& strm, size_t N)
{
while(N--)
strm.put(' ');
}
}
using std::string;
namespace epics { namespace pvData {
PrinterBase::PrinterBase()
:strm(NULL)
{}
PrinterBase::~PrinterBase() {}
void PrinterBase::setStream(std::ostream& s)
namespace format
{
strm = &s;
}
static int indent_index = std::ios_base::xalloc();
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;
}
}
}
long& indent_value(std::ios_base& ios)
{
return ios.iword(indent_index);
}
}
std::ostream& operator<<(std::ostream& os, indent_level const& indent)
{
indent_value(os) = indent.level;
return os;
}
PrinterPlain::PrinterPlain()
:PrinterBase()
,ilvl(0)
{}
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, ' ');
}
PrinterPlain::~PrinterPlain() {}
void PrinterPlain::beginStructure(const PVStructure& pv)
{
indentN(S(), ilvl);
S() << pv.getStructure()->getID() << " " << pv.getFieldName();
String ename(pv.getExtendsStructureName());
if(!ename.empty())
S() << " extends " << ename;
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;
}
array_at_internal operator<<(std::ostream& str, array_at const& manip)
{
return array_at_internal(manip.index, str);
}
};
}}

17
src/factory/pv/factory.h Normal file
View File

@@ -0,0 +1,17 @@
/*factory.h*/
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author mrk
*/
#ifndef FACTORY_H
#define FACTORY_H
namespace epics { namespace pvData {
enum DebugLevel{noDebug,lowDebug,highDebug};
}}
#endif /*FACTORY_H */

View File

@@ -1,7 +1,6 @@
/**
* 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.
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author Marty Kraimer
@@ -14,31 +13,36 @@
#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 len)
size_t toStride,
size_t count)
{
if(pvTo.isImmutable()) {
throw std::logic_error("pvSubArrayCopy to is immutable");
}
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();
if(fromOffset+len>fromLength) {
throw std::length_error("pvSubArrayCopy from length error");
}
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(toOffset+len>capacity) capacity = toOffset + len;
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<toOffset; ++i) temp[i] = vecTo[i];
for(size_t i=0; i<len; ++i) temp[i + toOffset] = vecFrom[i + fromOffset];
for(size_t i=len + toOffset; i<capacity; ++i) temp[i] = vecTo[i];
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);
}
@@ -46,9 +50,11 @@ void copy(
void copy(
PVScalarArray & from,
size_t fromOffset,
size_t fromStride,
PVScalarArray & to,
size_t toOffset,
size_t len)
size_t toStride,
size_t count)
{
ScalarType scalarType = from.getScalarArray()->getElementType();
ScalarType otherType = to.getScalarArray()->getElementType();
@@ -59,145 +65,210 @@ void copy(
{
case pvBoolean:
{
copy(dynamic_cast<PVValueArray<boolean> &>(from),fromOffset,
copy(dynamic_cast<PVValueArray<boolean> &>(from),fromOffset,fromStride,
dynamic_cast<PVValueArray<boolean>& >(to),
toOffset,len);
toOffset,toStride,count);
}
break;
case pvByte:
{
copy(dynamic_cast<PVValueArray<int8> &>(from),fromOffset,
copy(dynamic_cast<PVValueArray<int8> &>(from),fromOffset,fromStride,
dynamic_cast<PVValueArray<int8>& >(to),
toOffset,len);
toOffset,toStride,count);
}
break;
case pvShort:
{
copy(dynamic_cast<PVValueArray<int16> &>(from),fromOffset,
copy(dynamic_cast<PVValueArray<int16> &>(from),fromOffset,fromStride,
dynamic_cast<PVValueArray<int16>& >(to),
toOffset,len);
toOffset,toStride,count);
}
break;
case pvInt:
{
copy(dynamic_cast<PVValueArray<int32> &>(from),fromOffset,
copy(dynamic_cast<PVValueArray<int32> &>(from),fromOffset,fromStride,
dynamic_cast<PVValueArray<int32>& >(to),
toOffset,len);
toOffset,toStride,count);
}
break;
case pvLong:
{
copy(dynamic_cast<PVValueArray<int64> &>(from),fromOffset,
copy(dynamic_cast<PVValueArray<int64> &>(from),fromOffset,fromStride,
dynamic_cast<PVValueArray<int64>& >(to),
toOffset,len);
toOffset,toStride,count);
}
break;
case pvUByte:
{
copy(dynamic_cast<PVValueArray<uint8> &>(from),fromOffset,
copy(dynamic_cast<PVValueArray<uint8> &>(from),fromOffset,fromStride,
dynamic_cast<PVValueArray<uint8>& >(to),
toOffset,len);
toOffset,toStride,count);
}
break;
case pvUShort:
{
copy(dynamic_cast<PVValueArray<uint16> &>(from),fromOffset,
copy(dynamic_cast<PVValueArray<uint16> &>(from),fromOffset,fromStride,
dynamic_cast<PVValueArray<uint16>& >(to),
toOffset,len);
toOffset,toStride,count);
}
break;
case pvUInt:
{
copy(dynamic_cast<PVValueArray<uint32> &>(from),fromOffset,
copy(dynamic_cast<PVValueArray<uint32> &>(from),fromOffset,fromStride,
dynamic_cast<PVValueArray<uint32>& >(to),
toOffset,len);
toOffset,toStride,count);
}
break;
case pvULong:
{
copy(dynamic_cast<PVValueArray<uint64> &>(from),fromOffset,
copy(dynamic_cast<PVValueArray<uint64> &>(from),fromOffset,fromStride,
dynamic_cast<PVValueArray<uint64>& >(to),
toOffset,len);
toOffset,toStride,count);
}
break;
case pvFloat:
{
copy(dynamic_cast<PVValueArray<float> &>(from),fromOffset,
copy(dynamic_cast<PVValueArray<float> &>(from),fromOffset,fromStride,
dynamic_cast<PVValueArray<float>& >(to),
toOffset,len);
toOffset,toStride,count);
}
break;
case pvDouble:
{
copy(dynamic_cast<PVValueArray<double> &>(from),fromOffset,
copy(dynamic_cast<PVValueArray<double> &>(from),fromOffset,fromStride,
dynamic_cast<PVValueArray<double>& >(to),
toOffset,len);
toOffset,toStride,count);
}
break;
case pvString:
{
copy(dynamic_cast<PVValueArray<String> &>(from),fromOffset,
dynamic_cast<PVValueArray<String>& >(to),
toOffset,len);
copy(dynamic_cast<PVValueArray<string> &>(from),fromOffset,fromStride,
dynamic_cast<PVValueArray<string>& >(to),
toOffset,toStride,count);
}
break;
}
}
void copy(
PVStructureArray & from,
size_t fromOffset,
PVStructureArray & to,
PVStructureArray & pvFrom,
size_t pvFromOffset,
size_t pvFromStride,
PVStructureArray & pvTo,
size_t toOffset,
size_t len)
size_t toStride,
size_t count)
{
if(to.isImmutable()) {
throw std::logic_error("pvSubArrayCopy to is immutable");
if(pvTo.isImmutable()) {
throw std::logic_error("pvSubArrayCopy pvTo is immutable");
}
StructureArrayConstPtr fromStructure = from.getStructureArray();
StructureArrayConstPtr toStructure = to.getStructureArray();
if(fromStructure!=toStructure) {
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 to and from have different structures");
"pvSubArrayCopy structureArray pvTo and pvFrom have different structures");
}
size_t fromLength = from.getLength();
if(fromOffset+len>fromLength) {
throw std::length_error("pvSubArrayCopy from length error");
}
size_t capacity = to.getCapacity();
if(toOffset+len>capacity) capacity = toOffset+len;
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 = from.view();
PVValueArray<PVStructurePtr>::const_svector vecTo = to.view();
for(size_t i=0; i<toOffset; ++i) temp[i] = vecTo[i];
for(size_t i=0; i<len; ++i) temp[i + toOffset] = vecFrom[i + fromOffset];
for(size_t i=len + toOffset; i<capacity; ++i) temp[i] = vecTo[i];
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));
to.replace(temp2);
pvTo.replace(temp2);
}
void copy(
PVArray & from,
size_t fromOffset,
PVArray & to,
PVUnionArray & pvFrom,
size_t pvFromOffset,
size_t pvFromStride,
PVUnionArray & pvTo,
size_t toOffset,
size_t len)
size_t toStride,
size_t count)
{
Type type = from.getField()->getType();
Type otherType = to.getField()->getType();
if(type!=otherType) {
throw std::invalid_argument("pvSubArrayCopy types do not match");
if(pvTo.isImmutable()) {
throw std::logic_error("pvSubArrayCopy pvTo is immutable");
}
if(type==scalarArray) {
copy(dynamic_cast<PVScalarArray &>(from) ,fromOffset,
dynamic_cast<PVScalarArray&>(to),
toOffset,len);
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");
}
if(type==structureArray) {
copy(dynamic_cast<PVStructureArray &>(from) ,fromOffset,
dynamic_cast<PVStructureArray&>(to),
toOffset,len);
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);
}
}}

10
src/json/Makefile Normal file
View File

@@ -0,0 +1,10 @@
# This is a Makefile fragment, see ../Makefile
SRC_DIRS += $(PVDATA_SRC)/json
INC += pv/json.h
LIBSRCS += parsehelper.cpp
LIBSRCS += parseany.cpp
LIBSRCS += parseinto.cpp
LIBSRCS += print.cpp

284
src/json/parseany.cpp Normal file
View File

@@ -0,0 +1,284 @@
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
#include <sstream>
#define epicsExportSharedSymbols
#include <pv/pvdVersion.h>
#include <pv/pvData.h>
#include <pv/valueBuilder.h>
#if EPICS_VERSION_INT>=VERSION_INT(3,15,0,1)
#include "pv/json.h"
namespace pvd = epics::pvData;
using pvd::yajl::integer_arg;
using pvd::yajl::size_arg;
namespace {
struct context {
unsigned depth;
enum state_t {
Undefined,
Key,
Array,
} state;
pvd::shared_vector<void> arr;
pvd::ValueBuilder root,
*cur;
std::string msg,
key;
context() :depth(0u), state(Undefined), cur(&root) {}
};
#define TRY context *self = (context*)ctx; try
#define CATCH() catch(std::exception& e) { self->msg = e.what(); return 0; }
int jtree_null(void * ctx)
{
TRY {
self->msg = "NULL value not permitted";
return 0;
}CATCH()
}
int jtree_boolean(void * ctx, int boolVal)
{
TRY {
if(self->depth==0) throw std::runtime_error("Bare value not supported");
switch(self->state) {
case context::Key:
self->cur = &self->cur->add<pvd::pvBoolean>(self->key, boolVal);
self->key.clear();
self->state = context::Undefined;
break;
case context::Array:
{
if(self->arr.size()>0 && self->arr.original_type()!=pvd::pvBoolean)
throw std::runtime_error("Mixed type array not supported");
pvd::shared_vector<pvd::boolean> arr(pvd::static_shared_vector_cast<pvd::boolean>(self->arr));
arr.push_back(boolVal);
self->arr = pvd::static_shared_vector_cast<void>(arr);
break;
}
default:
throw std::logic_error("boolean in bad state");
}
return 1;
}CATCH()
}
int jtree_integer(void * ctx, integer_arg integerVal)
{
TRY {
if(self->depth==0) throw std::runtime_error("Bare value not supported");
switch(self->state) {
case context::Key:
self->cur = &self->cur->add<pvd::pvLong>(self->key, integerVal);
self->key.clear();
self->state = context::Undefined;
break;
case context::Array:
{
if(self->arr.size()>0 && self->arr.original_type()!=pvd::pvLong)
throw std::runtime_error("Mixed type array not supported");
pvd::shared_vector<pvd::int64> arr(pvd::static_shared_vector_cast<pvd::int64>(self->arr));
arr.push_back(integerVal);
self->arr = pvd::static_shared_vector_cast<void>(arr);
break;
}
default:
throw std::logic_error("int64 in bad state");
}
return 1;
}CATCH()
}
int jtree_double(void * ctx, double doubleVal)
{
TRY {
if(self->depth==0) throw std::runtime_error("Bare value not supported");
switch(self->state) {
case context::Key:
self->cur = &self->cur->add<pvd::pvDouble>(self->key, doubleVal);
self->key.clear();
self->state = context::Undefined;
break;
case context::Array:
{
if(self->arr.size()>0 && self->arr.original_type()!=pvd::pvDouble)
throw std::runtime_error("Mixed type array not supported");
pvd::shared_vector<double> arr(pvd::static_shared_vector_cast<double>(self->arr));
arr.push_back(doubleVal);
self->arr = pvd::static_shared_vector_cast<void>(arr);
break;
}
default:
throw std::logic_error("double in bad state");
}
return 1;
}CATCH()
}
int jtree_string(void * ctx, const unsigned char * stringVal,
size_arg stringLen)
{
TRY {
if(self->depth==0) throw std::runtime_error("Bare value not supported");
std::string sval((const char*)stringVal, stringLen);
switch(self->state) {
case context::Key:
self->cur = &self->cur->add<pvd::pvString>(self->key, sval);
self->key.clear();
self->state = context::Undefined;
break;
case context::Array:
{
if(self->arr.size()>0 && self->arr.original_type()!=pvd::pvString)
throw std::runtime_error("Mixed type array not supported");
pvd::shared_vector<std::string> arr(pvd::static_shared_vector_cast<std::string>(self->arr));
arr.push_back(sval);
self->arr = pvd::static_shared_vector_cast<void>(arr);
break;
}
default:
throw std::logic_error("double in bad state");
}
return 1;
}CATCH()
}
int jtree_start_map(void * ctx)
{
TRY {
if(self->depth>0) {
if(self->key.empty())
throw std::logic_error("anonymous dict not top level?");
self->cur = &self->cur->addNested(self->key);
self->key.clear();
}
self->depth++;
return 1;
}CATCH()
}
int jtree_map_key(void * ctx, const unsigned char * key,
size_arg stringLen)
{
TRY {
if(!self->key.empty())
throw std::logic_error("double key?");
if(stringLen==0)
throw std::runtime_error("empty key not allowed");
self->key = std::string((const char*)key, stringLen);
self->state = context::Key;
return 1;
}CATCH()
}
int jtree_end_map(void * ctx)
{
TRY {
if(self->depth>1)
self->cur = &self->cur->endNested();
else if(self->depth==0)
throw std::logic_error("Unbalenced dict");
self->depth--;
return 1;
}CATCH()
}
int jtree_start_array(void * ctx)
{
TRY {
if(self->depth==0) throw std::runtime_error("Bare array not supported");
if(self->state!=context::Key)
throw std::logic_error("bare array not supported");
self->state = context::Array;
return 1;
}CATCH()
}
int jtree_end_array(void * ctx)
{
TRY {
if(self->state!=context::Array)
throw std::logic_error("Bad array parse");
self->cur = &self->cur->add(self->key, pvd::freeze(self->arr));
self->key.clear();
self->state = context::Undefined;
return 1;
}CATCH()
}
yajl_callbacks jtree_cbs = {
&jtree_null,
&jtree_boolean,
&jtree_integer,
&jtree_double,
NULL, // number
&jtree_string,
&jtree_start_map,
&jtree_map_key,
&jtree_end_map,
&jtree_start_array,
&jtree_end_array,
};
struct handler {
yajl_handle handle;
handler(yajl_handle handle) :handle(handle)
{
if(!handle)
throw std::runtime_error("Failed to allocate yajl handle");
}
~handler() {
yajl_free(handle);
}
operator yajl_handle() { return handle; }
};
} // namespace
namespace epics{namespace pvData{
epics::pvData::PVStructure::shared_pointer
parseJSON(std::istream& strm)
{
#ifndef EPICS_YAJL_VERSION
yajl_parser_config conf;
memset(&conf, 0, sizeof(conf));
conf.allowComments = 1;
conf.checkUTF8 = 1;
#endif
context ctxt;
#ifndef EPICS_YAJL_VERSION
handler handle(yajl_alloc(&jtree_cbs, &conf, NULL, &ctxt));
#else
handler handle(yajl_alloc(&jtree_cbs, NULL, &ctxt));
yajl_config(handle, yajl_allow_comments, 1);
#endif
if(!yajl_parse_helper(strm, handle))
throw std::runtime_error(ctxt.msg);
return ctxt.cur->buildPVStructure();
}
}} // namespace epics::pvData
#endif // EPICS_VERSION_INT

122
src/json/parsehelper.cpp Normal file
View File

@@ -0,0 +1,122 @@
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
#include <stdexcept>
#include <sstream>
#define epicsExportSharedSymbols
#include <pv/pvdVersion.h>
#if EPICS_VERSION_INT>=VERSION_INT(3,15,0,1)
#include "pv/json.h"
namespace {
void check_trailing(const std::string& line)
{
size_t idx = line.find_first_not_of(" \t\n\r");
if(idx==line.npos) return;
// TODO: detect the end of potentially multi-line comments...
// for now trailing comments not allowed
throw std::runtime_error("Trailing junk");
}
} // namespace
namespace epics{namespace pvData{
bool yajl_parse_helper(std::istream& src,
yajl_handle handle)
{
unsigned linenum=0;
#ifndef EPICS_YAJL_VERSION
bool done = false;
#endif
std::string line;
while(std::getline(src, line)) {
linenum++;
#ifndef EPICS_YAJL_VERSION
if(done) {
check_trailing(line);
continue;
}
#endif
yajl_status sts = yajl_parse(handle, (const unsigned char*)line.c_str(), line.size());
switch(sts) {
case yajl_status_ok: {
size_t consumed = yajl_get_bytes_consumed(handle);
if(consumed<line.size()) {
check_trailing(line.substr(consumed));
}
#ifndef EPICS_YAJL_VERSION
done = true;
#endif
break;
}
case yajl_status_client_canceled:
return false;
#ifndef EPICS_YAJL_VERSION
case yajl_status_insufficient_data:
// continue with next line
break;
#endif
case yajl_status_error:
{
std::ostringstream msg;
unsigned char *raw = yajl_get_error(handle, 1, (const unsigned char*)line.c_str(), line.size());
if(!raw) {
msg<<"Unknown error on line "<<linenum;
} else {
try {
msg<<"Error on line "<<linenum<<" : "<<(const char*)raw;
}catch(...){
yajl_free_error(handle, raw);
throw;
}
yajl_free_error(handle, raw);
}
throw std::runtime_error(msg.str());
}
}
}
if(!src.eof() || src.bad()) {
std::ostringstream msg;
msg<<"I/O error after line "<<linenum;
throw std::runtime_error(msg.str());
#ifndef EPICS_YAJL_VERSION
} else if(!done) {
switch(yajl_parse_complete(handle)) {
#else
} else {
switch(yajl_complete_parse(handle)) {
#endif
case yajl_status_ok:
break;
case yajl_status_client_canceled:
return false;
#ifndef EPICS_YAJL_VERSION
case yajl_status_insufficient_data:
throw std::runtime_error("unexpected end of input");
#endif
case yajl_status_error:
throw std::runtime_error("Error while completing parsing");
}
}
return true;
}
}} // namespace epics::pvData
#endif // EPICS_VERSION_INT

342
src/json/parseinto.cpp Normal file
View File

@@ -0,0 +1,342 @@
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
#include <vector>
#include <sstream>
#define epicsExportSharedSymbols
#include <pv/pvdVersion.h>
#include <pv/pvData.h>
#include <pv/valueBuilder.h>
#include <pv/bitSet.h>
#if EPICS_VERSION_INT>=VERSION_INT(3,15,0,1)
#include "pv/json.h"
namespace pvd = epics::pvData;
using pvd::yajl::integer_arg;
using pvd::yajl::size_arg;
namespace {
struct context {
std::string msg;
struct frame {
pvd::PVFieldPtr fld;
pvd::BitSet *assigned;
frame(const pvd::PVFieldPtr& fld, pvd::BitSet *assigned)
:fld(fld), assigned(assigned)
{}
};
typedef std::vector<frame> stack_t;
stack_t stack;
context(const pvd::PVFieldPtr& root, pvd::BitSet *assigned)
{
stack.push_back(frame(root, assigned));
}
};
#define TRY context *self = (context*)ctx; assert(!self->stack.empty()); try
#define CATCH() catch(std::exception& e) { if(self->msg.empty()) self->msg = e.what(); return 0; }
int jtree_null(void * ctx)
{
TRY {
self->msg = "NULL value not permitted";
return 0;
}CATCH()
}
template<typename PVScalarT, typename PVArrayT>
void valueAssign(context *self, typename PVScalarT::value_type val)
{
assert(!self->stack.empty());
context::frame& back = self->stack.back();
pvd::Type type(back.fld->getField()->getType());
if(type==pvd::scalar) {
pvd::PVScalar* fld(static_cast<pvd::PVScalar*>(back.fld.get()));
fld->putFrom(val);
if(back.assigned)
back.assigned->set(fld->getFieldOffset());
self->stack.pop_back();
// structure at the top of the stack
} else if(type==pvd::scalarArray) {
pvd::PVScalarArray *fld(static_cast<pvd::PVScalarArray*>(back.fld.get()));
pvd::shared_vector<const void> carr;
fld->getAs(carr);
switch(carr.original_type())
{
#define CASE_STRING
#define CASE_REAL_INT64
#define CASE(BASETYPE, PVATYPE, DBFTYPE, PVACODE) case epics::pvData::pv##PVACODE: { \
pvd::shared_vector<const PVATYPE> arr(pvd::static_shared_vector_cast<const PVATYPE>(carr)); \
pvd::shared_vector<PVATYPE> tarr(pvd::thaw(arr)); \
tarr.push_back(pvd::castUnsafe<PVATYPE>(val)); \
carr = pvd::static_shared_vector_cast<const void>(pvd::freeze(tarr)); \
} break;
#include <pv/typemap.h>
#undef CASE
#undef CASE_REAL_INT64
#undef CASE_STRING
}
fld->putFrom(carr);
// leave array field at top of stack
} else if(type==pvd::union_) {
pvd::PVUnion* fld(static_cast<pvd::PVUnion*>(back.fld.get()));
pvd::UnionConstPtr utype(fld->getUnion());
if(utype->isVariant()) {
typename PVScalarT::shared_pointer elem(pvd::getPVDataCreate()->createPVScalar<PVScalarT>());
elem->put(val);
fld->set(elem);
} else {
// attempt automagic assignment
const pvd::StringArray& names = utype->getFieldNames();
const pvd::FieldConstPtrArray types = utype->getFields();
assert(names.size()==types.size());
bool assigned = false;
for(size_t i=0, N=names.size(); i<N; i++) {
if(types[i]->getType()!=pvd::scalar) continue;
pvd::PVScalarPtr ufld(fld->select<pvd::PVScalar>(i));
try{
ufld->putFrom(val);
assigned = true;
}catch(std::runtime_error&){
if(i==N-1)
throw;
continue;
}
break;
}
if(!assigned)
throw std::runtime_error("Unable to select union member");
}
if(back.assigned)
back.assigned->set(fld->getFieldOffset());
self->stack.pop_back();
// structure back at the top of the stack
} else {
throw std::invalid_argument("Can't assign value");
}
}
int jtree_boolean(void * ctx, int boolVal)
{
TRY {
valueAssign<pvd::PVBoolean, pvd::PVBooleanArray>(self, !!boolVal);
return 1;
}CATCH()
}
int jtree_integer(void * ctx, integer_arg integerVal)
{
TRY {
valueAssign<pvd::PVLong, pvd::PVLongArray>(self, integerVal);
return 1;
}CATCH()
}
int jtree_double(void * ctx, double doubleVal)
{
TRY {
valueAssign<pvd::PVDouble, pvd::PVDoubleArray>(self, doubleVal);
return 1;
}CATCH()
}
int jtree_string(void * ctx, const unsigned char * stringVal,
size_arg stringLen)
{
TRY {
std::string val((const char*)stringVal, stringLen);
valueAssign<pvd::PVString, pvd::PVStringArray>(self, val);
return 1;
}CATCH()
}
int jtree_start_map(void * ctx)
{
TRY {
assert(!self->stack.empty());
context::frame& back = self->stack.back();
pvd::Type type = back.fld->getField()->getType();
if(type==pvd::structure) {
// will fill in
} else if(type==pvd::structureArray) {
// starting new element in structure array
pvd::PVStructureArray* sarr(static_cast<pvd::PVStructureArray*>(back.fld.get()));
pvd::PVStructurePtr elem(pvd::getPVDataCreate()->createPVStructure(sarr->getStructureArray()->getStructure()));
self->stack.push_back(context::frame(elem, 0));
} else {
throw std::runtime_error("Can't map (sub)structure");
}
assert(self->stack.back().fld->getField()->getType()==pvd::structure);
return 1;
}CATCH()
}
int jtree_map_key(void * ctx, const unsigned char * key,
size_arg stringLen)
{
TRY {
assert(!self->stack.empty());
std::string name((const char*)key, stringLen);
// start_map() ensures we have a structure at the top of the stack
pvd::PVStructure *fld = static_cast<pvd::PVStructure*>(self->stack.back().fld.get());
try {
self->stack.push_back(context::frame(fld->getSubFieldT(name), self->stack.back().assigned));
}catch(std::runtime_error& e){
std::ostringstream strm;
strm<<"At "<<fld->getFullName()<<" : "<<e.what()<<"\n";
throw std::runtime_error(strm.str());
}
return 1;
}CATCH()
}
int jtree_end_map(void * ctx)
{
TRY {
assert(!self->stack.empty());
assert(self->stack.back().fld->getField()->getType()==pvd::structure);
context::frame elem(self->stack.back());
self->stack.pop_back();
if(!self->stack.empty() && self->stack.back().fld->getField()->getType()==pvd::structureArray) {
// append element to struct array
pvd::PVStructureArray *sarr = static_cast<pvd::PVStructureArray*>(self->stack.back().fld.get());
pvd::PVStructureArray::const_svector cval;
sarr->swap(cval);
pvd::PVStructureArray::svector val(pvd::thaw(cval));
val.push_back(std::tr1::static_pointer_cast<pvd::PVStructure>(elem.fld));
sarr->replace(pvd::freeze(val));
}
return 1;
}CATCH()
}
int jtree_start_array(void * ctx)
{
TRY {
assert(!self->stack.empty());
pvd::PVFieldPtr& back(self->stack.back().fld);
pvd::Type type = back->getField()->getType();
if(type!=pvd::structureArray && type!=pvd::scalarArray)
throw std::runtime_error("Can't assign array");
return 1;
}CATCH()
}
int jtree_end_array(void * ctx)
{
TRY {
assert(!self->stack.empty());
if(self->stack.back().assigned)
self->stack.back().assigned->set(self->stack.back().fld->getFieldOffset());
self->stack.pop_back();
return 1;
}CATCH()
}
yajl_callbacks jtree_cbs = {
&jtree_null,
&jtree_boolean,
&jtree_integer,
&jtree_double,
NULL, // number
&jtree_string,
&jtree_start_map,
&jtree_map_key,
&jtree_end_map,
&jtree_start_array,
&jtree_end_array,
};
struct handler {
yajl_handle handle;
handler(yajl_handle handle) :handle(handle)
{
if(!handle)
throw std::runtime_error("Failed to allocate yajl handle");
}
~handler() {
yajl_free(handle);
}
operator yajl_handle() { return handle; }
};
} // namespace
namespace epics{namespace pvData{
epicsShareFunc
void parseJSON(std::istream& strm,
const PVField::shared_pointer& dest,
BitSet *assigned)
{
#ifndef EPICS_YAJL_VERSION
yajl_parser_config conf;
memset(&conf, 0, sizeof(conf));
conf.allowComments = 1;
conf.checkUTF8 = 1;
#endif
context ctxt(dest, assigned);
#ifndef EPICS_YAJL_VERSION
handler handle(yajl_alloc(&jtree_cbs, &conf, NULL, &ctxt));
#else
handler handle(yajl_alloc(&jtree_cbs, NULL, &ctxt));
yajl_config(handle, yajl_allow_comments, 1);
#endif
if(!yajl_parse_helper(strm, handle))
throw std::runtime_error(ctxt.msg);
if(!ctxt.stack.empty())
throw std::logic_error("field stack not empty");
}
}} // namespace epics::pvData
#endif // EPICS_VERSION_INT

170
src/json/print.cpp Normal file
View File

@@ -0,0 +1,170 @@
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
#include <vector>
#include <sstream>
#define epicsExportSharedSymbols
#include <pv/pvdVersion.h>
#include <pv/pvData.h>
#include <pv/valueBuilder.h>
#if EPICS_VERSION_INT>=VERSION_INT(3,15,0,1)
#include "pv/json.h"
namespace pvd = epics::pvData;
namespace {
struct args {
std::ostream& strm;
const pvd::JSONPrintOptions& opts;
unsigned indent;
args(std::ostream& strm,
const pvd::JSONPrintOptions& opts)
:strm(strm)
,opts(opts)
,indent(opts.indent)
{}
void doIntent() {
if(!opts.multiLine) return;
strm.put('\n');
unsigned i=indent;
while(i--) strm.put(' ');
}
};
void show_field(args& A, const pvd::PVField* fld);
void show_struct(args& A, const pvd::PVStructure* fld)
{
const pvd::StructureConstPtr& type = fld->getStructure();
const pvd::PVFieldPtrArray& children = fld->getPVFields();
const pvd::StringArray& names = type->getFieldNames();
A.strm.put('{');
A.indent++;
for(size_t i=0, N=names.size(); i<N; i++)
{
if(i!=0)
A.strm.put(',');
A.doIntent();
A.strm<<'\"'<<names[i]<<"\": ";
show_field(A, children[i].get());
}
A.indent--;
A.doIntent();
A.strm.put('}');
}
void show_field(args& A, const pvd::PVField* fld)
{
switch(fld->getField()->getType())
{
case pvd::scalar:
{
const pvd::PVScalar *scalar=static_cast<const pvd::PVScalar*>(fld);
if(scalar->getScalar()->getScalarType()==pvd::pvString) {
A.strm<<'\"'<<scalar->getAs<std::string>()<<'\"';
} else {
A.strm<<scalar->getAs<std::string>();
}
}
break;
case pvd::scalarArray:
{
const pvd::PVScalarArray *scalar=static_cast<const pvd::PVScalarArray*>(fld);
const bool isstring = scalar->getScalarArray()->getElementType()==pvd::pvString;
pvd::shared_vector<const void> arr;
scalar->getAs<void>(arr);
pvd::shared_vector<const std::string> sarr(pvd::shared_vector_convert<const std::string>(arr));
A.strm.put('[');
for(size_t i=0, N=sarr.size(); i<N; i++) {
if(i!=0)
A.strm.put(',');
if(isstring)
A.strm.put('\"');
A.strm<<sarr[i];
if(isstring)
A.strm.put('\"');
}
A.strm.put(']');
}
break;
case pvd::structure:
show_struct(A, static_cast<const pvd::PVStructure*>(fld));
break;
case pvd::structureArray:
{
pvd::PVStructureArray::const_svector arr(static_cast<const pvd::PVStructureArray*>(fld)->view());
A.strm.put('[');
A.indent++;
for(size_t i=0, N=arr.size(); i<N; i++) {
if(i!=0)
A.strm.put(',');
A.doIntent();
if(arr[i])
show_struct(A, arr[i].get());
else
A.strm<<"NULL";
}
A.indent--;
A.doIntent();
A.strm.put(']');
}
break;
case pvd::union_:
{
const pvd::PVUnion *U=static_cast<const pvd::PVUnion*>(fld);
const pvd::PVField::const_shared_pointer& C(U->get());
if(!C) {
A.strm<<"null";
} else {
show_field(A, C.get());
}
}
break;
default:
if(A.opts.ignoreUnprintable)
A.strm<<"// unprintable field type";
else
throw std::runtime_error("Encountered unprintable field type");
}
}
} // namespace
namespace epics{namespace pvData{
JSONPrintOptions::JSONPrintOptions()
:multiLine(true)
,ignoreUnprintable(true)
,indent(0)
{}
void printJSON(std::ostream& strm,
const PVField::const_shared_pointer& val,
const JSONPrintOptions& opts)
{
args A(strm, opts);
show_field(A, val.get());
}
}} // namespace epics::pvData
#endif // EPICS_VERSION_INT

127
src/json/pv/json.h Normal file
View File

@@ -0,0 +1,127 @@
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
#ifndef PV_JSON_H
#define PV_JSON_H
#include <istream>
#include <ostream>
#include <string>
#include <map>
#include <pv/pvdVersion.h>
#include <pv/pvData.h>
#if EPICS_VERSION_INT>=VERSION_INT(3,15,0,1)
#ifdef epicsExportSharedSymbols
# define pvjson_epicsExportSharedSymbols
# undef epicsExportSharedSymbols
#endif
#include <yajl_parse.h>
#ifdef pvjson_epicsExportSharedSymbols
# define epicsExportSharedSymbols
# include "shareLib.h"
#endif
#include <shareLib.h>
namespace epics{namespace pvData{
class BitSet;
/** @defgroup pvjson JSON print/parse
*
* Printing PVField as JSON and parsing JSON into PVField.
*
* @{
*/
//! Options used during printing
struct epicsShareClass JSONPrintOptions
{
bool multiLine; //!< include new lines
bool ignoreUnprintable;//!< ignore union/union array when encountered
unsigned indent; //!< Initial indentation (# of spaces)
JSONPrintOptions();
};
/** Print PVStructure as JSON
*
* Restrictions:
*
* - No support for union or array of union
*/
epicsShareFunc
void printJSON(std::ostream& strm,
const PVField::const_shared_pointer& val,
const JSONPrintOptions& opts = JSONPrintOptions());
/** Parse JSON text into a PVStructure
*
* Restrictions:
*
* - Top level must be {} dict/object
* - field values must be number, string, array, or dict/object
* - array values must be number or string
*/
epicsShareFunc
PVStructure::shared_pointer parseJSON(std::istream& strm);
/** Parse JSON and store into the provided PVStructure.
*
* Restrictions:
*
* - array of union not supported
* - Only scalar value assigned to union
*
* @param strm Read JSON text from stream
* @param dest Store in fields of this structure
* @param assigned Which fields of _dest_ were assigned. (Optional)
* @throws std::runtime_error on failure. dest and assigned may be modified.
*/
epicsShareFunc
void parseJSON(std::istream& strm,
const PVField::shared_pointer& dest,
BitSet *assigned=0);
/** Wrapper around yajl_parse()
*
* Parse entire input stream.
* Errors if extranious non-whitespace found after the point were parsing completes.
*
* @param src The stream from which input charactors are read
* @param handle A parser handle previously allocated with yajl_alloc(). Not free'd on success or failure.
*
* @returns true if parsing completes successfully. false if parsing cancelled by callback. throws other errors
*
* @note The form of this call depends on EPICS_YAJL_VERSION
*/
epicsShareFunc
bool yajl_parse_helper(std::istream& src,
yajl_handle handle);
namespace yajl {
// undef implies API version 0
#ifndef EPICS_YAJL_VERSION
typedef long integer_arg;
typedef unsigned size_arg;
#else
typedef long long integer_arg;
typedef size_t size_arg;
#endif
} // namespace epics::pvData::yajl
/** @} */
}} // namespace epics::pvData
#else
# error JSON parser requires EPICS Base >= 3.15.0.1
#endif // EPICS_VERSION_INT
#endif // PV_JSON_H

View File

@@ -2,43 +2,43 @@
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
INC += pv/noDefaultMethods.h
INC += pv/lock.h
INC += pv/serialize.h
INC += pv/bitSet.h
INC += pv/byteBuffer.h
INC += pv/epicsException.h
INC += pv/serializeHelper.h
INC += pv/event.h
INC += pv/thread.h
INC += pv/executor.h
INC += pv/timeFunction.h
INC += pv/timer.h
INC += pv/queue.h
INC += pv/status.h
INC += pv/sharedPtr.h
INC += pv/debugPtr.h
INC += pv/localStaticLock.h
INC += pv/typeCast.h
INC += pv/sharedVector.h
INC += pv/templateMeta.h
INC += pv/current_function.h
INC += pv/pvUnitTest.h
INC += pv/reftrack.h
INC += pv/anyscalar.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
LIBSRCS += pvUnitTest.cpp
LIBSRCS += debugPtr.cpp
LIBSRCS += reftrack.cpp

View File

@@ -1,8 +1,7 @@
/* bitSet.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.
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author mes
@@ -10,12 +9,38 @@
#include <string.h>
#include <stdio.h>
#include <iostream>
#include <stdexcept>
#include <algorithm>
#include <epicsMutex.h>
#define epicsExportSharedSymbols
#include <pv/lock.h>
#include <pv/serializeHelper.h>
#include <pv/bitSet.h>
/*
* BitSets are packed into arrays of "words." Currently a word is
* a long, which consists of 64 bits, requiring 6 address bits.
* The choice of word size is determined purely by performance concerns.
*/
#define ADDRESS_BITS_PER_WORD 6u
#define BITS_PER_WORD (1u << ADDRESS_BITS_PER_WORD)
#define BYTES_PER_WORD sizeof(uint64)
#define BIT_INDEX_MASK (BITS_PER_WORD - 1u)
/** Used to shift left or right for a partial word mask */
#define WORD_MASK ~((uint64)0)
// index of work containing this bit
#define WORD_INDEX(bitn) ((bitn)>>ADDRESS_BITS_PER_WORD)
// bit offset within word
#define WORD_OFFSET(bitn) ((bitn)&BIT_INDEX_MASK)
// the words vector should be size()d as small as posible,
// so the last word should always have a bit set when the set is not empty
#define CHECK_POST() assert(words.empty() || words.back()!=0)
namespace epics { namespace pvData {
BitSet::shared_pointer BitSet::create(uint32 nbits)
@@ -23,90 +48,76 @@ namespace epics { namespace pvData {
return BitSet::shared_pointer(new BitSet(nbits));
}
BitSet::BitSet() : words(0), wordsLength(0), wordsInUse(0) {
initWords(BITS_PER_WORD);
BitSet::BitSet() {}
BitSet::BitSet(uint32 nbits)
{
words.reserve((nbits == 0) ? 1 : WORD_INDEX(nbits-1) + 1);
}
BitSet::BitSet(uint32 nbits) : words(0), wordsLength(0), wordsInUse(0) {
initWords(nbits);
#if __cplusplus>=201103L
BitSet::BitSet(std::initializer_list<uint32> I)
{
// optimistically guess that highest bit is last (not required)
words.reserve((I.size() == 0) ? 1 : WORD_INDEX(*(I.end()-1)) + 1);
for(uint32 idx : I)
{
set(idx);
}
}
#endif
BitSet::~BitSet() {
delete[] words;
}
void BitSet::initWords(uint32 nbits) {
uint32 length = (nbits <= 0) ? 1 : wordIndex(nbits-1) + 1;
if (words) delete[] words;
words = new uint64[length];
memset(words, 0, sizeof(uint64)*length);
wordsLength = length;
}
BitSet::~BitSet() {}
void BitSet::recalculateWordsInUse() {
// wordsInUse is unsigned
if (wordsInUse == 0)
return;
// Traverse the bitset until a used word is found
int32 i;
for (i = (int32)wordsInUse-1; i >= 0; i--)
if (words[i] != 0)
// step back from the end to find the first non-zero element
size_t nsize = words.size();
for(; nsize; nsize--) {
if(words[nsize-1])
break;
wordsInUse = i+1; // The new logical size
}
words.resize(nsize);
CHECK_POST();
}
void BitSet::ensureCapacity(uint32 wordsRequired) {
if (wordsLength < wordsRequired) {
// create and copy
uint64* newwords = new uint64[wordsRequired];
memset(newwords, 0, sizeof(uint64)*wordsRequired);
memcpy(newwords, words, sizeof(uint64)*wordsLength);
if (words) delete[] words;
words = newwords;
wordsLength = wordsRequired;
}
words.resize(std::max(words.size(), (size_t)wordsRequired), 0);
}
void BitSet::expandTo(uint32 wordIndex) {
uint32 wordsRequired = wordIndex+1;
if (wordsInUse < wordsRequired) {
ensureCapacity(wordsRequired);
wordsInUse = wordsRequired;
ensureCapacity(wordIndex+1);
}
BitSet& BitSet::flip(uint32 bitIndex) {
uint32 wordIdx = WORD_INDEX(bitIndex);
expandTo(wordIdx);
words[wordIdx] ^= (((uint64)1) << WORD_OFFSET(bitIndex));
recalculateWordsInUse();
return *this;
}
BitSet& BitSet::set(uint32 bitIndex) {
uint32 wordIdx = WORD_INDEX(bitIndex);
expandTo(wordIdx);
words[wordIdx] |= (((uint64)1) << WORD_OFFSET(bitIndex));
return *this;
}
BitSet& BitSet::clear(uint32 bitIndex) {
uint32 wordIdx = WORD_INDEX(bitIndex);
if (wordIdx < words.size()) {
words[wordIdx] &= ~(((uint64)1) << WORD_OFFSET(bitIndex));
recalculateWordsInUse();
}
}
void BitSet::flip(uint32 bitIndex) {
uint32 wordIdx = wordIndex(bitIndex);
expandTo(wordIdx);
words[wordIdx] ^= (((uint64)1) << (bitIndex % BITS_PER_WORD));
recalculateWordsInUse();
}
void BitSet::set(uint32 bitIndex) {
uint32 wordIdx = wordIndex(bitIndex);
expandTo(wordIdx);
words[wordIdx] |= (((uint64)1) << (bitIndex % BITS_PER_WORD));
}
void BitSet::clear(uint32 bitIndex) {
uint32 wordIdx = wordIndex(bitIndex);
if (wordIdx >= wordsInUse)
return;
words[wordIdx] &= ~(((uint64)1) << (bitIndex % BITS_PER_WORD));
recalculateWordsInUse();
return *this;
}
void BitSet::set(uint32 bitIndex, bool value) {
@@ -117,14 +128,13 @@ namespace epics { namespace pvData {
}
bool BitSet::get(uint32 bitIndex) const {
uint32 wordIdx = wordIndex(bitIndex);
return ((wordIdx < wordsInUse)
&& ((words[wordIdx] & (((uint64)1) << (bitIndex % BITS_PER_WORD))) != 0));
uint32 wordIdx = WORD_INDEX(bitIndex);
return ((wordIdx < words.size())
&& ((words[wordIdx] & (((uint64)1) << WORD_OFFSET(bitIndex))) != 0));
}
void BitSet::clear() {
while (wordsInUse > 0)
words[--wordsInUse] = 0;
words.clear();
}
uint32 BitSet::numberOfTrailingZeros(uint64 i) {
@@ -153,8 +163,8 @@ namespace epics { namespace pvData {
int32 BitSet::nextSetBit(uint32 fromIndex) const {
uint32 u = wordIndex(fromIndex);
if (u >= wordsInUse)
uint32 u = WORD_INDEX(fromIndex);
if (u >= words.size())
return -1;
uint64 word = words[u] & (WORD_MASK << (fromIndex % BITS_PER_WORD));
@@ -162,7 +172,7 @@ namespace epics { namespace pvData {
while (true) {
if (word != 0)
return (u * BITS_PER_WORD) + numberOfTrailingZeros(word);
if (++u == wordsInUse)
if (++u == words.size())
return -1;
word = words[u];
}
@@ -171,8 +181,8 @@ namespace epics { namespace pvData {
int32 BitSet::nextClearBit(uint32 fromIndex) const {
// Neither spec nor implementation handle bitsets of maximal length.
uint32 u = wordIndex(fromIndex);
if (u >= wordsInUse)
uint32 u = WORD_INDEX(fromIndex);
if (u >= words.size())
return fromIndex;
uint64 word = ~words[u] & (WORD_MASK << (fromIndex % BITS_PER_WORD));
@@ -180,79 +190,77 @@ namespace epics { namespace pvData {
while (true) {
if (word != 0)
return (u * BITS_PER_WORD) + numberOfTrailingZeros(word);
if (++u == wordsInUse)
return wordsInUse * BITS_PER_WORD;
if (++u == words.size())
return words.size() * BITS_PER_WORD;
word = ~words[u];
}
}
bool BitSet::isEmpty() const {
return (wordsInUse == 0);
return words.empty();
}
uint32 BitSet::cardinality() const {
uint32 sum = 0;
for (uint32 i = 0; i < wordsInUse; i++)
for (uint32 i = 0; i < words.size(); i++)
sum += bitCount(words[i]);
return sum;
}
uint32 BitSet::size() const {
return wordsLength * BITS_PER_WORD;
return words.size() * BITS_PER_WORD;
}
bool BitSet::logical_and(const BitSet& set) const
{
size_t nwords = std::min(words.size(), set.words.size());
for(size_t i=0; i<nwords; i++) {
if(words[i] & set.words[i])
return true;
}
return false;
}
bool BitSet::logical_or(const BitSet& set) const
{
return !words.empty() || !set.words.empty();
}
BitSet& BitSet::operator&=(const BitSet& set) {
// Check for self-assignment!
if (this == &set) return *this;
while (wordsInUse > set.wordsInUse)
words[--wordsInUse] = 0;
// the result length will be <= the shorter of the two inputs
words.resize(std::min(words.size(), set.words.size()), 0);
// Perform logical AND on words in common
for (uint32 i = 0; i < wordsInUse; i++)
for(size_t i=0, e=words.size(); i<e; i++)
words[i] &= set.words[i];
recalculateWordsInUse();
return *this;
}
BitSet& BitSet::operator|=(const BitSet& set) {
// Check for self-assignment!
if (this == &set) return *this;
uint32 wordsInCommon = wordsInUse;
if(wordsInUse>set.wordsInUse) wordsInCommon = set.wordsInUse;
if (wordsInUse < set.wordsInUse) {
ensureCapacity(set.wordsInUse);
wordsInUse = set.wordsInUse;
}
// Perform logical OR on words in common
for (uint32 i =0; i < wordsInCommon; i++) {
// result length will be the same as the longer of the two inputs
words.resize(std::max(words.size(), set.words.size()), 0);
// since we expand w/ zeros, then iterate using the size of the other vector
for(size_t i=0, e=set.words.size(); i<e; i++)
words[i] |= set.words[i];
}
// Copy any remaining words
for(uint32 i=wordsInCommon; i<set.wordsInUse; ++i) {
words[i] = set.words[i];
}
// recalculateWordsInUse() is not needed
CHECK_POST();
return *this;
}
BitSet& BitSet::operator^=(const BitSet& set) {
uint32 wordsInCommon = wordsInUse;
if(wordsInUse>set.wordsInUse) wordsInCommon = set.wordsInUse;
if (wordsInUse < set.wordsInUse) {
ensureCapacity(set.wordsInUse);
wordsInUse = set.wordsInUse;
}
// Perform logical OR on words in common
for (uint32 i =0; i < wordsInCommon; i++) {
// result length will <= the longer of the two inputs
words.resize(std::max(words.size(), set.words.size()), 0);
for(size_t i=0, e=set.words.size(); i<e; i++)
words[i] ^= set.words[i];
}
// Copy any remaining words
for(uint32 i=wordsInCommon; i<set.wordsInUse; ++i) {
words[i] = set.words[i];
}
recalculateWordsInUse();
return *this;
}
@@ -260,32 +268,27 @@ namespace epics { namespace pvData {
BitSet& BitSet::operator=(const BitSet &set) {
// Check for self-assignment!
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)
{
if (words) delete[] words;
words = new uint64[set.wordsLength];
wordsLength = set.wordsLength;
if (this != &set) {
words = set.words;
}
memcpy(words, set.words, sizeof(uint64)*set.wordsInUse);
wordsInUse = set.wordsInUse;
return *this;
}
void BitSet::or_and(const BitSet& set1, const BitSet& set2) {
uint32 inUse = (set1.wordsInUse < set2.wordsInUse) ? set1.wordsInUse : set2.wordsInUse;
void BitSet::swap(BitSet& set)
{
words.swap(set.words);
}
ensureCapacity(inUse);
wordsInUse = inUse;
void BitSet::or_and(const BitSet& set1, const BitSet& set2) {
const size_t andlen = std::min(set1.words.size(), set2.words.size());
words.resize(std::max(words.size(), andlen), 0);
// Perform logical AND on words in common
for (uint32 i = 0; i < inUse; i++)
for (uint32 i = 0; i < andlen; i++)
words[i] |= (set1.words[i] & set2.words[i]);
// recalculateWordsInUse()...
recalculateWordsInUse();
}
bool BitSet::operator==(const BitSet &set) const
@@ -293,11 +296,11 @@ namespace epics { namespace pvData {
if (this == &set)
return true;
if (wordsInUse != set.wordsInUse)
if (words.size() != set.words.size())
return false;
// Check words in use by both BitSets
for (uint32 i = 0; i < wordsInUse; i++)
for (uint32 i = 0; i < words.size(); i++)
if (words[i] != set.words[i])
return false;
@@ -309,70 +312,69 @@ 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;
uint32 n = words.size();
if (n == 0) {
SerializeHelper::writeSize(0, buffer, flusher);
return;
}
uint32 len = 8 * (n-1);
uint32 len = BYTES_PER_WORD * (n-1); // length excluding bits in the last word
// count non-zero bytes in the last word
for (uint64 x = words[n - 1]; x != 0; x >>= 8)
len++;
SerializeHelper::writeSize(len, buffer, flusher);
flusher->ensureBuffer(len);
for (uint32 i = 0; i < n - 1; i++)
n = len / 8;
for (uint32 i = 0; i < n; i++)
buffer->putLong(words[i]);
for (uint64 x = words[n - 1]; x != 0; x >>= 8)
buffer->putByte((int8) (x & 0xff));
if (n < words.size())
for (uint64 x = words[words.size() - 1]; x != 0; x >>= 8)
buffer->putByte((int8) (x & 0xff));
}
void BitSet::deserialize(ByteBuffer* buffer, DeserializableControl* control) {
uint32 bytes = static_cast<uint32>(SerializeHelper::readSize(buffer, control)); // in bytes
wordsInUse = (bytes + 7) / 8;
if (wordsInUse > wordsLength)
{
if (words) delete[] words;
words = new uint64[wordsInUse];
wordsLength = wordsInUse;
}
size_t wordsInUse = (bytes + 7) / BYTES_PER_WORD;
words.resize(wordsInUse);
if (wordsInUse == 0)
return;
control->ensureData(bytes);
uint32 i = 0;
uint32 longs = bytes / 8;
while (i < longs)
words[i++] = buffer->getLong();
for (uint32 j = i; j < wordsInUse; j++)
words[j] = 0;
for (uint32 remaining = (bytes - longs * 8), j = 0; j < remaining; j++)
words[i] |= (buffer->getByte() & 0xffL) << (8 * j);
words[i] |= (buffer->getByte() & 0xffLL) << (8 * j);
recalculateWordsInUse(); // Sender shouldn't add extra zero bytes, but don't fail it it does
}
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

@@ -1,8 +1,10 @@
/**
* 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.
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author mse
*/
#define epicsExportSharedSymbols
#include <pv/byteBuffer.h>

165
src/misc/debugPtr.cpp Normal file
View File

@@ -0,0 +1,165 @@
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
#if __cplusplus>=201103L
#include <epicsMutex.h>
#include <epicsGuard.h>
#define epicsExportSharedSymbols
#include <pv/debugPtr.h>
namespace {
typedef epicsGuard<epicsMutex> Guard;
}
namespace epics {
namespace debug {
// joins together a group of ptr_base instances
// which all have the same dtor
struct tracker {
epicsMutex mutex;
ptr_base::ref_set_t refs;
};
void shared_ptr_base::track_new()
{
if(track) {
Guard G(track->mutex);
track->refs.insert(this);
}
snap_stack();
}
// create new tracker if ptr!=nullptr, otherwise clear
void shared_ptr_base::track_new(void* ptr)
{
track_clear();
if(ptr){
track.reset(new tracker);
Guard G(track->mutex);
track->refs.insert(this);
}
snap_stack();
}
void shared_ptr_base::track_assign(const shared_ptr_base &o)
{
if(track!=o.track) {
track_clear();
track = o.track;
if(track) {
Guard G(track->mutex);
track->refs.insert(this);
}
snap_stack();
}
}
void shared_ptr_base::track_clear()
{
if(track) {
Guard G(track->mutex);
track->refs.erase(this);
}
track.reset();
#ifndef EXCEPT_USE_NONE
m_depth = 0;
#endif
}
void shared_ptr_base::swap(shared_ptr_base &o)
{
// we cheat a bit here to avoid lock order, and to lock only twice
if(track) {
Guard G(track->mutex);
track->refs.insert(&o);
track->refs.erase(this);
}
track.swap(o.track);
if(track) {
Guard G(track->mutex);
track->refs.insert(this);
track->refs.erase(&o);
}
//TODO: keep original somehow???
snap_stack();
o.snap_stack();
}
void shared_ptr_base::snap_stack()
{
if(!track) {
#ifndef EXCEPT_USE_NONE
m_depth = 0;
#endif
return;
}
#if defined(EXCEPT_USE_BACKTRACE)
{
m_depth=backtrace(m_stack,EXCEPT_DEPTH);
}
#else
{}
#endif
}
void shared_ptr_base::show_stack(std::ostream& strm) const
{
strm<<"ptr "<<this;
#ifndef EXCEPT_USE_NONE
if(m_depth<=0) return;
#endif
#if 0 && defined(EXCEPT_USE_BACKTRACE)
{
char **symbols=backtrace_symbols(m_stack, m_depth);
strm<<": ";
for(int i=0; i<m_depth; i++) {
strm<<symbols[i]<<", ";
}
std::free(symbols);
}
#elif !defined(EXCEPT_USE_NONE)
{
strm<<": ";
for(int i=0; i<m_depth; i++) {
strm<<std::hex<<m_stack[i]<<" ";
}
}
#endif
}
void ptr_base::show_refs(std::ostream& strm, bool self, bool weak) const
{
if(!track) {
strm<<"# No refs\n";
} else {
Guard G(track->mutex);
for(auto ref : track->refs) {
if(!self && ref==this) continue;
strm<<'#';
ref->show_stack(strm);
strm<<'\n';
}
}
}
void ptr_base::spy_refs(ref_set_t &refs) const
{
if(track) {
Guard G(track->mutex);
refs.insert(track->refs.begin(), track->refs.end());
}
}
}} // namespace epics::debug
#endif // __cplusplus>=201103L

View File

@@ -1,40 +0,0 @@
/* destroyable.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 mse
*/
#ifndef DESTROYABLE_H
#define DESTROYABLE_H
#include <pv/sharedPtr.h>
#include <shareLib.h>
namespace epics { namespace pvData {
/**
* Instance declaring destroy method.
* @author mse
*/
class epicsShareClass Destroyable {
public:
POINTER_DEFINITIONS(Destroyable);
/**
* Destroy this instance.
*/
virtual void destroy() = 0;
protected:
/**
* Do not allow delete on this instance and derived classes, destroy() must be used instead.
*/
virtual ~Destroyable() {};
};
}}
#endif /* DESTROYABLE_H */

View File

@@ -1,7 +1,6 @@
/**
* 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.
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author mes
@@ -10,10 +9,13 @@
#include <sstream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <string>
#define epicsExportSharedSymbols
#include <pv/epicsException.h>
using std::string;
namespace epics{ namespace pvData {
@@ -32,7 +34,7 @@ ExceptionMixin::print(FILE *fp) const
#endif
}
std::string
string
ExceptionMixin::show() const
{
std::ostringstream out;
@@ -48,7 +50,7 @@ ExceptionMixin::show() const
out<<symbols[i]<<"\n";
}
free(symbols);
std::free(symbols);
}
#endif
@@ -62,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

@@ -1,8 +1,7 @@
/* event.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.
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author mrk
@@ -26,6 +25,8 @@
#include <pv/lock.h>
#include <pv/event.h>
using std::string;
namespace epics { namespace pvData {
@@ -36,34 +37,33 @@ Event::~Event() {
Event::Event(bool full)
: id(epicsEventCreate(full?epicsEventFull : epicsEventEmpty)),
alreadyOn("already on list")
: id(epicsEventCreate(full?epicsEventFull : epicsEventEmpty))
{
}
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

@@ -1,53 +0,0 @@
/* event.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 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 epicsShareClass Event {
public:
POINTER_DEFINITIONS(Event);
explicit Event(bool = false);
~Event();
void signal();
bool wait (); /* blocks until full */
bool wait ( double timeOut ); /* false if empty at time out */
bool tryWait (); /* false if empty */
private:
epicsEventId id;
String alreadyOn;
};
}}
#endif /* EVENT_H */

View File

@@ -1,8 +1,7 @@
/* executor.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.
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author mrk
@@ -13,9 +12,20 @@
#include <string>
#include <cstdio>
#include <epicsEvent.h>
#include <epicsMutex.h>
#include <epicsThread.h>
// Suppress deprecation warnings for the implementation
#include <compilerDependencies.h>
#undef EPICS_DEPRECATED
#define EPICS_DEPRECATED
#define epicsExportSharedSymbols
#include <pv/executor.h>
using std::string;
namespace epics { namespace pvData {
// special instance to stop the executor thread
@@ -31,7 +41,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)
{
}
@@ -52,14 +62,14 @@ void Executor::run()
{
Lock xx(mutex);
while(true) {
while(head.get()==NULL) {
while(!head.get()) {
xx.unlock();
moreWork.wait();
xx.lock();
}
CommandPtr command = head;
head = command->next;
if(command.get()==NULL) continue;
if(!command.get()) continue;
if(command.get()==shutdown.get()) break;
xx.unlock();
try {
@@ -80,13 +90,13 @@ void Executor::execute(CommandPtr const & command)
{
Lock xx(mutex);
command->next.reset();
if(head.get()==NULL) {
if(!head.get()) {
head = command;
moreWork.signal();
return;
}
CommandPtr tail = head;
while(tail->next!=NULL) tail = tail->next;
while(tail->next) tail = tail->next;
tail->next = command;
}

View File

@@ -1,57 +0,0 @@
/* executor.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 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;
class Executor;
typedef std::tr1::shared_ptr<Command> CommandPtr;
typedef std::tr1::shared_ptr<Executor> ExecutorPtr;
class epicsShareClass Command {
public:
POINTER_DEFINITIONS(Command);
virtual ~Command(){}
virtual void command() = 0;
private:
CommandPtr next;
friend class Executor;
};
class epicsShareClass Executor : public Runnable{
public:
POINTER_DEFINITIONS(Executor);
Executor(String threadName,ThreadPriority priority);
~Executor();
void execute(CommandPtr const &node);
virtual void run();
private:
CommandPtr head;
CommandPtr tail;
epics::pvData::Mutex mutex;
epics::pvData::Event moreWork;
epics::pvData::Event stopped;
epics::pvData::Thread thread;
};
}}
#endif /* EXECUTOR_H */

View File

@@ -1,8 +1,7 @@
/* localStaticLock.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.
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author mse

View File

@@ -1,114 +0,0 @@
/* messageQueue.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 <string>
#define epicsExportSharedSymbols
#include <pv/messageQueue.h>
namespace epics { namespace pvData {
MessageNode::MessageNode()
: messageType(infoMessage)
{}
String MessageNode::getMessage() const
{
return message;
}
MessageType MessageNode::getMessageType() const
{
return messageType;
}
MessageQueuePtr MessageQueue::create(int size)
{
MessageNodePtrArray nodeArray;
nodeArray.reserve(size);
for(int i=0; i<size; i++) {
nodeArray.push_back(
MessageNodePtr(new MessageNode()));
}
return std::tr1::shared_ptr<MessageQueue>(new MessageQueue(nodeArray));
}
MessageQueue::MessageQueue(MessageNodePtrArray &data)
: Queue<MessageNode>(data),
overrun(0)
{ }
MessageQueue::~MessageQueue()
{
}
MessageNodePtr &MessageQueue::get() {
if(getNumberUsed()==0) return nullNode;
lastGet = getUsed();
return lastGet;
}
void MessageQueue::release() {
if(lastGet.get()==NULL) return;
releaseUsed(lastGet);
lastGet.reset();
}
bool MessageQueue::put(String message,MessageType messageType,bool replaceLast)
{
MessageNodePtr node = getFree();
if(node.get()!= NULL) {
node->message = message;
node->messageType = messageType;
lastPut = node;
setUsed(node);
return true;
}
overrun++;
if(replaceLast) {
node = lastPut;
node->message = message;
node->messageType = messageType;
return true;
}
return false;
}
bool MessageQueue::isEmpty()
{
int free = getNumberFree();
if(free==capacity()) return true;
return false;
}
bool MessageQueue::isFull()
{
if(getNumberFree()==0) return true;
return false;
}
int MessageQueue::getClearOverrun()
{
int num = overrun;
overrun = 0;
return num;
}
MessageQueuePtr createMessageQueue(int size)
{
MessageNodePtrArray nodeArray;
nodeArray.reserve(size);
for(int i=0; i<size; i++) {
nodeArray.push_back(
MessageNodePtr(new MessageNode()));
}
return std::tr1::shared_ptr<MessageQueue>(new MessageQueue(nodeArray));
}
}}

View File

@@ -1,67 +0,0 @@
/* messageQueue.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 MESSAGEQUEUE_H
#define MESSAGEQUEUE_H
#include <memory>
#include <vector>
#include <cstddef>
#include <stdexcept>
#include <pv/pvType.h>
#include <pv/requester.h>
#include <pv/queue.h>
#include <shareLib.h>
namespace epics { namespace pvData {
class MessageNode;
class MessageQueue;
typedef std::tr1::shared_ptr<MessageNode> MessageNodePtr;
typedef std::vector<MessageNodePtr> MessageNodePtrArray;
typedef std::tr1::shared_ptr<MessageQueue> MessageQueuePtr;
class epicsShareClass MessageNode {
public:
MessageNode();
String getMessage() const;
MessageType getMessageType() const;
private:
String message;
MessageType messageType;
friend class MessageQueue;
};
class epicsShareClass MessageQueue : public Queue<MessageNode> {
public:
POINTER_DEFINITIONS(MessageQueue);
static MessageQueuePtr create(int size);
MessageQueue(MessageNodePtrArray &nodeArray);
virtual ~MessageQueue();
MessageNodePtr &get();
// 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 isEmpty() ;
bool isFull() ;
int getClearOverrun();
private:
MessageNodePtr nullNode;
MessageNodePtr lastGet;
MessageNodePtr lastPut;
uint32 overrun;
};
}}
#endif /* MESSAGEQUEUE_H */

View File

@@ -1,33 +0,0 @@
/* noDefaultMethods.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 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 epicsShareClass NoDefaultMethods {
protected:
// allow by derived objects
NoDefaultMethods(){};
~NoDefaultMethods(){}
private:
// do not implment
NoDefaultMethods(const NoDefaultMethods&);
NoDefaultMethods & operator=(const NoDefaultMethods &);
};
}}
#endif /* NO_DEFAULT_METHODS_H */

View File

@@ -1,3 +1,7 @@
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
#include <ctype.h>
#include <stdio.h>
#include <errno.h>
@@ -12,10 +16,12 @@
#include <epicsConvert.h>
#define epicsExportSharedSymbols
#include "typeCast.h"
#include "pv/typeCast.h"
using std::string;
// need to use "long long" when sizeof(int)==sizeof(long)
#if (ULONG_MAX == 0xfffffffful) || defined(_WIN32) || defined(__rtems__)
#if (ULONG_MAX == 0xfffffffful) || defined(_WIN32) || defined(__rtems__) || defined(__APPLE__)
#define NEED_LONGLONG
#endif
@@ -25,7 +31,7 @@
#endif
#if EPICS_VERSION_INT < VERSION_INT(3,15,0,1)
/* integer conversion primatives added to epicsStdlib.c in 3.15.0.1 */
/* These integer conversion primitives 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 */
@@ -247,7 +253,19 @@ epicsParseFloat(const char *str, float *to, char **units)
}
#endif
#if defined(NEED_LONGLONG) && (defined(__vxworks) || defined (_WIN32))
// Sometimes we have to provide our own copy of strtoll()
#if defined(_WIN32) && !defined(_MINGW)
// On Windows with MSVC, Base-3.15 provides strtoll()
# define NEED_OLL_FUNCS (EPICS_VERSION_INT < VERSION_INT(3,15,0,1))
#elif defined(vxWorks)
// On VxWorks, Base-3.15 provides strtoll()
# define NEED_OLL_FUNCS (EPICS_VERSION_INT < VERSION_INT(3,15,0,1))
#else
// Other architectures all provide strtoll()
# define NEED_OLL_FUNCS 0
#endif
#if defined(NEED_LONGLONG) && NEED_OLL_FUNCS
static
long long strtoll(const char *ptr, char ** endp, int base)
{
@@ -295,6 +313,73 @@ noconvert:
return 0;
}
#if defined(vxWorks)
/* The VxWorks version of std::istringstream >> uint64_t is buggy,
* provide our own implementation
*/
static
unsigned long long strtoull(const char *nptr, char **endptr, int base)
{
const char *s = nptr;
unsigned long long acc;
int c;
unsigned long long cutoff;
int neg = 0, any, cutlim;
do
c = *s++;
while (isspace(c));
if (c == '-')
{
neg = 1;
c = *s++;
}
else if (c == '+')
c = *s++;
if ((base == 0 || base == 16) &&
c == '0' && (*s == 'x' || *s == 'X'))
{
c = s[1];
s += 2;
base = 16;
}
if (base == 0)
base = c == '0' ? 8 : 10;
cutoff = (unsigned long long) UINT64_MAX / (unsigned long long) base;
cutlim = (unsigned long long) UINT64_MAX % (unsigned long long) base;
for (acc = 0, any = 0;; c = *s++)
{
if (isdigit(c))
c -= '0';
else if (isalpha(c))
c -= isupper(c) ? 'A' - 10 : 'a' - 10;
else
break;
if (c >= base)
break;
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
any = -1;
else
{
any = 1;
acc *= base;
acc += c;
}
}
if (any < 0)
{
acc = UINT64_MAX;
errno = ERANGE;
}
else if (neg)
acc = -acc;
if (endptr != 0)
*endptr = any ? (char *) s - 1 : (char *) nptr;
return (acc);
}
#else
static
unsigned long long strtoull(const char *ptr, char ** endp, int base)
{
@@ -337,7 +422,7 @@ noconvert:
*endp = (char*)ptr;
return 0;
}
#endif
#endif
/* do we need long long? */
@@ -422,18 +507,18 @@ void handleParseError(int err)
namespace epics { namespace pvData { namespace detail {
void parseToPOD(const std::string & in, boolean *out)
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");
throw std::runtime_error("parseToPOD: string no match true/false");
}
#define INTFN(T, S) \
void parseToPOD(const std::string& in, T *out) { \
void parseToPOD(const string& in, T *out) { \
epics ## S temp; \
int err = epicsParse ## S (in.c_str(), &temp, 0, NULL); \
if(err) handleParseError(err); \
@@ -447,7 +532,7 @@ INTFN(uint16_t, UInt16);
INTFN(int32_t, Int32);
INTFN(uint32_t, UInt32);
void parseToPOD(const std::string& in, int64_t *out) {
void parseToPOD(const string& in, int64_t *out) {
#ifdef NEED_LONGLONG
int err = epicsParseLongLong(in.c_str(), out, 0, NULL);
#else
@@ -456,7 +541,7 @@ void parseToPOD(const std::string& in, int64_t *out) {
if(err) handleParseError(err);
}
void parseToPOD(const std::string& in, uint64_t *out) {
void parseToPOD(const string& in, uint64_t *out) {
#ifdef NEED_LONGLONG
int err = epicsParseULongLong(in.c_str(), out, 0, NULL);
#else
@@ -465,14 +550,35 @@ void parseToPOD(const std::string& in, uint64_t *out) {
if(err) handleParseError(err);
}
void parseToPOD(const std::string& in, float *out) {
void parseToPOD(const string& in, float *out) {
int err = epicsParseFloat(in.c_str(), out, NULL);
if(err) handleParseError(err);
}
void parseToPOD(const std::string& in, double *out) {
void parseToPOD(const string& in, double *out) {
int err = epicsParseDouble(in.c_str(), out, NULL);
if(err) handleParseError(err);
#if defined(vxWorks)
/* vxWorks strtod returns [-]epicsINF when it should return ERANGE error.
* If [-]epicsINF is returned and the first char is a digit we translate
* this into an ERANGE error
*/
else if (*out == epicsINF || *out == -epicsINF) {
const char* s = in.c_str();
int c;
/* skip spaces and the sign */
do {
c = *s++;
} while (isspace(c));
if (c == '-' || c == '+')
c = *s++;
if (isdigit(c))
handleParseError(S_stdlib_overflow);
}
#endif
}
}}}

332
src/misc/pv/anyscalar.h Normal file
View File

@@ -0,0 +1,332 @@
#ifndef PV_ANYSCALAR_H
#define PV_ANYSCALAR_H
#if __cplusplus>=201103L
# include <type_traits>
#endif
#include <ostream>
#include <exception>
#include <map>
#include <epicsAssert.h>
#include <pv/templateMeta.h>
#include <pv/typeCast.h>
#include <pv/pvIntrospect.h> /* for ScalarType enum */
namespace epics{namespace pvData{
namespace detail {
// special mangling for AnyScalar ctor to map from argument type to storage type.
// allow construction from constants.
template <typename T>
struct any_storage_type { typedef T type; };
template<> struct any_storage_type<int> { typedef int32 type; };
template<> struct any_storage_type<unsigned> { typedef uint32 type; };
template<> struct any_storage_type<char*> { typedef std::string type; };
template<> struct any_storage_type<const char*> { typedef std::string type; };
#if __cplusplus>=201103L
// std::max() isn't constexpr until c++14 :(
constexpr size_t cmax(size_t A, size_t B) {
return A>B ? A : B;
}
#endif
}// namespace detail
/** A type-safe variant union capable of holding
* any of the PVD scalar types (POD or string)
*
@code
AnyScalar A(5);
assert(A.type()==pvInt);
assert(A.ref<int32>()==5);
assert(A.as<int32>()==5);
assert(A.as<double>()==5.0);
assert(A.ref<double>()==5.0); // throws AnyScalar::bad_cast
@endcode
*/
class AnyScalar {
public:
struct bad_cast : public std::exception {
#if __cplusplus>=201103L
bad_cast() noexcept {}
virtual ~bad_cast() noexcept {}
virtual const char* what() const noexcept
#else
bad_cast() throw() {}
virtual ~bad_cast() throw() {}
virtual const char* what() const throw()
#endif
{ return "bad_cast() type mis-match"; }
};
private:
ScalarType _stype;
// always reserve enough storage for std::string or double (assumed worst case)
#if __cplusplus>=201103L
struct wrap_t {
typename std::aligned_storage<detail::cmax(sizeof(std::string), sizeof(double)),
detail::cmax(alignof(std::string), alignof(double))
>::type blob[1];
} _wrap;
#else
struct wrap_t {
union blob_t {
char data[sizeof(std::string)];
double align_f; // assume std::string alignment <= 8
} blob[1];
} _wrap;
#endif
// assumed largest non-string type
typedef double _largest_blob;
template<typename T>
inline T& _as() {
return *reinterpret_cast<T*>(_wrap.blob);
}
template<typename T>
inline const T& _as() const {
return *reinterpret_cast<const T*>(_wrap.blob);
}
public:
AnyScalar() : _stype((ScalarType)-1) {}
template<typename T>
explicit AnyScalar(T v)
{
typedef typename meta::strip_const<T>::type T2;
typedef typename detail::any_storage_type<T2>::type TT;
STATIC_ASSERT(sizeof(TT)<=sizeof(_wrap.blob));
new (_wrap.blob) TT(v);
// this line fails to compile when type T can't be mapped to one of
// the PVD scalar types.
_stype = (ScalarType)ScalarTypeID<TT>::value;
}
AnyScalar(const AnyScalar& o)
:_stype(o._stype)
{
if(o._stype==pvString) {
new (_wrap.blob) std::string(o._as<std::string>());
} else if(o._stype!=(ScalarType)-1) {
memcpy(_wrap.blob, o._wrap.blob, sizeof(_largest_blob));
}
}
#if __cplusplus>=201103L
AnyScalar(AnyScalar&& o)
:_stype(o._stype)
{
typedef std::string string;
if(o._stype==pvString) {
new (_wrap.blob) std::string();
_as<std::string>() = std::move(o._as<std::string>());
o._as<string>().~string();
} else if(o._stype!=(ScalarType)-1) {
memcpy(_wrap.blob, o._wrap.blob, sizeof(_largest_blob));
}
o._stype = (ScalarType)-1;
}
#endif
~AnyScalar() {
if(_stype==pvString) {
typedef std::string string;
_as<string>().~string();
}
// other types need no cleanup
}
AnyScalar& operator=(const AnyScalar& o) {
AnyScalar(o).swap(*this);
return *this;
}
template<typename T>
AnyScalar& operator=(T v) {
AnyScalar(v).swap(*this);
return *this;
}
#if __cplusplus>=201103L
AnyScalar& operator=(AnyScalar&& o) {
if(_stype==pvString) {
typedef std::string string;
_as<string>().~string();
}
_stype = (ScalarType)-1;
swap(o);
return *this;
}
#endif
void swap(AnyScalar& o) {
typedef std::string string;
switch((int)_stype) {
case -1:
switch((int)o._stype) {
case -1:
// nil <-> nil
break;
case pvString:
// nil <-> string
new (_wrap.blob) std::string();
_as<std::string>().swap(o._as<std::string>());
o._as<std::string>().~string();
break;
default:
// nil <-> non-string
memcpy(_wrap.blob, o._wrap.blob, sizeof(_largest_blob));
break;
}
break;
case pvString:
switch((int)o._stype) {
case -1:
// string <-> nil
new (o._wrap.blob) std::string();
_as<std::string>().swap(o._as<std::string>());
_as<std::string>().~string();
break;
case pvString:
// string <-> string
_as<std::string>().swap(o._as<std::string>());
break;
default: {
// string <-> non-string
std::string temp;
temp.swap(_as<std::string>());
_as<std::string>().~string();
memcpy(_wrap.blob, o._wrap.blob, sizeof(_largest_blob));
new (o._wrap.blob) std::string();
temp.swap(o._as<std::string>());
}
break;
}
break;
default:
switch((int)o._stype) {
case -1:
// non-string <-> nil
memcpy(o._wrap.blob, _wrap.blob, sizeof(_largest_blob));
break;
case pvString: {
// non-string <-> string
std::string temp;
temp.swap(o._as<std::string>());
o._as<std::string>().~string();
memcpy(o._wrap.blob, _wrap.blob, sizeof(_largest_blob));
new (_wrap.blob) std::string();
temp.swap(_as<std::string>());
}
break;
default:
// non-string <-> non-string
_largest_blob temp;
memcpy(&temp, _wrap.blob, sizeof(_largest_blob));
memcpy(_wrap.blob, o._wrap.blob, sizeof(_largest_blob));
memcpy(o._wrap.blob, &temp, sizeof(_largest_blob));
// std::swap(o._wrap.blob, _wrap.blob); // gcc <=4.3 doesn't like this
break;
}
break;
}
std::swap(_stype, o._stype);
}
inline ScalarType type() const {
return _stype;
}
void* unsafe() { return _wrap.blob; }
const void* unsafe() const { return _wrap.blob; }
inline bool empty() const { return _stype==(ScalarType)-1; }
#if __cplusplus>=201103L
explicit operator bool() const { return !empty(); }
#else
private:
typedef void (AnyScalar::*bool_type)(AnyScalar&);
public:
operator bool_type() const { return !empty() ? &AnyScalar::swap : 0; }
#endif
/** Return reference to wrapped value */
template<typename T>
// T -> strip_const -> map to storage type -> add reference
typename detail::any_storage_type<typename meta::strip_const<T>::type>::type&
ref() {
typedef typename meta::strip_const<T>::type T2;
typedef typename detail::any_storage_type<T2>::type TT;
if(_stype!=(ScalarType)ScalarTypeID<TT>::value)
throw bad_cast();
return _as<TT>();
}
template<typename T>
// T -> strip_const -> map to storage type -> add const reference
typename meta::decorate_const<typename detail::any_storage_type<typename meta::strip_const<T>::type>::type>::type&
ref() const {
typedef typename meta::strip_const<T>::type T2;
typedef typename detail::any_storage_type<T2>::type TT;
if(_stype!=(ScalarType)ScalarTypeID<TT>::value)
throw bad_cast();
return _as<TT>();
}
/** copy out wrapped value, with a value conversion. */
template<typename T>
T as() const {
typedef typename meta::strip_const<T>::type T2;
typedef typename detail::any_storage_type<T2>::type TT;
if(_stype==(ScalarType)-1)
throw bad_cast();
TT ret;
castUnsafeV(1, (ScalarType)ScalarTypeID<T2>::value, &ret,
_stype, _wrap.blob);
return ret;
}
private:
friend std::ostream& operator<<(std::ostream& strm, const AnyScalar& v);
};
inline
std::ostream& operator<<(std::ostream& strm, const AnyScalar& v)
{
switch(v.type()) {
#define CASE(BASETYPE, PVATYPE, DBFTYPE, PVACODE) case pv ## PVACODE: strm<<v._as<PVATYPE>(); break;
#define CASE_REAL_INT64
#define CASE_STRING
#include "pv/typemap.h"
#undef CASE
#undef CASE_REAL_INT64
#undef CASE_STRING
default:
strm<<"(nil)"; break;
}
return strm;
}
}} // namespace epics::pvData
#endif // PV_ANYSCALAR_H

View File

@@ -1,8 +1,7 @@
/* bitSet.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.
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author mse
@@ -10,7 +9,11 @@
#ifndef BITSET_H
#define BITSET_H
#include <stdexcept>
#if __cplusplus>=201103L
# include <initializer_list>
#endif
#include <vector>
#include <pv/pvType.h>
#include <pv/serialize.h>
@@ -24,16 +27,18 @@ namespace epics { namespace pvData {
typedef std::tr1::shared_ptr<BitSet> BitSetPtr;
/**
* @brief A vector of bits.
*
* This class implements a vector of bits that grows as needed. Each
* component of the bit set has a {@code bool} value. The
* bits of a {@code BitSet} are indexed by nonnegative integers.
* Individual indexed bits can be examined, set, or cleared. One
* {@code BitSet} may be used to modify the contents of another
* {@code BitSet} through logical AND, logical inclusive OR, and
* logical exclusive OR operations.
* component of the bit set has a @c bool value. The bits of a
* @c BitSet are indexed by nonnegative integers. Individual
* indexed bits can be examined, set, or cleared. One @c BitSet may
* be used to modify the contents of another @c BitSet through
* logical AND, logical inclusive OR, and logical exclusive OR
* operations.
*
* <p>By default, all bits in the set initially have the value
* {@code false}.
* @c false.
*
* <p>Every bit set has a current size, which is the number of bits
* of space currently in use by the bit set. Note that the size is
@@ -41,8 +46,8 @@ namespace epics { namespace pvData {
* implementation. The length of a bit set relates to logical length
* of a bit set and is defined independently of implementation.
*
* <p>A {@code BitSet} is not safe for multithreaded use without
* external synchronization.
* <p>A @c BitSet is not safe for multithreaded use without external
* synchronization.
*
* Based on Java implementation.
*/
@@ -51,19 +56,29 @@ namespace epics { namespace pvData {
POINTER_DEFINITIONS(BitSet);
static BitSetPtr create(uint32 nbits);
/**
* Creates a new bit set. All bits are initially {@code false}.
* Creates a new bit set. All bits are initially @c false.
*/
BitSet();
/**
* Creates a bit set whose initial size is large enough to explicitly
* represent bits with indices in the range {@code 0} through
* {@code nbits-1}. All bits are initially {@code false}.
* represent bits with indices in the range @c 0 through
* @c nbits-1. All bits are initially @c false.
*
* @param nbits the initial size of the bit set
*/
BitSet(uint32 nbits);
#if __cplusplus>=201103L
/** Initialize from a list of indicies
@code
BitSet X({1, 5});
assert(X.get(1) && X.get(5));
@endcode
*/
BitSet(std::initializer_list<uint32> I);
#endif
/**
* Destructor.
*/
@@ -75,21 +90,21 @@ namespace epics { namespace pvData {
*
* @param bitIndex the index of the bit to flip
*/
void flip(uint32 bitIndex);
BitSet& flip(uint32 bitIndex);
/**
* Sets the bit at the specified index to {@code true}.
* Sets the bit at the specified index to @c true.
*
* @param bitIndex a bit index
*/
void set(uint32 bitIndex);
BitSet& set(uint32 bitIndex);
/**
* Sets the bit specified by the index to {@code false}.
* Sets the bit specified by the index to @c false.
*
* @param bitIndex the index of the bit to be cleared
*/
void clear(uint32 bitIndex);
BitSet& clear(uint32 bitIndex);
/**
* Sets the bit at the specified index to the specified value.
@@ -101,9 +116,8 @@ namespace epics { namespace pvData {
/**
* Returns the value of the bit with the specified index. The value
* is {@code true} if the bit with the index {@code bitIndex}
* is currently set in this {@code BitSet}; otherwise, the result
* is {@code false}.
* is @c true if the bit with the index @c bitIndex is currently
* set in this @c BitSet; otherwise, the result is @c false.
*
* @param bitIndex the bit index
* @return the value of the bit with the specified index
@@ -111,16 +125,16 @@ namespace epics { namespace pvData {
bool get(uint32 bitIndex) const;
/**
* Sets all of the bits in this BitSet to {@code false}.
* Sets all of the bits in this BitSet to @c false.
*/
void clear();
/**
* Returns the index of the first bit that is set to {@code true}
* that occurs on or after the specified starting index. If no such
* bit exists then {@code -1} is returned.
* Returns the index of the first bit that is set to @c true that
* occurs on or after the specified starting index. If no such bit
* exists then @c -1 is returned.
*
* <p>To iterate over the {@code true} bits in a {@code BitSet},
* <p>To iterate over the @c true bits in a @c BitSet,
* use the following loop:
*
* <pre> {@code
@@ -129,13 +143,13 @@ namespace epics { namespace pvData {
* }}</pre>
*
* @param fromIndex the index to start checking from (inclusive)
* @return the index of the next set bit, or {@code -1} if there
* @return the index of the next set bit, or @c -1 if there
* is no such bit
*/
int32 nextSetBit(uint32 fromIndex) const;
/**
* Returns the index of the first bit that is set to {@code false}
* Returns the index of the first bit that is set to @c false
* that occurs on or after the specified starting index.
*
* @param fromIndex the index to start checking from (inclusive)
@@ -144,61 +158,66 @@ namespace epics { namespace pvData {
int32 nextClearBit(uint32 fromIndex) const;
/**
* Returns true if this {@code BitSet} contains no bits that are set
* to {@code true}.
* Returns true if this @c BitSet contains no bits that are set
* to @c true.
*
* @return indicating whether this {@code BitSet} is empty
* @return indicating whether this @c BitSet is empty
*/
bool isEmpty() const;
/**
* Returns the number of bits set to {@code true} in this {@code BitSet}.
* Returns the number of bits set to @c true in this @c BitSet.
*
* @return the number of bits set to {@code true} in this {@code BitSet}
* @return the number of bits set to @c true in this @c BitSet
*/
uint32 cardinality() const;
/**
* Returns the number of bits of space actually in use by this
* {@code BitSet} to represent bit values.
* @c BitSet to represent bit values.
* The maximum element in the set is the size - 1st element.
*
* @return the number of bits currently in this bit set
*/
uint32 size() const;
//! Returns true if any bit is set in both *this and other
bool logical_and(const BitSet& other) const;
//! Returns true if any bit is set in both *this or other
bool logical_or(const BitSet& other) const;
/**
* Performs a logical <b>AND</b> of this target bit set with the
* Performs a bitwise <b>AND</b> of this target bit set with the
* argument bit set. This bit set is modified so that each bit in it
* has the value {@code true} if and only if it both initially
* had the value {@code true} and the corresponding bit in the
* bit set argument also had the value {@code true}.
* has the value @c true if and only if it both initially
* had the value @c true and the corresponding bit in the
* bit set argument also had the value @c true.
*
* @param set a bit set
*/
BitSet& operator&=(const BitSet& set);
/**
* Performs a logical <b>OR</b> of this bit set with the bit set
* Performs a bitwise <b>OR</b> of this bit set with the bit set
* argument. This bit set is modified so that a bit in it has the
* value {@code true} if and only if it either already had the
* value {@code true} or the corresponding bit in the bit set
* argument has the value {@code true}.
* value @c true if and only if it either already had the
* value @c true or the corresponding bit in the bit set
* argument has the value @c true.
*
* @param set a bit set
*/
BitSet& operator|=(const BitSet& set);
/**
* Performs a logical <b>XOR</b> of this bit set with the bit set
* Performs a bitwise <b>XOR</b> of this bit set with the bit set
* argument. This bit set is modified so that a bit in it has the
* value {@code true} if and only if one of the following
* value @c true if and only if one of the following
* statements holds:
* <ul>
* <li>The bit initially has the value {@code true}, and the
* corresponding bit in the argument has the value {@code false}.
* <li>The bit initially has the value {@code false}, and the
* corresponding bit in the argument has the value {@code true}.
* <li>The bit initially has the value @c true, and the
* corresponding bit in the argument has the value @c false.
* <li>The bit initially has the value @c false, and the
* corresponding bit in the argument has the value @c true.
* </ul>
*
* @param set a bit set
@@ -206,10 +225,13 @@ namespace epics { namespace pvData {
BitSet& operator^=(const BitSet& set);
/**
* Assigment operator.
* Assignment operator.
*/
BitSet& operator=(const BitSet &set);
//! Swap contents
void swap(BitSet& set);
/**
* Perform AND operation on <code>set1</code> and <code>set2</code>,
* and OR on result and this instance.
@@ -225,8 +247,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,
@@ -234,42 +254,11 @@ namespace epics { namespace pvData {
private:
/*
* BitSets are packed into arrays of "words." Currently a word is
* a long, which consists of 64 bits, requiring 6 address bits.
* The choice of word size is determined purely by performance concerns.
*/
static const uint32 ADDRESS_BITS_PER_WORD = 6;
static const uint32 BITS_PER_WORD = 1 << ADDRESS_BITS_PER_WORD;
static const uint32 BIT_INDEX_MASK = BITS_PER_WORD - 1;
/** Used to shift left or right for a partial word mask */
static const uint64 WORD_MASK = ~((uint64)0);
typedef std::vector<uint64> words_t;
/** The internal field corresponding to the serialField "bits". */
uint64* words;
/** The internal field corresponding to the size of words[] array. */
uint32 wordsLength;
/** The number of words in the logical size of this BitSet. */
uint32 wordsInUse;
words_t words;
private:
/**
* Given a bit index, return word index containing it.
*/
static inline uint32 wordIndex(uint32 bitIndex) {
return bitIndex >> ADDRESS_BITS_PER_WORD;
}
/**
* Creates a new word array.
*/
void initWords(uint32 nbits);
/**
* Sets the field wordsInUse to the logical size in words of the bit set.
* WARNING: This method assumes that the number of words actually in use is
@@ -317,6 +306,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

@@ -1,8 +1,7 @@
/* byteBuffer.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.
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author mse
@@ -11,175 +10,158 @@
#define BYTEBUFFER_H
#include <string>
#include <string.h>
#ifdef epicsExportSharedSymbols
#define byteBufferepicsExportSharedSymbols
#undef epicsExportSharedSymbols
#endif
#include <cstring>
#include <cstdlib>
#include <epicsEndian.h>
#include <shareLib.h>
#include <epicsAssert.h>
#ifdef byteBufferepicsExportSharedSymbols
#define epicsExportSharedSymbols
#undef byteBufferepicsExportSharedSymbols
#endif
#include <pv/templateMeta.h>
#include <pv/pvType.h>
#include <pv/epicsException.h>
#include <shareLib.h>
namespace epics {
namespace pvData {
/*
TODO can be used:
#ifndef EPICS_ALWAYS_INLINE
# define EPICS_ALWAYS_INLINE inline
#endif
MS Visual C++:
/* various compilers provide builtins for byte order swaps.
* conditions based on boost endian library
*/
#if defined(__GNUC__) && ((__GNUC__>4) || (__GNUC__==4 && __GNUC_MINOR__>=3))
You include intrin.h and call the following functions:
#if (__GNUC__>4) || (__GNUC__==4 && __GNUC_MINOR__>=8)
#define _PVA_swap16(X) __builtin_bswap16(X)
#endif
For 16 bit numbers:
unsigned short _byteswap_ushort(unsigned short value);
#define _PVA_swap32(X) __builtin_bswap32(X)
#define _PVA_swap64(X) __builtin_bswap64(X)
For 32 bit numbers:
unsigned long _byteswap_ulong(unsigned long value);
#elif defined(__clang__)
For 64 bit numbers:
unsigned __int64 _byteswap_uint64(unsigned __int64 value);
*/
#if __has_builtin(__builtin_bswap16)
#define _PVA_swap16(X) __builtin_bswap16(X)
#endif
#if __has_builtin(__builtin_bswap32)
#define _PVA_swap32(X) __builtin_bswap32(X)
#endif
#if __has_builtin(__builtin_bswap64)
#define _PVA_swap64(X) __builtin_bswap64(X)
#endif
/*
For floats and doubles it's more difficult as with plain integers as these may or not may be in the host machines byte-order.
You can get little-endian floats on big-endian machines and vice versa.
*/
#elif defined(_MSC_VER)
#define GCC_VERSION_SINCE(major, minor, patchlevel) \
(defined(__GNUC__) && !defined(__INTEL_COMPILER) && \
((__GNUC__ > (major)) || \
(__GNUC__ == (major) && __GNUC_MINOR__ > (minor)) || \
(__GNUC__ == (major) && __GNUC_MINOR__ == (minor) && __GNUC_PATCHLEVEL__ >= (patchlevel))))
#if GCC_VERSION_SINCE(4,3,0)
#define swap32(x) __builtin_bswap32(x)
#define swap64(x) __builtin_bswap64(x)
#define __byte_swap16(x) \
(((x) >> 8) | \
((x) << 8))
static inline uint16_t
swap16(uint16_t _x)
{
return (__byte_swap16(_x));
}
#else
#define __byte_swap16(x) \
(((x) >> 8) | \
((x) << 8))
#define __byte_swap32(x) \
((((x) & 0xff000000) >> 24) | \
(((x) & 0x00ff0000) >> 8) | \
(((x) & 0x0000ff00) << 8) | \
(((x) & 0x000000ff) << 24))
#define __byte_swap64(x) \
(((x) >> 56) | \
(((x) >> 40) & 0xff00) | \
(((x) >> 24) & 0xff0000) | \
(((x) >> 8) & 0xff000000) | \
(((x) << 8) & ((uint64_t)0xff << 32)) | \
(((x) << 24) & ((uint64_t)0xff << 40)) | \
(((x) << 40) & ((uint64_t)0xff << 48)) | \
(((x) << 56)))
static inline uint16_t
swap16(uint16_t _x)
{
return (__byte_swap16(_x));
}
static inline uint32_t
swap32(uint32_t _x)
{
return (__byte_swap32(_x));
}
static inline uint64_t
swap64(uint64_t _x)
{
return (__byte_swap64(_x));
}
#define _PVA_swap16(X) _byteswap_ushort(X)
#define _PVA_swap32(X) _byteswap_ulong(X)
#define _PVA_swap64(X) _byteswap_uint64(X)
#endif
namespace epics {namespace pvData {
namespace detail {
template<typename T>
inline T swap(T val) { return val; } // not valid
struct asInt {
static EPICS_ALWAYS_INLINE T from(T v) { return v; }
static EPICS_ALWAYS_INLINE T to(T v) { return v; }
};
template<>
inline int16 swap(int16 val)
{
return swap16(val);
}
struct asInt<float> {
union pun {float f; uint32 i;};
static EPICS_ALWAYS_INLINE float from(uint32 v) {
pun P;
P.i = v;
return P.f;
}
static EPICS_ALWAYS_INLINE uint32 to(float v) {
pun P;
P.f = v;
return P.i;
}
};
template<>
inline int32 swap(int32 val)
{
return swap32(val);
}
struct asInt<double> {
union pun {double f; uint64 i;};
static EPICS_ALWAYS_INLINE double from(uint64 v) {
pun P;
P.i = v;
return P.f;
}
static EPICS_ALWAYS_INLINE uint64 to(double v) {
pun P;
P.f = v;
return P.i;
}
};
template<int N>
struct swap; // no default
template<>
inline int64 swap(int64 val)
{
return swap64(val);
}
struct swap<1> {
static EPICS_ALWAYS_INLINE uint8 op(uint8 v) { return v; }
};
template<>
struct swap<2> {
static EPICS_ALWAYS_INLINE uint16 op(uint16 v) {
#ifdef _PVA_swap16
return _PVA_swap16(v);
#else
return (((v) >> 8) | ((v) << 8));
#endif
}
};
template<>
struct swap<4> {
static EPICS_ALWAYS_INLINE uint32 op(uint32 v) {
#ifdef _PVA_swap32
return _PVA_swap32(v);
#else
return ((((v) & 0xff000000) >> 24) |
(((v) & 0x00ff0000) >> 8) |
(((v) & 0x0000ff00) << 8) |
(((v) & 0x000000ff) << 24));
#endif
}
};
template<>
struct swap<8> {
#ifdef _PVA_swap64
static EPICS_ALWAYS_INLINE uint64 op(uint64 v) {
return _PVA_swap64(v);
}
#else
static inline uint64 op(uint64 v) {
return (((v) >> 56) | \
(((v) >> 40) & 0x0000ff00) | \
(((v) >> 24) & 0x00ff0000) | \
(((v) >> 8) & 0xff000000) | \
(((v) << 8) & ((uint64_t)0xff << 32)) | \
(((v) << 24) & ((uint64_t)0xff << 40)) | \
(((v) << 40) & ((uint64_t)0xff << 48)) | \
(((v) << 56)));
}
#endif
};
template<>
inline float swap(float val)
{
union {
int32 i;
float f;
} conv;
conv.f = val;
conv.i = swap32(conv.i);
return conv.f;
}
#undef _PVA_swap16
#undef _PVA_swap32
#undef _PVA_swap64
template<>
inline double swap(double val)
} // namespace detail
//! Unconditional byte order swap.
//! defined for integer and floating point types
template<typename T>
EPICS_ALWAYS_INLINE T swap(T val)
{
union {
int64 i;
double d;
} conv;
conv.d = val;
conv.i = swap64(conv.i);
return conv.d;
return detail::asInt<T>::from(
detail::swap<sizeof(T)>::op(
detail::asInt<T>::to(val)));
}
#define is_aligned(POINTER, BYTE_COUNT) \
(((std::ptrdiff_t)(const void *)(POINTER)) % (BYTE_COUNT) == 0)
/*template <bool ENDIANESS_SUPPORT = false,
bool UNALIGNED_ACCESS = false,
bool ADAPTIVE_ACCESS = true,
bool USE_INLINE_MEMCPY = true>*/
#define ENDIANESS_SUPPORT true
#define UNALIGNED_ACCESS true
#define ADAPTIVE_ACCESS true
#define USE_INLINE_MEMCPY true
(((std::size_t)(POINTER)) % (BYTE_COUNT) == 0)
#if defined (__GNUC__) && (__GNUC__ < 3)
#define GET(T) get((T*)0)
@@ -188,8 +170,9 @@ inline double swap(double val)
#endif
/**
* This class implements {@code Bytebuffer} that is like the {@code java.nio.ByteBuffer}.
* <p>A {@code BitSet} is not safe for multithreaded use without
* @brief This class implements a Bytebuffer that is like the java.nio.ByteBuffer.
*
* <p>A @c BitSet is not safe for multithreaded use without
* external synchronization.
*
* Based on Java implementation.
@@ -205,19 +188,20 @@ public:
* 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),
_buffer((char*)std::malloc(size)), _size(size),
_reverseEndianess(byteOrder != EPICS_BYTE_ORDER),
_reverseFloatEndianess(byteOrder != EPICS_FLOAT_WORD_ORDER),
_wrapped(false)
{
_buffer = (char*)malloc(size);
if(!_buffer)
throw std::bad_alloc();
clear();
}
/**
* Constructor for wrapping existing buffers.
* Constructor for wrapping an existing buffer.
* Given buffer will not be released by the ByteBuffer instance.
* @param buffer Existing buffer.
* @param buffer Existing buffer. May not be NULL.
* @param size The number of bytes.
* @param byteOrder The byte order.
* Must be one of EPICS_BYTE_ORDER,EPICS_ENDIAN_LITTLE,EPICS_ENDIAN_BIG.
@@ -228,6 +212,8 @@ public:
_reverseFloatEndianess(byteOrder != EPICS_FLOAT_WORD_ORDER),
_wrapped(true)
{
if(!_buffer)
throw std::invalid_argument("ByteBuffer can't be constructed with NULL");
clear();
}
/**
@@ -235,7 +221,7 @@ public:
*/
~ByteBuffer()
{
if (_buffer && !_wrapped) free(_buffer);
if (_buffer && !_wrapped) std::free(_buffer);
}
/**
* Set the byte order.
@@ -252,7 +238,7 @@ public:
* Get the raw buffer data.
* @return the raw buffer data.
*/
inline const char* getBuffer()
inline const char* getBuffer() const
{
return _buffer;
}
@@ -266,8 +252,18 @@ public:
_limit = _buffer + _size;
}
/**
* Makes a buffer ready for a new sequence of channel-write or relative get operations:
* It sets the limit to the current position and then sets the position to zero.
* Makes a buffer ready to read out previously written values.
*
* Typically _limit==_buffer+_size is the initial state, but this is not
* required.
*
* V _buffer V _position V _limit V _buffer+_size
* |_______written_______|____uninitialized___|____allocated___|
*
* becomes
*
* V _buffer/_position V _limit V _buffer+size
* |_______written_______|________________allocated____________|
*/
inline void flip() {
_limit = _position;
@@ -276,6 +272,16 @@ public:
/**
* Makes a buffer ready for re-reading the data that it already contains:
* It leaves the limit unchanged and sets the position to zero.
*
* Note that this may allow reading of uninitialized values. flip() should be considered
*
* V _buffer V _position V _limit V _buffer+_size
* |_______written_______|____uninitialized___|____allocated___|
*
* becomes
*
* V _buffer/_position V _limit V _buffer+size
* |_______written_______|____uninitialized___|____allocated___|
*/
inline void rewind() {
_position = _buffer;
@@ -284,9 +290,9 @@ public:
* Returns the current position.
* @return The current position in the raw data.
*/
inline std::size_t getPosition()
inline std::size_t getPosition() const
{
return (std::size_t)(((std::ptrdiff_t)(const void *)_position) - ((std::ptrdiff_t)(const void *)_buffer));
return _position - _buffer;
}
/**
* Sets the buffer position.
@@ -297,16 +303,18 @@ public:
*/
inline void setPosition(std::size_t pos)
{
assert(pos<=_size);
_position = _buffer + pos;
assert(_position<=_limit);
}
/**
* Returns this buffer's limit.
*
* @return The offset into the raw buffer.
*/
inline std::size_t getLimit()
inline std::size_t getLimit() const
{
return (std::size_t)(((std::ptrdiff_t)(const void *)_limit) - ((std::ptrdiff_t)(const void *)_buffer));
return _limit - _buffer;
}
/**
* Sets this buffer's limit.
@@ -318,23 +326,25 @@ public:
*/
inline void setLimit(std::size_t limit)
{
assert(limit<=_size);
_limit = _buffer + limit;
assert(_position<=_limit);
}
/**
* Returns the number of elements between the current position and the limit.
*
* @return The number of elements remaining in this buffer.
*/
inline std::size_t getRemaining()
inline std::size_t getRemaining() const
{
return (std::size_t)(((std::ptrdiff_t)(const void *)_limit) - ((std::ptrdiff_t)(const void *)_position));
return _limit - _position;
}
/**
* Returns The size, i.e. capacity of the raw data buffer in bytes.
*
* @return The size of the raw data buffer.
*/
inline std::size_t getSize()
inline std::size_t getSize() const
{
return _size;
}
@@ -352,9 +362,9 @@ public:
* @param value The value to be put into the byte buffer.
*/
template<typename T>
inline void put(std::size_t index, T value);
inline void put(std::size_t index, T value) const;
/**
* Get the new object from the byte buffer. The item MUST have type {@code T}.
* Get the new object from the byte buffer. The item MUST have type @c T.
* The position is adjusted based on the type.
*
* @return The object.
@@ -368,24 +378,25 @@ public:
#endif
/**
* Get the new object from the byte buffer at the specified index.
* The item MUST have type {@code T}.
* The item MUST have type @c T.
* The position is adjusted based on the type.
*
* @param index The location in the byte buffer.
* @return The object.
*/
template<typename T>
inline T get(std::size_t index);
inline T get(std::size_t index) const;
/**
* Put a sub-array of bytes into the byte buffer.
* The position is increased by the count.
*
* @param src The source array.
* @param offset The starting position within src.
* @param count The number of bytes to put into the byte buffer,
* @param src The source array.
* @param src_offset The starting position within src.
* @param count The number of bytes to put into the byte buffer.
* Must be less than getRemaining()
*/
inline void put(const char* src, std::size_t src_offset, std::size_t count) {
//if(count>getRemaining()) THROW_BASE_EXCEPTION("buffer overflow");
assert(count<=getRemaining());
memcpy(_position, src + src_offset, count);
_position += count;
}
@@ -393,17 +404,18 @@ public:
* Get a sub-array of bytes from the byte buffer.
* The position is increased by the count.
*
* @param dest The destination array.
* @param offset The starting position within src.
* @param count The number of bytes to put into the byte buffer,
* @param dest The destination array.
* @param dest_offset The starting position within src.
* @param count The number of bytes to put into the byte buffer.
* Must be less than getRemaining()
*/
inline void get(char* dest, std::size_t dest_offset, std::size_t count) {
//if(count>getRemaining()) THROW_BASE_EXCEPTION("buffer overflow");
assert(count<=getRemaining());
memcpy(dest + dest_offset, _position, count);
_position += count;
}
/**
* Put an array of type {@code T} into the byte buffer.
* Put an array of type @c T into the byte buffer.
* The position is adjusted.
*
* @param values The input array.
@@ -412,7 +424,7 @@ public:
template<typename T>
inline void putArray(const T* values, std::size_t count);
/**
* Get an array of type {@code T} from the byte buffer.
* Get an array of type @c T from the byte buffer.
* The position is adjusted.
*
* @param values The destination array.
@@ -425,19 +437,26 @@ public:
* @return (false,true) if (is, is not) the EPICS_BYTE_ORDER
*/
template<typename T>
inline bool reverse()
EPICS_ALWAYS_INLINE bool reverse() const
{
return _reverseEndianess;
return sizeof(T)>1 && _reverseEndianess;
}
/**
* Adjust position so that it is aligned to the specified size.
* Size MUST be a power of 2.
* @param size The alignment requirement.
* Adjust position to the next multiple of 'size.
* @param size The alignment requirement, must be a power of 2. (unchecked)
* @param fill value to use for padding bytes (default '\0').
*
* @note This alignment is absolute, not necessarily with respect to _buffer.
*/
inline void align(std::size_t size)
inline void align(std::size_t size, char fill='\0')
{
const std::size_t k = size - 1;
_position = (char*)((((std::ptrdiff_t)(const void *)_position) + k) & ~(k));
const std::size_t k = size - 1, bufidx = (std::size_t)_position;
if(bufidx&k) {
std::size_t npad = size-(bufidx&k);
assert(npad<=getRemaining());
std::fill(_position, _position+npad, fill);
_position += npad;
}
}
/**
* Put a boolean value into the byte buffer.
@@ -618,54 +637,54 @@ public:
/**
* Get a boolean value from the byte buffer at the specified index.
*
* @param double The offset in the byte buffer.
* @param index The offset in the byte buffer.
* @return The value.
*/
inline double getDouble (std::size_t index) { return get<double>(index); }
// TODO remove
inline const char* getArray()
inline const char* getArray() const
{
return _buffer;
}
private:
char* _buffer;
char* const _buffer;
char* _position;
char* _limit;
std::size_t _size;
const std::size_t _size;
bool _reverseEndianess;
bool _reverseFloatEndianess;
bool _wrapped;
const bool _wrapped;
};
template<>
inline bool ByteBuffer::reverse<bool>()
inline bool ByteBuffer::reverse<bool>() const
{
return false;
}
template<>
inline bool ByteBuffer::reverse<int8>()
inline bool ByteBuffer::reverse<int8>() const
{
return false;
}
template<>
inline bool ByteBuffer::reverse<uint8>()
inline bool ByteBuffer::reverse<uint8>() const
{
return false;
}
template<>
inline bool ByteBuffer::reverse<float>()
inline bool ByteBuffer::reverse<float>() const
{
return _reverseFloatEndianess;
}
template<>
inline bool ByteBuffer::reverse<double>()
inline bool ByteBuffer::reverse<double>() const
{
return _reverseFloatEndianess;
}
@@ -675,96 +694,26 @@ private:
template<typename T>
inline void ByteBuffer::put(T value)
{
// this avoids int8 specialization, compiler will take care if optimization, -O2 or more
if (sizeof(T) == 1)
{
*(_position++) = (int8)value;
return;
}
assert(sizeof(T)<=getRemaining());
if (ENDIANESS_SUPPORT && reverse<T>())
{
if(reverse<T>())
value = swap<T>(value);
}
if (UNALIGNED_ACCESS)
{
// NOTE: some CPU handle unaligned access pretty good (e.g. x86)
*((T*)_position) = value;
_position += sizeof(T);
}
else
{
// NOTE: this check and branching does not always payoff
if (ADAPTIVE_ACCESS && is_aligned(_position, sizeof(T)))
{
*((T*)_position) = value;
_position += sizeof(T);
}
else
{
if (USE_INLINE_MEMCPY)
{
// NOTE: it turns out that this compiler can optimize this with inline code, e.g. gcc
memcpy(_position, &value, sizeof(T));
_position += sizeof(T);
}
else
{
// NOTE: compiler should optimize this and unroll the loop
for (size_t i = 0; i < sizeof(T); i++)
_position[i] = ((char*)&value)[i];
_position += sizeof(T);
}
}
}
//assert(is_aligned(_position, sizeof(T)));
*((T*)_position) = value;
_position += sizeof(T);
}
template<typename T>
inline void ByteBuffer::put(std::size_t index, T value)
inline void ByteBuffer::put(std::size_t index, T value) const
{
// this avoids int8 specialization, compiler will take care if optimization, -O2 or more
if (sizeof(T) == 1)
{
*(_buffer + index) = (int8)value;
return;
}
assert(_buffer+index<=_limit);
if (ENDIANESS_SUPPORT && reverse<T>())
{
if(reverse<T>())
value = swap<T>(value);
}
if (UNALIGNED_ACCESS)
{
// NOTE: some CPU handle unaligned access preety good (e.g. x86)
*((T*)(_buffer + index)) = value;
}
else
{
// NOTE: this check and branching does not always payoff
if (ADAPTIVE_ACCESS && is_aligned(_position, sizeof(T)))
{
*((T*)(_buffer + index)) = value;
}
else
{
if (USE_INLINE_MEMCPY)
{
// NOTE: it turns out that this compiler can optimize this with inline code, e.g. gcc
memcpy(_buffer + index, &value, sizeof(T));
}
else
{
// NOTE: compiler should optimize this and unroll the loop
char *p = _buffer + index;
for (size_t i = 0; i < sizeof(T); i++)
p[i] = ((char*)&value)[i];
}
}
}
//assert(is_aligned(_buffer+index, sizeof(T))); //TODO: special case for targets which support unaligned access
*((T*)(_buffer+index)) = value;
}
#if defined (__GNUC__) && (__GNUC__ < 3)
@@ -775,160 +724,65 @@ private:
inline T ByteBuffer::get()
#endif
{
// this avoids int8 specialization, compiler will take care if optimization, -O2 or more
if (sizeof(T) == 1)
{
return (int8)(*(_position++));
}
assert(sizeof(T)<=getRemaining());
//assert(is_aligned(_position, sizeof(T)));
T value = *((T*)_position);
_position += sizeof(T);
T value;
if (UNALIGNED_ACCESS)
{
// NOTE: some CPU handle unaligned access preety good (e.g. x86)
value = *((T*)_position);
_position += sizeof(T);
}
else
{
// NOTE: this check and branching does not always payoff
if (ADAPTIVE_ACCESS && is_aligned(_position, sizeof(T)))
{
value = *((T*)_position);
_position += sizeof(T);
}
else
{
if (USE_INLINE_MEMCPY)
{
// NOTE: it turns out that this compiler can optimize this with inline code, e.g. gcc
memcpy(&value, _position, sizeof(T));
_position += sizeof(T);
}
else
{
// NOTE: compiler should optimize this and unroll the loop
for (size_t i = 0; i < sizeof(T); i++)
((char*)&value)[i] = _position[i];
_position += sizeof(T);
}
}
}
if (ENDIANESS_SUPPORT && reverse<T>())
{
if(reverse<T>())
value = swap<T>(value);
}
return value;
}
template<typename T>
inline T ByteBuffer::get(std::size_t index)
inline T ByteBuffer::get(std::size_t index) const
{
// this avoids int8 specialization, compiler will take care if optimization, -O2 or more
if (sizeof(T) == 1)
{
return (int8)(*(_buffer + index));
}
assert(_buffer+index<=_limit);
//assert(is_aligned(_position, sizeof(T)));
T value = *((T*)(_buffer + index));
T value;
if (UNALIGNED_ACCESS)
{
// NOTE: some CPU handle unaligned access preety good (e.g. x86)
value = *((T*)(_buffer + index));
}
else
{
// NOTE: this check and branching does not always payoff
if (ADAPTIVE_ACCESS && is_aligned(_position, sizeof(T)))
{
value = *((T*)(_buffer + index));
}
else
{
if (USE_INLINE_MEMCPY)
{
// NOTE: it turns out that this compiler can optimize this with inline code, e.g. gcc
memcpy(&value, _buffer + index, sizeof(T));
}
else
{
// NOTE: compiler should optimize this and unroll the loop
char* p = _buffer + index;
for (size_t i = 0; i < sizeof(T); i++)
((char*)&value)[i] = p[i];
}
}
}
if (ENDIANESS_SUPPORT && reverse<T>())
{
if(reverse<T>())
value = swap<T>(value);
}
return value;
}
template<typename T>
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)
{
put((const char*)values, 0, count);
return;
}
T* start = (T*)_position;
size_t n = sizeof(T)*count;
// we require aligned arrays...
memcpy(_position, values, n);
_position += n;
//assert(is_aligned(_position, sizeof(T)));
T* start = (T*)_position;
size_t n = sizeof(T)*count; // bytes
assert(n<=getRemaining());
// ... so that we can be fast changing endianess
if (ENDIANESS_SUPPORT && reverse<T>())
{
for (std::size_t i = 0; i < count; i++)
{
*start = swap<T>(*start);
start++;
}
if (reverse<T>()) {
for(std::size_t i=0; i<count; i++)
start[i] = swap<T>(values[i]);
} else {
memcpy(start, values, n);
}
_position += n;
}
template<typename T>
inline void ByteBuffer::getArray(T* values, std::size_t count)
{
// this avoids int8 specialization, compiler will take care if optimization, -O2 or more
if (sizeof(T) == 1)
{
get((char*)values, 0, count);
return;
}
T* start = (T*)values;
size_t n = sizeof(T)*count;
// we require aligned arrays...
memcpy(values, _position, n);
_position += n;
//assert(is_aligned(_position, sizeof(T)));
const T* start = (T*)_position;
size_t n = sizeof(T)*count; // bytes
assert(n<=getRemaining());
// ... so that we can be fast changing endianess
if (ENDIANESS_SUPPORT && reverse<T>())
{
for (std::size_t i = 0; i < count; i++)
{
*start = swap<T>(*start);
start++;
}
if (reverse<T>()) {
for(std::size_t i=0; i<count; i++)
values[i] = swap<T>(start[i]);
} else {
memcpy(values, start, n);
}
_position += n;
}
}
}
}}
#endif /* BYTEBUFFER_H */

View File

328
src/misc/pv/debugPtr.h Normal file
View File

@@ -0,0 +1,328 @@
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/* Author: Michael Davidsaver */
/* wrapper around shared_ptr which tracks backwards references.
* Can help to find ref. leaks, loops, and other exciting bugs.
* See comments in sharedPtr.h
*/
#ifndef DEBUGPTR_H
#define DEBUGPTR_H
#if __cplusplus<201103L
# error c++11 required
#endif
#include <ostream>
#include <memory>
#include <set>
#include <pv/epicsException.h>
#include <shareLib.h>
//! User code should test this macro
//! before calling epics::debug::shared_ptr::show_refs()
#define HAVE_SHOW_REFS
namespace epics {
namespace debug {
struct tracker;
class shared_ptr_base;
class epicsShareClass ptr_base {
friend class shared_ptr_base;
template<typename A>
friend class shared_ptr;
template<typename A>
friend class weak_ptr;
protected:
typedef std::shared_ptr<tracker> track_t;
track_t track;
ptr_base() noexcept : track() {}
ptr_base(const track_t& track) :track(track) {}
ptr_base(const ptr_base&) = delete;
ptr_base(ptr_base&&) = delete;
ptr_base& operator=(const ptr_base&) = delete;
public:
typedef std::set<const shared_ptr_base *> ref_set_t;
void show_refs(std::ostream&, bool self=true, bool weak=false) const;
void spy_refs(ref_set_t&) const;
};
class epicsShareClass weak_ptr_base : public ptr_base {
protected:
weak_ptr_base() {}
weak_ptr_base(const track_t& track) :ptr_base(track) {}
};
class epicsShareClass shared_ptr_base : public ptr_base {
protected:
shared_ptr_base() noexcept
#ifndef EXCEPT_USE_NONE
:m_stack(), m_depth(0)
#endif
{}
shared_ptr_base(const track_t& track) :ptr_base(track)
#ifndef EXCEPT_USE_NONE
,m_stack(), m_depth(0)
#endif
{}
~shared_ptr_base() {track_clear();}
// add ourselves to tracker
void track_new();
// create new tracker if ptr!=nullptr, otherwise clear
void track_new(void* ptr);
// copy tracker and add ourself
void track_assign(const shared_ptr_base& o);
void track_clear();
void swap(shared_ptr_base& o);
void snap_stack();
#ifndef EXCEPT_USE_NONE
void *m_stack[EXCEPT_DEPTH];
int m_depth; // always <= EXCEPT_DEPTH
#endif
public:
void show_stack(std::ostream&) const;
};
template<typename T>
class shared_ptr;
template<typename T>
class weak_ptr;
template<class Base>
class enable_shared_from_this;
template<typename Store, typename Actual>
inline void
do_enable_shared_from_this(const shared_ptr<Store>& dest,
enable_shared_from_this<Actual>* self
);
template<typename T>
inline void
do_enable_shared_from_this(const shared_ptr<T>&, ...) {}
template<typename T>
class shared_ptr : public shared_ptr_base {
typedef ::std::shared_ptr<T> real_type;
real_type real;
template<typename A>
friend class shared_ptr;
template<typename A>
friend class weak_ptr;
// ctor for casts
shared_ptr(const real_type& r, const ptr_base::track_t& t)
:shared_ptr_base(t), real(r)
{track_new();}
public:
typedef typename real_type::element_type element_type;
typedef weak_ptr<T> weak_type;
// new NULL
shared_ptr() noexcept {}
// copy existing same type
shared_ptr(const shared_ptr& o) :shared_ptr_base(o.track), real(o.real) {track_new();}
// copy existing of implicitly castable type
template<typename A>
shared_ptr(const shared_ptr<A>& o) :shared_ptr_base(o.track), real(o.real) {track_new();}
// construct around new pointer
template<typename A, class ... Args>
explicit shared_ptr(A* a, Args ... args) : shared_ptr_base(), real(a, args...) {
track_new(a);
do_enable_shared_from_this(*this, a);
}
// make strong ref from weak
template<typename A>
shared_ptr(const weak_ptr<A>& o) :shared_ptr_base(o.track), real(o.real) {track_new();}
// takeover from unique_ptr
template<typename A>
shared_ptr(std::unique_ptr<A>&& a) : shared_ptr_base(), real(a.release()) {track_new();}
~shared_ptr() {}
shared_ptr& operator=(const shared_ptr& o) {
if(this!=&o) {
real = o.real;
track_assign(o);
}
return *this;
}
template<typename A>
shared_ptr& operator=(const shared_ptr<A>& o) {
if(get()!=o.get()) {
real = o.real;
track_assign(o);
}
return *this;
}
void reset() noexcept { real.reset(); track_clear(); }
template<typename A, class ... Args>
void reset(A* a, Args ... args)
{
real.reset(a, args...);
track_new(a);
do_enable_shared_from_this(*this, a);
}
void swap(shared_ptr &o) noexcept
{
if(this!=&o) {
real.swap(o.real);
shared_ptr_base::swap(o);
}
}
// proxy remaining to underlying shared_ptr
T* get() const noexcept { return real.get(); }
typename std::add_lvalue_reference<T>::type operator*() const noexcept { return *real; }
T* operator->() const noexcept { return real.get(); }
long use_count() const noexcept { return real.use_count(); }
bool unique() const noexcept { return real.unique(); }
explicit operator bool() const noexcept { return bool(real); }
bool operator==(const shared_ptr<T>& o) const { return real==o.real; }
bool operator!=(const shared_ptr<T>& o) const { return real!=o.real; }
bool operator<(const shared_ptr<T>& o) const { return real<o.real; }
template<typename A>
bool owner_before(const shared_ptr<A>& o) { return real.owner_before(o); }
template<typename A>
bool owner_before(const weak_ptr<A>& o) { return real.owner_before(o); }
template<typename TO, typename FROM>
friend
shared_ptr<TO> static_pointer_cast(const shared_ptr<FROM>& src);
template<typename TO, typename FROM>
friend
shared_ptr<TO> const_pointer_cast(const shared_ptr<FROM>& src);
template<typename TO, typename FROM>
friend
shared_ptr<TO> dynamic_pointer_cast(const shared_ptr<FROM>& src);
template<typename Store, typename Actual>
friend void
do_enable_shared_from_this(const shared_ptr<Store>& dest,
enable_shared_from_this<Actual>* self
);
};
template<typename TO, typename FROM>
shared_ptr<TO> static_pointer_cast(const shared_ptr<FROM>& src) {
return shared_ptr<TO>(std::static_pointer_cast<TO>(src.real), src.track);
}
template<typename TO, typename FROM>
shared_ptr<TO> const_pointer_cast(const shared_ptr<FROM>& src) {
return shared_ptr<TO>(std::const_pointer_cast<TO>(src.real), src.track);
}
template<typename TO, typename FROM>
shared_ptr<TO> dynamic_pointer_cast(const shared_ptr<FROM>& src) {
return shared_ptr<TO>(std::dynamic_pointer_cast<TO>(src.real), src.track);
}
template<typename T>
class weak_ptr : public weak_ptr_base {
typedef ::std::weak_ptr<T> real_type;
real_type real;
template<typename A>
friend class shared_ptr;
template<typename A>
friend class weak_ptr;
public:
typedef typename real_type::element_type element_type;
typedef weak_ptr<T> weak_type;
// new NULL
weak_ptr() noexcept {}
// copy existing same type
weak_ptr(const weak_ptr& o) :weak_ptr_base(o.track), real(o.real) {}
// copy existing of similar type
template<typename A>
weak_ptr(const weak_ptr<A>& o) :weak_ptr_base(o.track), real(o.real) {}
// create week ref from strong ref
template<typename A>
weak_ptr(const shared_ptr<A>& o) :weak_ptr_base(o.track), real(o.real) {}
~weak_ptr() {}
weak_ptr& operator=(const weak_ptr& o) {
if(this!=&o) {
real = o.real;
track = o.track;
}
return *this;
}
template<typename A>
weak_ptr& operator=(const shared_ptr<A>& o) {
real = o.real;
track = o.track;
return *this;
}
shared_ptr<T> lock() const noexcept { return shared_ptr<T>(real.lock(), track); }
void reset() noexcept { track.reset(); real.reset(); }
long use_count() const noexcept { return real.use_count(); }
bool unique() const noexcept { return real.unique(); }
};
template<class Base>
class enable_shared_from_this {
mutable weak_ptr<Base> xxInternalSelf;
template<typename Store, typename Actual>
friend
void
do_enable_shared_from_this(const shared_ptr<Store>& dest,
enable_shared_from_this<Actual>* self
);
public:
shared_ptr<Base> shared_from_this() const {
return shared_ptr<Base>(xxInternalSelf);
}
};
template<typename Store, typename Actual>
inline void
do_enable_shared_from_this(const shared_ptr<Store>& dest,
enable_shared_from_this<Actual>* self
)
{
shared_ptr<Actual> actual(dynamic_pointer_cast<Actual>(dest));
if(!actual)
throw std::logic_error("epics::debug::enabled_shared_from_this fails");
self->xxInternalSelf = actual;
}
}} // namespace epics::debug
template<typename T>
inline std::ostream& operator<<(std::ostream& strm, const epics::debug::shared_ptr<T>& ptr)
{
strm<<ptr.get();
return strm;
}
#endif // DEBUGPTR_H

View File

@@ -1,10 +1,9 @@
/**
* 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.
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/*
* epicsException.hpp
* epicsException.h
*
* Created on: Oct 20, 2010
* Author: Matej Sekoranja
@@ -34,19 +33,14 @@
#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)
#if defined(_WIN32) && !defined(NOMINMAX)
#define NOMINMAX
#endif
#include <stdexcept>
#include <string>
#include <cstdio>
#include <stdio.h>
#include <stdlib.h>
#include <shareLib.h>
// Users may redefine this for a large size if desired
@@ -58,7 +52,7 @@
# include <execinfo.h>
# include <cxxabi.h>
# define EXCEPT_USE_BACKTRACE
#elif defined(_WIN32) && !defined(__MINGW__) && !defined(SKIP_DBGHELP)
#elif defined(_WIN32) && !defined(_MINGW) && !defined(SKIP_DBGHELP)
# define _WINSOCKAPI_
# include <windows.h>
# include <dbghelp.h>
@@ -67,6 +61,12 @@
# define EXCEPT_USE_NONE
#endif
#if defined(_WIN32) && !defined(_MINGW)
#pragma warning( push )
#pragma warning(disable: 4275) // non dll-interface class used as base for dll-interface class (std::logic_error)
#pragma warning(disable: 4251) // class std::string needs to have dll-interface to be used by clients
#endif
namespace epics { namespace pvData {
@@ -175,17 +175,17 @@ do { \
#define PRINT_EXCEPTION2(EI, FP) \
do { \
ExceptionMixin *_em_p=dynamic_cast<ExceptionMixin*>(&EI); \
::epics::pvData::ExceptionMixin *_em_p=dynamic_cast< ::epics::pvData::ExceptionMixin*>(&EI); \
if (_em_p) {_em_p->print(FP);} \
}while(0)
#define PRINT_EXCEPTION(EI) PRINT_EXCEPTION2(EI,stderr)
#ifndef __GNUC__
#if !defined(__GNUC__) || __GNUC__ < 4
# define SHOW_EXCEPTION(EI) ::epics::pvData::detail::showException(EI)
#else
# define SHOW_EXCEPTION(EI) \
({ ExceptionMixin *_mx=dynamic_cast<ExceptionMixin*>(&(EI)); \
({ ::epics::pvData::ExceptionMixin *_mx=dynamic_cast< ::epics::pvData::ExceptionMixin*>(&(EI)); \
_mx ? _mx->show() : std::string(); \
})
#endif
@@ -202,20 +202,33 @@ do { \
#define THROW_EXCEPTION2(E,A) do{throw (E)(A);}while(0)
#endif // THROW_EXCEPTION_COMPAT
/**
* @brief Base for pvData exceptions.
*
*/
class epicsShareClass BaseException : public std::logic_error {
public:
/**
* Constructor.
*/
explicit BaseException(const std::string msg) : std::logic_error(msg) {}
/**
* Destructor.
*/
virtual ~BaseException() throw(){};
/**
*
* Reason for excepton.
*/
virtual const char* what() const throw();
private:
mutable std::string base_msg;
};
#ifdef _WIN32
#if defined(_WIN32) && !defined(_MINGW)
#pragma warning( pop )
#endif

68
src/misc/pv/event.h Normal file
View File

@@ -0,0 +1,68 @@
/* event.h */
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author mrk
*/
#ifndef EVENT_H
#define EVENT_H
#include <memory>
#include <vector>
#include <epicsEvent.h>
#include <shareLib.h>
#include <pv/pvType.h>
#include <pv/sharedPtr.h>
namespace epics { namespace pvData {
class Event;
typedef std::tr1::shared_ptr<Event> EventPtr;
/**
* @brief C++ wrapper for epicsEvent from EPICS base.
*
*/
class epicsShareClass Event {
public:
POINTER_DEFINITIONS(Event);
/**
* Constructor
*/
explicit Event(bool = false);
/**
* Destructor.
*/
~Event();
/**
* Signal the event i.e. ensures that the next or current call to wait completes.
*/
void signal();
/**
* wait
* @return (false,true) if (some error, event signaled).
* The next wait or tryWait will clear signal.
*/
bool wait (); /* blocks until full */
/**
* wait for up to timeOut seconds.
* @param timeOut max number of seconds to wait
* @return (false, true) if (timeout or error, event signaled).
*/
bool wait ( double timeOut ); /* false if empty at time out */
/**
* See if a signal has been called.
* @return (false, true) if (timeout or error, event signaled).
*/
bool tryWait (); /* false if empty */
private:
epicsEventId id;
};
}}
#endif /* EVENT_H */

92
src/misc/pv/executor.h Normal file
View File

@@ -0,0 +1,92 @@
/* executor.h */
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author mrk
*/
#ifndef EXECUTOR_H
#define EXECUTOR_H
#include <memory>
#include <compilerDependencies.h>
#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;
class Executor;
typedef std::tr1::shared_ptr<Command> CommandPtr;
typedef std::tr1::shared_ptr<Executor> ExecutorPtr;
/**
* @brief A command to be called by Executor
*
*/
class epicsShareClass EPICS_DEPRECATED Command {
public:
POINTER_DEFINITIONS(Command);
/**
*
* Destructor
*/
virtual ~Command(){}
/**
*
* The command that is executed.
*/
virtual void command() = 0;
private:
CommandPtr next;
friend class Executor;
};
/**
* @brief A class that executes commands.
*
*/
class epicsShareClass EPICS_DEPRECATED Executor : public Runnable{
public:
POINTER_DEFINITIONS(Executor);
/**
* Constructor
*
* @param threadName name for the executor thread.
* @param priority The thread priority.
*/
Executor(std::string const & threadName,ThreadPriority priority);
/**
* Destructor
*/
~Executor();
/**
*
* Request to execute a command.
* @param command A shared pointer to the command instance.
*/
void execute(CommandPtr const &command);
/**
*
* The thread run method.
*/
virtual void run();
private:
CommandPtr head;
CommandPtr tail;
epics::pvData::Mutex mutex;
epics::pvData::Event moreWork;
epics::pvData::Event stopped;
epics::pvData::Thread thread;
};
}}
#endif /* EXECUTOR_H */

View File

@@ -1,8 +1,7 @@
/* localStaticLock.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.
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author mse

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