Compare commits
276 Commits
before_mer
...
6.0.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e0367a2dd7 | ||
|
|
1e0f1119e2 | ||
|
|
6d6314a924 | ||
|
|
e0b881d036 | ||
|
|
d24ff6c3d2 | ||
|
|
ef17aac046 | ||
|
|
83b63a9138 | ||
|
|
0a5ab8625d | ||
|
|
a115c9cd15 | ||
|
|
6ba40803d8 | ||
|
|
8d6094c55a | ||
|
|
d258acfc49 | ||
|
|
d9072402db | ||
|
|
1a706e3842 | ||
|
|
a227897504 | ||
|
|
0833d68e91 | ||
|
|
99bab6796c | ||
|
|
0544187057 | ||
|
|
e12e7b4d76 | ||
|
|
7609ac6f1e | ||
|
|
3c946a91e8 | ||
|
|
2389ebd87e | ||
|
|
90ad497a6f | ||
|
|
1bb0b6fe03 | ||
|
|
c16c1df6fd | ||
|
|
e460641711 | ||
|
|
1e980651a9 | ||
|
|
028076e79c | ||
|
|
e5b6a88551 | ||
|
|
b18b4f236f | ||
|
|
605d4e99b9 | ||
|
|
ad00b6465a | ||
|
|
537ebd05f2 | ||
|
|
2ee8769752 | ||
|
|
8d7f534d54 | ||
|
|
47bb62b051 | ||
|
|
50b8213781 | ||
|
|
fd1fe53b49 | ||
|
|
378def0a58 | ||
|
|
ed5f48b353 | ||
|
|
fa6c2c7683 | ||
|
|
3fadc9b481 | ||
|
|
c3d7fa0d26 | ||
|
|
5c16357fe2 | ||
|
|
ef2e6079ba | ||
|
|
18633288fb | ||
|
|
67daef7bcc | ||
|
|
5eb29dcfc4 | ||
|
|
d2fc922ee7 | ||
|
|
d35010c1cb | ||
|
|
bd4b65225c | ||
|
|
be95a62965 | ||
|
|
4336d524af | ||
|
|
ae7976fc01 | ||
|
|
72f9dc4c7c | ||
|
|
84760648fe | ||
|
|
b0df40d9a6 | ||
|
|
139217914d | ||
|
|
efa5795193 | ||
|
|
4f499aed01 | ||
|
|
a8ba831f5e | ||
|
|
a90405c25a | ||
|
|
4546fda8e9 | ||
|
|
b02f771146 | ||
|
|
dc94b26e50 | ||
|
|
4c32f37ede | ||
|
|
336a8b3bc2 | ||
|
|
faecea39c8 | ||
|
|
d08d5362be | ||
|
|
d4292d81f2 | ||
|
|
62893e33e9 | ||
|
|
5b07ecbd01 | ||
|
|
b5c1b9178d | ||
|
|
65ff7ab1c3 | ||
|
|
35fd991fdc | ||
|
|
57e1acba79 | ||
|
|
620d351946 | ||
|
|
de3c2656ef | ||
|
|
3b2e9b2485 | ||
|
|
75a3005d74 | ||
|
|
448f606054 | ||
|
|
e35c6f29fb | ||
|
|
85a1a48b00 | ||
|
|
45427d3202 | ||
|
|
93c7a05dac | ||
|
|
a34c38c9b9 | ||
|
|
3100b77a1a | ||
|
|
c8429069a3 | ||
|
|
01172217dc | ||
|
|
14b0e409f2 | ||
|
|
2107bae8dd | ||
|
|
433676226c | ||
|
|
f0c88234a0 | ||
|
|
393d711e5f | ||
|
|
cb24bd9c2c | ||
|
|
abc5c5a374 | ||
|
|
54c94f181a | ||
|
|
6641e7f5d1 | ||
|
|
f4a00f2b0f | ||
|
|
05d41f81e4 | ||
|
|
fdc289d888 | ||
|
|
0a2243e033 | ||
|
|
9d877d764f | ||
|
|
f5df29cf34 | ||
|
|
8008823ea5 | ||
|
|
6515de4bc0 | ||
|
|
8c5f535b79 | ||
|
|
3714be4f16 | ||
|
|
f24f565e58 | ||
|
|
036186fc12 | ||
|
|
d3853bd4e9 | ||
|
|
7253bac48a | ||
|
|
973fbeeba5 | ||
|
|
f22cefba97 | ||
|
|
a5abc37b17 | ||
|
|
b95fa7be56 | ||
|
|
f6cf87a52d | ||
|
|
51f36b2281 | ||
|
|
ddebd494c6 | ||
|
|
d0a8d2b1cd | ||
|
|
1731a0daf6 | ||
|
|
3487b3ee9e | ||
|
|
5834efb709 | ||
|
|
52bc6d060d | ||
|
|
35ca5f3aed | ||
|
|
ac2b6ea8db | ||
|
|
9827caa3e3 | ||
|
|
ebe2d6196c | ||
|
|
e4689dd3f8 | ||
|
|
1dba611b8e | ||
|
|
97cbea6f4d | ||
|
|
d9963b0631 | ||
|
|
8418303ce2 | ||
|
|
40952df965 | ||
|
|
4f2c51c480 | ||
|
|
fd31a0d6b0 | ||
|
|
9ad725a272 | ||
|
|
2b6172ba63 | ||
|
|
c521f9299d | ||
|
|
1e646f8df1 | ||
|
|
b5a436c1b7 | ||
|
|
4f25c7a3ea | ||
|
|
eadb8ff65b | ||
|
|
6a80e941a0 | ||
|
|
7fc9b42b3a | ||
|
|
0d857999bf | ||
|
|
8ba71b048e | ||
|
|
e07f6c1703 | ||
|
|
e4f38121d2 | ||
|
|
255ee3f151 | ||
|
|
e72dbaabe1 | ||
|
|
b39662450f | ||
|
|
98da0c0bec | ||
|
|
45dde325fd | ||
|
|
2967a8f798 | ||
|
|
d4bdc73948 | ||
|
|
37c2f6bb17 | ||
|
|
a8e4d749e3 | ||
|
|
3df16ee449 | ||
|
|
332c2f959b | ||
|
|
a1b89c9a3b | ||
|
|
d6921fdac0 | ||
|
|
4cb3c22221 | ||
|
|
cc1536b6e1 | ||
|
|
92a178cbf9 | ||
|
|
fbebce0a49 | ||
|
|
b13bb9819a | ||
|
|
bb505b8ed9 | ||
|
|
cf030bc711 | ||
|
|
6cb95c5cfc | ||
|
|
a277a4fdd5 | ||
|
|
388799d39d | ||
|
|
4acf7edf95 | ||
|
|
e39346d51e | ||
|
|
5ae6de4f1d | ||
|
|
e0f1427af7 | ||
|
|
69297bdb58 | ||
|
|
0fa2f2c2ff | ||
|
|
9efce46fff | ||
|
|
c356ecb402 | ||
|
|
4c6887e7ec | ||
|
|
6d338cab15 | ||
|
|
354fdd412f | ||
|
|
f3f6141e6a | ||
|
|
f2b43b704c | ||
|
|
de1478d7ba | ||
|
|
b9592eeb8c | ||
|
|
6a62f9c082 | ||
|
|
2e4a8b2e23 | ||
|
|
c5112ffa11 | ||
|
|
7b9fda4e81 | ||
|
|
278e531806 | ||
|
|
047de40642 | ||
|
|
4e671a1c21 | ||
|
|
f36c8ce280 | ||
|
|
e77f2c91d7 | ||
|
|
82b0d5ce5f | ||
|
|
6117035863 | ||
|
|
c86e31ad99 | ||
|
|
f506fe1c0e | ||
|
|
554dc06eda | ||
|
|
80e1dfd142 | ||
|
|
6db5cf60dc | ||
|
|
63d181a0ac | ||
|
|
73c4896cce | ||
|
|
5b1b5ab904 | ||
|
|
80a537bc4c | ||
|
|
2a8a1d3736 | ||
|
|
61fbfa0684 | ||
|
|
f06a6bfe7b | ||
|
|
587f81f511 | ||
|
|
435ca63d1b | ||
|
|
64bb660f44 | ||
|
|
8bf24de0b3 | ||
|
|
943ea633a4 | ||
|
|
b1d5f7d7e5 | ||
|
|
188b94ce19 | ||
|
|
515282abfe | ||
|
|
efbdb722e7 | ||
|
|
e980823294 | ||
|
|
3692f4fb3c | ||
|
|
3e645f3c79 | ||
|
|
6127763302 | ||
|
|
19a181b38f | ||
|
|
2818b0384c | ||
|
|
36faf8c2ea | ||
|
|
a208171250 | ||
|
|
b8a2b7cff6 | ||
|
|
2a08cbc1a0 | ||
|
|
62bc6c1fb1 | ||
|
|
1098650421 | ||
|
|
15d85c2f87 | ||
|
|
16fb3f0339 | ||
|
|
37f6dff065 | ||
|
|
baf8832fc9 | ||
|
|
b558e11ede | ||
|
|
103cdabff1 | ||
|
|
57e33c8f7d | ||
|
|
da0f65c2d3 | ||
|
|
6535c075f3 | ||
|
|
f3c0b9544c | ||
|
|
3609fd4745 | ||
|
|
622e140622 | ||
|
|
a4954c3825 | ||
|
|
b6e1b9c203 | ||
|
|
34a35c2658 | ||
|
|
90b7c9a17c | ||
|
|
c72297020b | ||
|
|
f07b601dce | ||
|
|
63c62a2aae | ||
|
|
6888a9d340 | ||
|
|
72bf9f76a3 | ||
|
|
c0c6213c7c | ||
|
|
652ef4bc82 | ||
|
|
c6eed12139 | ||
|
|
1132e25072 | ||
|
|
879e3a2b67 | ||
|
|
6ec207141f | ||
|
|
45c657ce79 | ||
|
|
888dc11c03 | ||
|
|
5e3159f800 | ||
|
|
570ec97eda | ||
|
|
09c75823e6 | ||
|
|
50c8c3b0bd | ||
|
|
3fb44312c7 | ||
|
|
67bdf2ab8b | ||
|
|
a56ed44e74 | ||
|
|
3c912c3812 | ||
|
|
0ceb87eee1 | ||
|
|
6510c10884 | ||
|
|
20345ab0dd | ||
|
|
d5dfb3de0c | ||
|
|
c2f22a4ad8 | ||
|
|
cb15a8676b | ||
|
|
34f2d7bc9a | ||
|
|
fb7f1b622b |
15
.gitignore
vendored
Normal file
15
.gitignore
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
bin/
|
||||
lib/
|
||||
doc/
|
||||
include/
|
||||
db/
|
||||
dbd/
|
||||
documentation/html
|
||||
documentation/*.tag
|
||||
envPaths
|
||||
configure/*.local
|
||||
configure/RELEASE.*
|
||||
configure/CONFIG_SITE.*
|
||||
!configure/ExampleRELEASE.local
|
||||
**/O.*
|
||||
QtC-*
|
||||
8
.hgflow
8
.hgflow
@@ -1,8 +0,0 @@
|
||||
[branchname]
|
||||
master = master
|
||||
develop = default
|
||||
feature = feature/
|
||||
release = release/
|
||||
hotfix = hotfix/
|
||||
support = support/
|
||||
|
||||
11
.hgignore
11
.hgignore
@@ -1,11 +0,0 @@
|
||||
^QtC-
|
||||
^bin/
|
||||
^lib/
|
||||
^doc/
|
||||
^include/
|
||||
^db/
|
||||
^dbd/
|
||||
^documentation/html
|
||||
envPaths
|
||||
configure/.*\.local
|
||||
/O\..*
|
||||
11
.hgtags
11
.hgtags
@@ -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
|
||||
12
COPYRIGHT
12
COPYRIGHT
@@ -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
|
||||
*************************************************** */
|
||||
77
LICENSE
77
LICENSE
@@ -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.
|
||||
________________________________________________________________________
|
||||
|
||||
82
README.html
82
README.html
@@ -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 &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
57
README.md
Normal 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).
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -21,5 +21,5 @@
|
||||
# PVCOMMON = /home/install/epicsV4/pvCommonCPP
|
||||
# EPICS_BASE = /home/install/epics/base
|
||||
|
||||
-include $(TOP)/configure/RELEASE.local
|
||||
-include $(TOP)/../RELEASE.local
|
||||
-include $(TOP)/configure/RELEASE.local
|
||||
|
||||
@@ -580,7 +580,7 @@ WARN_LOGFILE =
|
||||
# directories like "/usr/src/myproject". Separate the files or directories
|
||||
# with spaces.
|
||||
|
||||
INPUT = ../pvDataApp
|
||||
INPUT = ../include/pv
|
||||
|
||||
# This tag can be used to specify the character encoding of the source files
|
||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
|
||||
|
||||
345
documentation/RELEASE_NOTES.html
Normal file
345
documentation/RELEASE_NOTES.html
Normal file
@@ -0,0 +1,345 @@
|
||||
<?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;" />
|
||||
<meta name="keywords" content="EPICS, EPICSv4" />
|
||||
<title>EPICS V4 pvData C++ Release Notes</title>
|
||||
<link rel="stylesheet" type="text/css" href="../../base.css" />
|
||||
<link rel="stylesheet" type="text/css" href="../../epicsv4.css" />
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<h1>Release 6.0.1</h1>
|
||||
|
||||
<p>The changes since release 6.0.0 are:</p>
|
||||
|
||||
<ul>
|
||||
<li>Fix "Problem building pvDataCPP for win32-x86-mingw" (issue #42)</li>
|
||||
<li>In src/misc/bitSet.cpp #include <algorithm> required for MSVS 2015</li>
|
||||
<li>In testApp/misc/testTypeCast.cpp print (u)int8 values as integers</li>
|
||||
<li>Minor documentation updates</li>
|
||||
</ul>
|
||||
|
||||
<h1>Release 6.0.0</h1>
|
||||
|
||||
<p>The main changes since release 5.0.4 are:</p>
|
||||
|
||||
<ul>
|
||||
<li>Linux shared library version added</li>
|
||||
<li>Headers have been moved into pv directories</li>
|
||||
<li>Bitset functions declared const where possible</li>
|
||||
<li>Bitset::swap added</li>
|
||||
<li>Requester::message has default implementation</li>
|
||||
<li>Serialization/deserialization helpers added</li>
|
||||
<li>Non-template getSubField char* overload added</li>
|
||||
<li>MonitorPlugin deprecated</li>
|
||||
<li>Field name validation performed</li>
|
||||
<li>Now builds for Cygwin and MinGW targets</li>
|
||||
<li>Fix for debug build issue.</li>
|
||||
<li>New license file replaces LICENSE and COPYRIGHT</li>
|
||||
</ul>
|
||||
|
||||
<h2>Shared library version added</h2>
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<h2>Headers have been moved into pv directories</h2>
|
||||
|
||||
<p>E.g. src/property/alarm.h -> src/property/pv/alarm.h</p>
|
||||
|
||||
<p>This facilitates using some IDEs such as Qt Creator.</p>
|
||||
|
||||
<h2>Requester::message has default implementation</h2>
|
||||
|
||||
<p>Requester::message is no longer pure virtual. Default implementation sends
|
||||
string to std::cerr.</p>
|
||||
|
||||
<h2>Serialization/deserialization helpers added</h2>
|
||||
|
||||
<p>A helper function, serializeToVector, has been added which serializes a
|
||||
Serializable object into a standard vector of UInt8s.</p>
|
||||
|
||||
<p>Similarly a function deserializeFromVector deserializes a standard vector into
|
||||
a Deserializable object.</p>
|
||||
|
||||
<p>A function deserializeFromBuffer deserializes a ByteBuffer into a
|
||||
Deserializable object.</p>
|
||||
|
||||
<h2>Field name validation performed</h2>
|
||||
|
||||
<p>On creating a Structure or Union the field names are now validated.</p>
|
||||
|
||||
<p>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<em>][A-Za-z0-9</em>]*.</p>
|
||||
|
||||
<h2>Now builds for Cygwin and MinGW targets</h2>
|
||||
|
||||
<p>Includes cross-compiling MinGW on Linux.</p>
|
||||
|
||||
<h1>Release 5.0.4</h1>
|
||||
|
||||
<p>The changes since release 5.0.3 are:</p>
|
||||
|
||||
<ul>
|
||||
<li>Fixed bitset serialization (issue #24)</li>
|
||||
<li>Fixed truncation in BitSet::or_and (issue #27)</li>
|
||||
</ul>
|
||||
|
||||
<h2>Fixed bitset serialization (issue #24)</h2>
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<p>Fix exposed issue in deserialization on 32-bit platforms which
|
||||
has also been corrected. </p>
|
||||
|
||||
<h2>Fixed truncation in BitSet::or_and (issue #27)</h2>
|
||||
|
||||
<p>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).</p>
|
||||
|
||||
<p>Previously min(n1,n2) words were used and the result would be truncated in
|
||||
some instances. This has been fixed.</p>
|
||||
|
||||
<h1>Release 5.0.3</h1>
|
||||
|
||||
<p>The only change since release 5.0.2 is:</p>
|
||||
|
||||
<h2>Fixed buffer overflow in PVUnion::serialize() (issue #20)</h2>
|
||||
|
||||
<p>A PVUnion whose stored value was null was serialized without checking
|
||||
whether the buffer had sufficient capacity. This has been fixed by calling
|
||||
ensureBuffer().</p>
|
||||
|
||||
<h1>Release 5.0.2</h1>
|
||||
|
||||
<p>The main changes since release 4.0.3 are:</p>
|
||||
|
||||
<ul>
|
||||
<li>Deprecated getXXXField() methods have been removed from PVStructure</li>
|
||||
<li>Convert copy methods and equals operators (re)moved</li>
|
||||
<li>Convert::copyUnion now always copies between subfields.</li>
|
||||
<li>New method getSubFieldT, like getSubField except it throws an exception</li>
|
||||
<li>findSubField method removed from PVStructure</li>
|
||||
<li>New stream operators for Field and PVField are provided</li>
|
||||
<li>New template versions of Structure::getField</li>
|
||||
<li>Fixes for static initialisation order issues</li>
|
||||
<li>CreateRequest prevents a possible SEGFAULT</li>
|
||||
</ul>
|
||||
|
||||
<h2>Deprecated getXXXField methods have been removed from PVStructure</h2>
|
||||
|
||||
<p>The following methods have been removed from PVStructure</p>
|
||||
|
||||
<ul>
|
||||
<li>getBooleanField</li>
|
||||
<li>getByteField, getShortField, getIntField, getLongField</li>
|
||||
<li>getUByteField, getUShortField, getUIntField, getULongField</li>
|
||||
<li>getStringField</li>
|
||||
<li>getStructureField, getUnionField</li>
|
||||
<li>getScalarArrayField, getStructureArrayField, getUnionArrayField</li>
|
||||
</ul>
|
||||
|
||||
<p>Use template getSubField instead, e.g. use</p>
|
||||
|
||||
<pre><code>getSubField< PVInt >(fieldName)
|
||||
</code></pre>
|
||||
|
||||
<p>in place of</p>
|
||||
|
||||
<pre><code>getIntField(fieldName)
|
||||
</code></pre>
|
||||
|
||||
<h2>Convert copy methods and equals operators</h2>
|
||||
|
||||
<p>Convert copy methods where moved and replaced with methods
|
||||
on PVField classes, i.e.</p>
|
||||
|
||||
<pre><code>PVField::copy(const PVField& from)
|
||||
</code></pre>
|
||||
|
||||
<p>Methods</p>
|
||||
|
||||
<pre><code>PVField::copyUnchecked(const PVField& from)
|
||||
</code></pre>
|
||||
|
||||
<p>were added to allow unchecked copies, to gain performance
|
||||
where checked are not needed (anymore).</p>
|
||||
|
||||
<p>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</p>
|
||||
|
||||
<h2>Convert::copyUnion</h2>
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<h2>New method getSubFieldT, like getSubField except it throws an exception</h2>
|
||||
|
||||
<p>PVStructure has a new template member</p>
|
||||
|
||||
<pre><code>getSubFieldT(std::string const &fieldName)
|
||||
</code></pre>
|
||||
|
||||
<p>that is like <b>getSubField</b> except that it throws a runtime_error
|
||||
instead of returning null.</p>
|
||||
|
||||
<h2>findSubField method removed from PVStructure</h2>
|
||||
|
||||
<p>This was mainly used in the implementation of getSubField. With a change to
|
||||
the latter, findSubField was removed.</p>
|
||||
|
||||
<h2>New stream operators</h2>
|
||||
|
||||
<p>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:</p>
|
||||
|
||||
<pre><code> void print(StructureConstPtr struc, PVStructurePtr pv)
|
||||
{
|
||||
if(struc) {
|
||||
cout << *struc << endl;
|
||||
} else {
|
||||
cout << "nullptr\n"
|
||||
}
|
||||
if(pv) {
|
||||
cout << *.struc << endl;
|
||||
} else {
|
||||
cout << "nullptr\n"
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
|
||||
<p>Now it can be done as follows:</p>
|
||||
|
||||
<pre><code> void print(StructureConstPtr struc, PVStructurePtr pv)
|
||||
{
|
||||
cout << struc << endl;
|
||||
cout << pv << endl;
|
||||
}
|
||||
</code></pre>
|
||||
|
||||
<h2>New template version of Structure::getField</h2>
|
||||
|
||||
<p>A new template getField method has been added to Structure</p>
|
||||
|
||||
<p>template<typename FT->
|
||||
std::tr1::shared_ptr< const FT-> getField(std::string const &fieldName) const </p>
|
||||
|
||||
<p>Can be used, for example, as follows:</p>
|
||||
|
||||
<pre><code>StructurePtr tsStruc = struc->getField<Structure>("timeStamp");
|
||||
</code></pre>
|
||||
|
||||
<h2>Fixes for static initialisation order issues</h2>
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<h2>CreateRequest change</h2>
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<h1>Release 4.0.3</h1>
|
||||
|
||||
<p>The main changes since release 3.0.2 are:</p>
|
||||
|
||||
<ul>
|
||||
<li>array semantics now enforce Copy On Write.</li>
|
||||
<li>String no longer defined.</li>
|
||||
<li>timeStamp and valueAlarm name changes</li>
|
||||
<li>toString replaced by stream I/O </li>
|
||||
<li>union is new type.</li>
|
||||
<li>copy is new.</li>
|
||||
<li>monitorPlugin is new.</li>
|
||||
</ul>
|
||||
|
||||
<h2>New Semantics for Arrays</h2>
|
||||
|
||||
<p>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<em>vector facility.
|
||||
This allows multiple instances of array data to use the shared raw data.
|
||||
COW is implemented via shared</em>vectors of const data, i. e. data that can not be modified.</p>
|
||||
|
||||
<h2>String no longer defined</h2>
|
||||
|
||||
<p>This is replaced by std::string.</p>
|
||||
|
||||
<h2>timeStamp and valueAlarm name changes</h2>
|
||||
|
||||
<p>In timeStamp nanoSeconds is changed to nanoseconds.</p>
|
||||
|
||||
<p>In valueAlarm hysteresis is changed to hysteresis</p>
|
||||
|
||||
<h2>toString replaced by stream I/O</h2>
|
||||
|
||||
<p>pvData.h and pvIntrospect no longer defines toString
|
||||
Instead they have stream support.
|
||||
pvIntrospect uses method dump and pvData uses dumpValue.
|
||||
For example:</p>
|
||||
|
||||
<pre><code> PVDoublePtr pvValue;
|
||||
String buffer;
|
||||
pvValue->toString(&buffer);
|
||||
cout << buffer << endl;
|
||||
buffer.clear();
|
||||
pvValue->getField()->toString(&buffer);
|
||||
cout << buffer << evdl;
|
||||
</code></pre>
|
||||
|
||||
<p>is replaced by</p>
|
||||
|
||||
<pre><code> PVDoublePtr pvValue;
|
||||
cout << *pvValue << endl
|
||||
cout << *pvValue->getField() << endl;
|
||||
</code></pre>
|
||||
|
||||
<h2>union is a new basic type.</h2>
|
||||
|
||||
<p>There are two new basic types: union_t and unionArray.</p>
|
||||
|
||||
<p>A union is like a structure that has a single subfield.
|
||||
There are two flavors:</p>
|
||||
|
||||
<ul>
|
||||
<li><b>variant union</b> The field can have any type.</li>
|
||||
<li><b>union</b> The field can any of specified set of types.</li>
|
||||
</ul>
|
||||
|
||||
<p>The field type can be dynamically changed.</p>
|
||||
|
||||
<h2>copy </h2>
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<h2>monitorPlugin</h2>
|
||||
|
||||
<p>This is for is for use by code that implements pvAccess monitors.
|
||||
This is prototype and is subject to debate.</p>
|
||||
|
||||
<h1>Release 3.0.2</h1>
|
||||
|
||||
<p>This was the starting point for RELEASE_NOTES</p>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
350
documentation/RELEASE_NOTES.md
Normal file
350
documentation/RELEASE_NOTES.md
Normal file
@@ -0,0 +1,350 @@
|
||||
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
|
||||
=============
|
||||
|
||||
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
|
||||
=============
|
||||
|
||||
The main changes since release 4.0.3 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 <b>getSubField</b> 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:
|
||||
|
||||
* <b>variant union</b> The field can have any type.
|
||||
* <b>union</b> The field can any of specified set of types.
|
||||
|
||||
The field type can be dynamically changed.
|
||||
|
||||
copy
|
||||
----
|
||||
|
||||
This consists of createRequest and pvCopy.
|
||||
createRequest was moved from pvAccess to here.
|
||||
pvCopy is moved from pvDatabaseCPP and now depends
|
||||
only on pvData, i.e. it no longer has any knowledge of PVRecord.
|
||||
|
||||
monitorPlugin
|
||||
-------------
|
||||
|
||||
This is for is for use by code that implements pvAccess monitors.
|
||||
This is prototype and is subject to debate.
|
||||
|
||||
Release 3.0.2
|
||||
==========
|
||||
This was the starting point for RELEASE_NOTES
|
||||
20
documentation/TODO.md
Normal file
20
documentation/TODO.md
Normal file
@@ -0,0 +1,20 @@
|
||||
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.
|
||||
|
||||
monitorPlugin
|
||||
-------------
|
||||
|
||||
A debate is on-going about what semantics should be.
|
||||
|
||||
679
documentation/copyandmonitor.html
Normal file
679
documentation/copyandmonitor.html
Normal file
@@ -0,0 +1,679 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
|
||||
<title>EPICS pvDataCPP: copy and monitor</title>
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="http://epics-pvdata.sourceforge.net/base.css" />
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="http://epics-pvdata.sourceforge.net/epicsv4.css" />
|
||||
<style type="text/css">
|
||||
/*<![CDATA[*/
|
||||
.about { margin-left: 3em; margin-right: 3em; font-size: .83em}
|
||||
table { margin-left: auto; margin-right: auto }
|
||||
.diagram { text-align: center; margin: 2.5em 0 }
|
||||
span.opt { color: grey }
|
||||
span.nterm { font-style:italic }
|
||||
span.term { font-family:courier }
|
||||
span.user { font-family:courier }
|
||||
span.user:before { content:"<" }
|
||||
span.user:after { content:">" }
|
||||
.nonnorm { font-style:italic }
|
||||
p.ed { color: #AA0000 }
|
||||
span.ed { color: #AA0000 }
|
||||
p.ed.priv { display: inline; }
|
||||
span.ed.priv { display: inline; }
|
||||
/*]]>*/</style>
|
||||
<!-- Script that generates the Table of Contents -->
|
||||
<script type="text/javascript"
|
||||
src="http://epics-pvdata.sourceforge.net/script/tocgen.js">
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
<div id="toc">
|
||||
<h2 class="nocount" style="page-break-before: always">Table of Contents</h2>
|
||||
</div>
|
||||
<div id="contents" class="contents">
|
||||
|
||||
<h2>support for copy and monitor</h2>
|
||||
<p><b>copy</b> and <b>monitor</b> are not used in this project.
|
||||
They are intended for use by pvAccess and by pvAccess servers.
|
||||
They are provided with this project because the code depends only on
|
||||
pvData itself.
|
||||
</p>
|
||||
<p>This document describes C++ specific code.
|
||||
<a href="http://epics-pvdata.sourceforge.net/informative/pvRequest.html">
|
||||
pvRequest.html</a>
|
||||
provides a language independent overview of <b>copy</b> and <b>monitor</b>.
|
||||
</p>
|
||||
<p>
|
||||
<b>NOTE:pvRequest.html</b> must be updated since it is based on an earlier version of pvCopy that
|
||||
had knowledge of PVRecord. The C++ version was implemented in pvDatabaseCPP
|
||||
and the Java version on pvIOCJava.
|
||||
At present only the C++ version of the new API for pvCopy is implemented.
|
||||
</p>
|
||||
<p>Copy provides:
|
||||
<dl>
|
||||
<dt>createRequest</dt>
|
||||
<dd>
|
||||
The Channel create methods in pvAccess all have an argument
|
||||
<b>PVStructure pvRequest</b>.<br />
|
||||
Given an ascii string createRequest creates a PVStructure that provides
|
||||
a pvData representation of the information from the ascii string.
|
||||
It is this structure that can be passed to the channel create methods.<br />
|
||||
The information in a pvRequest selects an arbitrary subset of the
|
||||
fields in a top level structure that resides in the server.
|
||||
In addition options can be specified. Both global and field specific
|
||||
options can be specified.
|
||||
</dd>
|
||||
<dt>pvCopy</dt>
|
||||
<dd>This is a facility used by channel providers.
|
||||
It provides client specific code that manages a copy of an arbitrary
|
||||
subset of the fields in a top level structure that resides in the
|
||||
provider. It also allows provider access to options specified
|
||||
by the client.
|
||||
</dd>
|
||||
</dl>
|
||||
Monitor provides:
|
||||
<dl>
|
||||
<dt>monitor</dt>
|
||||
<dd>This is support code for channel providers that implement channel
|
||||
monitor. It, together with the queue facility, provides support for
|
||||
monitor queues.
|
||||
</dd>
|
||||
<dt>monitorPlugin</dt>
|
||||
<dd>This is support for implementing monitor plugins.
|
||||
A monitor plugin can be developed that has no knowledge
|
||||
of pvAccess but only pvData.
|
||||
</dd>
|
||||
</dl>
|
||||
</p>
|
||||
|
||||
<h2>support for copy</h2>
|
||||
<p><b>copy</b> provides the ability to create a structure that has
|
||||
a copy of an arbitrary subset of the fields in an existing top level
|
||||
structure. In addition it allows global options and field specific options.
|
||||
It has two main components: <b>createRequest</b> and <b>pvCopy</b>.
|
||||
Given a string createRequest creates a pvRequest, which is a PVStructure
|
||||
that has the format expected by <b>pvCopy</b>.
|
||||
</p>
|
||||
|
||||
<h3>createRequest</h3>
|
||||
<p>This is mainly used by pvAccess clients. Given a request string it creates
|
||||
a pvRequest structure that can be passed to the pvAccess create methods.
|
||||
In turn pvAccess passes the pvRequest to a local channel provider which
|
||||
then passes it to pvCopy.
|
||||
</p>
|
||||
<p>The definition of the public members is:</p>
|
||||
<pre>
|
||||
class CreateRequest {
|
||||
...
|
||||
static CreateRequestPtr create();
|
||||
virtual PVStructurePtr createRequest(std::string const &request);
|
||||
std::string getMessage();
|
||||
};
|
||||
</pre>
|
||||
<p>An example of how it is used is:</p>
|
||||
<pre>
|
||||
CreateRequestPtr createRequest = CreateRequest::create();
|
||||
PVStructurePtr pvRequest = createRequest->createRequest(request);
|
||||
if(pvRequest==NULL) {
|
||||
std::string error = createRequest->getMessage();
|
||||
// take some action
|
||||
} else {
|
||||
//success do something
|
||||
}
|
||||
</pre>
|
||||
<h3>pvCopy</h3>
|
||||
<p>The definition of the public members is:</p>
|
||||
<pre>
|
||||
class epicsShareClass PVCopyTraverseMasterCallback
|
||||
{
|
||||
...
|
||||
virtual void nextMasterPVField(PVFieldPtr const &pvField);
|
||||
};
|
||||
|
||||
class class epicsShareClass PVCopy
|
||||
{
|
||||
...
|
||||
static PVCopyPtr create(
|
||||
PVStructurePtr const &pvMaster,
|
||||
PVStructurePtr const &pvRequest,
|
||||
std::string const & structureName);
|
||||
PVStructurePtr getPVMaster();
|
||||
void traverseMaster(PVCopyTraverseMasterCallbackPtr const & callback);
|
||||
StructureConstPtr getStructure();
|
||||
PVStructurePtr createPVStructure();
|
||||
size_t getCopyOffset(PVFieldPtr const &masterPVField);
|
||||
size_t getCopyOffset(
|
||||
PVStructurePtr const &masterPVStructure,
|
||||
PVFieldPtr const &masterPVField);
|
||||
PVFieldPtr getMasterPVField(std::size_t structureOffset);
|
||||
void initCopy(
|
||||
PVStructurePtr const &copyPVStructure,
|
||||
BitSetPtr const &bitSet);
|
||||
void updateCopySetBitSet(
|
||||
PVStructurePtr const &copyPVStructure,
|
||||
BitSetPtr const &bitSet);
|
||||
void updateCopyFromBitSet(
|
||||
PVStructurePtr const &copyPVStructure,
|
||||
BitSetPtr const &bitSet);
|
||||
void updateMaster(
|
||||
PVStructurePtr const &copyPVStructure,
|
||||
BitSetPtr const &bitSet);
|
||||
PVStructurePtr getOptions(std::size_t fieldOffset);
|
||||
...
|
||||
};
|
||||
</pre>
|
||||
where
|
||||
<dl>
|
||||
<dt>PVCopyTraverseMasterCallback::nextMasterPVField</dt>
|
||||
<dd>
|
||||
<b>PVCopyTraverseMasterCallback</b> is a callback which must
|
||||
be implemented by the code that uses pvCopy, normally
|
||||
the channel provider. It has the single method <b>nextMasterPVField</b>
|
||||
<br />
|
||||
<b>nextMasterPVField</b> is called for each field in the master
|
||||
as a result of a call to <b>traverseMaster</b>.
|
||||
</dd>
|
||||
<dt>create</dt>
|
||||
<dd>
|
||||
This is the method for creating a PVCopy instance.<br/>
|
||||
<dl>
|
||||
<dt>pvMaster</dt>
|
||||
<dd>the top level structure managed by the server.</dd>
|
||||
<dt>pvRequest</dt>
|
||||
<dd>selects the set of subfields desired
|
||||
and options for each field.</dd>
|
||||
<dt>structureName</dt>
|
||||
<dd>the name for the top level of any PVStructure created.
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>getPVMaster</dt>
|
||||
<dd>
|
||||
Gets the top level structure from pvMaster.
|
||||
</dd>
|
||||
<dt>traverseMaster</dt>
|
||||
<dd>
|
||||
Traverse all fields of the top level structure of pvMaster.
|
||||
For each field the callback is called.
|
||||
</dd>
|
||||
<dt>getStructure</dt>
|
||||
<dd>
|
||||
Get the introspection interface for a PVStructure for e copy.
|
||||
</dd>
|
||||
<dt>createPVStructure</dt>
|
||||
<dd>Create a copy instance.
|
||||
Monitors keep a queue of monitor elements.
|
||||
Since each element needs a PVStructure, multiple top level structures
|
||||
will be created.
|
||||
</dd>
|
||||
<dt>getCopyOffset</dt>
|
||||
<dd>Given a field in pvMaster.
|
||||
return the offset in copy for the same field.
|
||||
A value of std::string::npos means that the copy does not have this field.
|
||||
Two overloaded methods are provided. The first is called if
|
||||
the field of master is not a structure. The second is for
|
||||
subfields of a structure.
|
||||
</dd>
|
||||
<dt>getMasterPVField</dt>
|
||||
<dd>
|
||||
Given a offset in the copy get the corresponding field in pvMaster.
|
||||
</dd>
|
||||
<dt>initCopy</dt>
|
||||
<dd>
|
||||
Initialize the fields in copyPVStructure
|
||||
by giving each field the value from the corresponding field in pvMaster.
|
||||
bitSet will be set to show that all fields are changed.
|
||||
This means that bit set will have the value <b>{0}</b>.
|
||||
</dd>
|
||||
<dt>updateCopySetBitSet</dt>
|
||||
<dd>
|
||||
Set all fields in copyPVStructure to the value of the corresponding field
|
||||
in pvMaster. Each field that is changed has it's corresponding
|
||||
bit set in bitSet.
|
||||
</dd>
|
||||
<dt>updateCopyFromBitSet</dt>
|
||||
<dd>
|
||||
For each set bit in bitSet set the field in copyPVStructure to the value
|
||||
of the corresponding field in pvMaster.
|
||||
</dd>
|
||||
<dt>updateMaster</dt>
|
||||
<dd>
|
||||
For each set bit in bitSet set the field in pvMaster to the value
|
||||
of the corresponding field in copyPVStructure.
|
||||
|
||||
</dd>
|
||||
<dt>getOptions</dt>
|
||||
<dd>
|
||||
Get the options for the field at the specified offset.
|
||||
A NULL is returned if no options were specified for the field.
|
||||
If options were specified,PVStructurePtr is
|
||||
a structure with a set of PVString subfields that specify name,value
|
||||
pairs. name is the subField name and value is the subField value.
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
<h2>support for monitor</h2>
|
||||
<p>This consists of two components:
|
||||
<dl>
|
||||
<dt>monitor</dt>
|
||||
<dd>Used by code that implements pvAccess monitors.</dd>
|
||||
<dt>monitorPlugin</dt>
|
||||
<dd>Code that provides special semantics for monitors.</dd>
|
||||
</dl>
|
||||
</p>
|
||||
<h3>monitor</h3>
|
||||
<pre>
|
||||
class MonitorElement {
|
||||
MonitorElement(PVStructurePtr const & pvStructurePtr);
|
||||
PVStructurePtr pvStructurePtr;
|
||||
BitSetPtr changedBitSet;
|
||||
BitSetPtr overrunBitSet;
|
||||
};
|
||||
|
||||
class Monitor {
|
||||
virtual Status start() = 0;
|
||||
virtual Status stop() = 0;
|
||||
virtual MonitorElementPtr poll() = 0;
|
||||
virtual void release(MonitorElementPtr const & monitorElement) = 0;
|
||||
};
|
||||
|
||||
class MonitorRequester : public virtual Requester {
|
||||
virtual void monitorConnect(Status const & status,
|
||||
MonitorPtr const & monitor, StructureConstPtr const & structure) = 0;
|
||||
virtual void monitorEvent(MonitorPtr const & monitor) = 0;
|
||||
virtual void unlisten(MonitorPtr const & monitor) = 0;
|
||||
};
|
||||
</pre>
|
||||
<h4>monitorElement</h4>
|
||||
<p><b>MonitorElement</b> holds the data for one element of a monitor queue.
|
||||
It has the fields:
|
||||
<dl>
|
||||
<dt>pvStructurePtr</dt>
|
||||
<dd>A top level structure with data values at the time the monitors occurs.</dd>
|
||||
<dt>changedBitSet</dt>
|
||||
<dd>Shows which fields have changed since the previous monitor.</dd>
|
||||
<dt>overrunBitSet</dt>
|
||||
<dd>Shows which fields have changed more han once since the previous monitor.</dd>
|
||||
</dl>
|
||||
</p>
|
||||
<h4>monitorElement queue</h4>
|
||||
<p>
|
||||
A queue of monitor elements must be implemented by any channel provider that implements
|
||||
<b>Channel::createMonitor</b>.
|
||||
For an example implementation look at pvDatabaseCPP.
|
||||
It has the following:
|
||||
<pre>
|
||||
typedef Queue<MonitorElement> MonitorElementQueue;
|
||||
typedef std::tr1::shared_ptr<MonitorElementQueue> MonitorElementQueuePtr;
|
||||
|
||||
class MultipleElementQueue :
|
||||
public ElementQueue
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(MultipleElementQueue);
|
||||
virtual ~MultipleElementQueue(){}
|
||||
MultipleElementQueue(
|
||||
MonitorLocalPtr const &monitorLocal,
|
||||
MonitorElementQueuePtr const &queue,
|
||||
size_t nfields);
|
||||
virtual void destroy(){}
|
||||
virtual Status start();
|
||||
virtual Status stop();
|
||||
virtual bool dataChanged();
|
||||
virtual MonitorElementPtr poll();
|
||||
virtual void release(MonitorElementPtr const &monitorElement);
|
||||
...
|
||||
};
|
||||
</pre>
|
||||
<h4>Monitor</h4>
|
||||
<p><b>Monitor</b> must be implemented by any channel provider that implements
|
||||
<b>Channel::createMonitor</b>.
|
||||
Remote PVAccess also implements Monitor on the client side.
|
||||
Note that each client has it's own queue that is not shared with other client.
|
||||
</p>
|
||||
<p>Monitor has the following methods:</p>
|
||||
<dl>
|
||||
<dt>start</dt>
|
||||
<dd>
|
||||
Start monitoring.
|
||||
This will result in a an initial monitor that has the current value
|
||||
of all fields.
|
||||
</dd>
|
||||
<dt>stop</dt>
|
||||
<dd>
|
||||
Stop monitoring.
|
||||
</dd>
|
||||
<dt>poll</dt>
|
||||
<dd>
|
||||
Called to get a monitor element.
|
||||
If no new elements are available then a null pointer is returned.
|
||||
</dd>
|
||||
<dt>release</dt>
|
||||
<dd>
|
||||
Release the monitor element.
|
||||
The caller owns the monitor element between the calls to poll and release.
|
||||
</dd>
|
||||
<dl>
|
||||
</dl>
|
||||
<h4>MonitorRequester</h4>
|
||||
<p>This must be implemented by a pvAccess client.
|
||||
It has the methods:</p>
|
||||
<dl>
|
||||
<dt>monitorConnect</dt>
|
||||
<dd>
|
||||
A monitor has either connected of disconnected.
|
||||
</dd>
|
||||
<dt>monitorEvent</dt>
|
||||
<dd>
|
||||
A new monitor element is available.
|
||||
</dd>
|
||||
<dt>unlisten</dt>
|
||||
<dd>
|
||||
The channel is going away. The client cam no longer access the monitor.
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<h3>monitorPlugin</h3>
|
||||
<pre>
|
||||
class MonitorPlugin
|
||||
{
|
||||
virtual std::string const & getName() = 0;
|
||||
virtual bool causeMonitor(
|
||||
PVFieldPtr const &pvField,
|
||||
PVStructurePtr const &pvTop,
|
||||
MonitorElementPtr const &monitorElement) = 0;
|
||||
virtual void monitorDone(
|
||||
MonitorElementPtr const &monitorElement);
|
||||
virtual void startMonitoring();
|
||||
virtual void stopMonitoring();
|
||||
virtual void beginGroupPut();
|
||||
virtual void endGroupPut();
|
||||
};
|
||||
|
||||
class MonitorPluginCreator
|
||||
{
|
||||
virtual MonitorPluginPtr create(
|
||||
FieldConstPtr const &field,
|
||||
StructureConstPtr const &top,
|
||||
PVStructurePtr const &pvFieldOptions) = 0;
|
||||
virtual std::string const & getName() = 0;
|
||||
}
|
||||
|
||||
class MonitorPluginManager
|
||||
{
|
||||
static MonitorPluginManagerPtr get();
|
||||
bool addPlugin(
|
||||
std::string const &pluginName,
|
||||
MonitorPluginCreatorPtr const &creator);
|
||||
MonitorPluginCreatorPtr findPlugin(std::string const &pluginName);
|
||||
void showNames();
|
||||
};
|
||||
|
||||
</pre>
|
||||
<h4>MonitorPlugin</h4>
|
||||
<p><b>MonitorPlugin</b> must be implemented by the plugin implementation.
|
||||
It has methods:</p>
|
||||
<dl>
|
||||
<dt>getName</dt>
|
||||
<dd>Get the name of the plugin.</dd>
|
||||
<dt>causeMonitor</dt>
|
||||
<dd>
|
||||
Should the value of pvField cause a monitor to be raised.
|
||||
pvField and pvTop are fields in the top level structure
|
||||
being monitored. monitorElement has the top level structure
|
||||
for the copy</b>.
|
||||
The implementation should <b>not</b> modify the fields in the structure
|
||||
being monitored.
|
||||
Called with pvTop locked.
|
||||
</dd>
|
||||
<dt>monitorDone</dt>
|
||||
<dd>
|
||||
Called just before monitorElement will be given to client.
|
||||
The plugin can change the data values and bitSets in monitorElement.
|
||||
Called with pvTop unlocked.
|
||||
</dd>
|
||||
<dt>startMonitoring</dt>
|
||||
<dd>
|
||||
Monitoring is starting.
|
||||
</dd>
|
||||
<dt>stopMonitoring</dt>
|
||||
<dd>
|
||||
Monitoring is being stopped.
|
||||
</dd>
|
||||
<dt>beginGroupPut</dt>
|
||||
<dd>
|
||||
A set of puts is starting.
|
||||
Called with pvTop locked.
|
||||
</dd>
|
||||
<dt>endGroupPut</dt>
|
||||
<dd>
|
||||
The set of puts is complete.
|
||||
Called with pvTop locked.
|
||||
</dd>
|
||||
</dl>
|
||||
<h4>MonitorPluginCreator</h4>
|
||||
<p><b>MonitorPluginCreator</b> must also be implemented by the plugin implementation.
|
||||
It is called for each field instance that has options of the from
|
||||
<b>[plugin=name...]</b> where <b>name</b> is the name of the plugin.
|
||||
Note that a plugin instance will belong to a single client.
|
||||
It has methods:</p>
|
||||
<dl>
|
||||
<dt>getName</dt>
|
||||
<dd>Get the name of the plugin.</dd>
|
||||
<dt>create</dt>
|
||||
<dd>
|
||||
Create a new plugin instance.
|
||||
If the arguments are not compatible with the plugin a NULL shared pointer is
|
||||
returned.<br/>
|
||||
pvFieldOptions is
|
||||
a structure with a set of PVString subfields that specify <b>name,value</b>
|
||||
pairs. name is the subField name and value is the subField value.<br/>
|
||||
Note that a plugin will below to a single client.
|
||||
</dd>
|
||||
<dl>
|
||||
<h4>MonitorPluginManager</h4>
|
||||
<p><b>MonitorPluginManager</b> has the methods:</p>
|
||||
<dl>
|
||||
<dt>get</dt>
|
||||
<dd>
|
||||
MonitorPluginManager is a singleton.
|
||||
The first call to get will create the single instance.
|
||||
Further calls will return the single instance.
|
||||
</dd>
|
||||
<dt>addPlugin</dt>
|
||||
<dd>
|
||||
Add a new plugin.
|
||||
</dd>
|
||||
<dt>findPlugin</dt>
|
||||
<dd>
|
||||
Find a plugin. A NULL shared pointer is returned if it has not been added.
|
||||
</dd>
|
||||
<dt>showNames</dt>
|
||||
<dd>
|
||||
Show the names of all plugins that have been added.
|
||||
</dd>
|
||||
</dl>
|
||||
<p><b>NOTE:</b>
|
||||
Should the method <b>causeMonitor</b>
|
||||
have arguments <b>pvField</b> and <b>pvTop</b>
|
||||
be defined so that they can not be modified.
|
||||
This would be possible if the following was defined:
|
||||
<pre>
|
||||
typedef std::tr1::shared_ptr<const PVField> PVFieldConstPtr;
|
||||
typedef std::tr1::shared_ptr<const PVStructure> PVStructureConstPtr;
|
||||
</pre>
|
||||
then the definition for causeMonitor could be:
|
||||
<pre>
|
||||
virtual bool causeMonitor(
|
||||
PVFieldConstPtr const &pvField,
|
||||
PVStructureConstPtr const &pvTop,
|
||||
MonitorElementPtr const &monitorElement) = 0;
|
||||
</pre>
|
||||
But just adding these definitions is not sufficient.
|
||||
In addition all methods defined in pvDataCPP must be checked.
|
||||
In particular many of the methods in <b>Convert</b> must have
|
||||
their arguments modified.
|
||||
Big job.
|
||||
</p>
|
||||
<h2>monitorPlugin example</h2>
|
||||
<h3>Example Plugin Overview</h3>
|
||||
<p>This section describes an example plugin that:</p>
|
||||
<ul>
|
||||
<li>Only raises monitors when a field changes value.<br />
|
||||
If no plugin is provided
|
||||
the default is to raise a monitor when a put is issued to a field.</li>
|
||||
<li>Optionally a change will not raise a monitor.<br />
|
||||
The change will, however,
|
||||
appear if a put to another field raise a monitor.</li>
|
||||
</ul>
|
||||
<p>As an example assume that a channel provided by pvAccess has a top level structure
|
||||
that represents a power supply.</p>
|
||||
<pre>
|
||||
structure powerSupply
|
||||
structure alarm
|
||||
structure timeStamp
|
||||
structure power
|
||||
double value
|
||||
structure alarm
|
||||
structure display
|
||||
structure voltage
|
||||
double value
|
||||
structure alarm
|
||||
structure display
|
||||
structure current
|
||||
double value
|
||||
structure alarm
|
||||
structure display
|
||||
</pre>
|
||||
<p>A pvAccess client wants to create a monitor on the powerSupply as follows:
|
||||
The client wants a top level structure that looks like:
|
||||
<pre>
|
||||
structure powerSupply
|
||||
structure alarm
|
||||
structure timeStamp
|
||||
structure power
|
||||
double value
|
||||
structure voltage
|
||||
double value
|
||||
structure current
|
||||
double value
|
||||
</pre>
|
||||
In addition the client wants monitors to occur only when one of the monitored
|
||||
fields changes value but not just because a put occured.
|
||||
Also if only the timeStamp changes value then that should not cause a monitor.
|
||||
</p>
|
||||
<p>The example monitor plugin implements the semantics the
|
||||
client wants. It can be attached to any field via the following options:
|
||||
<pre>
|
||||
[plugin=onChange,raiseMonitor=value]
|
||||
</pre>
|
||||
This plugin will trigger a monitor for the field only if the field changes
|
||||
value. In addition <b>value</b> equals <b>false</b> means do not raise a monitor
|
||||
for changes to this field.
|
||||
But if a change to another field does cause a monitor the change to this field
|
||||
will be passed to the client.
|
||||
</p>
|
||||
<p>
|
||||
Assume that the client has already connected to the channel.
|
||||
The client can then issue the commands:</p>
|
||||
<pre>
|
||||
std::string request("field(alarm[plugin=onChange]");
|
||||
request += ",timeStamp[plugin=onChange,raiseMonitor=false]";
|
||||
request += ",power.value[plugin=onChange";
|
||||
request += ",voltage.value[plugin=onChange";
|
||||
request += ",current.value[plugin=onChange";
|
||||
|
||||
PVStructurePtr pvRequest = createRequest->createRequest(request);
|
||||
|
||||
MonitorPtr monitor = channel->createMonitor(monitorRequester,pvRequest);
|
||||
</pre>
|
||||
<h3>Example Plugin Code</h3>
|
||||
<p>The header file to create the example has the definition:</p>
|
||||
<pre>
|
||||
class ExampleMonitorPlugin{
|
||||
public:
|
||||
static void create();
|
||||
};
|
||||
</pre>
|
||||
<p>The implementation is:</p>
|
||||
<pre>
|
||||
class OnChangePlugin : public MonitorPlugin
|
||||
{
|
||||
public:
|
||||
virtual ~OnChangePlugin(){}
|
||||
OnChangePlugin() {}
|
||||
bool init(
|
||||
FieldConstPtr const &field,
|
||||
StructureConstPtr const &top,
|
||||
PVStructurePtr const &pvFieldOptions)
|
||||
{
|
||||
pvField = getPVDataCreate()->createPVField(field);
|
||||
raiseMonitor = true;
|
||||
if(pvFieldOptions!=NULL) {
|
||||
PVStringPtr pvString =
|
||||
pvFieldOptions->getSubField<PVString>("raiseMonitor");
|
||||
if(pvString!=NULL) {
|
||||
std::string value = pvString->get();
|
||||
if(value.compare("false")==0) raiseMonitor = false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
virtual std::string &getName(){return pluginName;}
|
||||
virtual bool causeMonitor(
|
||||
PVFieldPtr const &pvNew,
|
||||
PVStructurePtr const &pvTop,
|
||||
MonitorElementPtr const &monitorElement)
|
||||
{
|
||||
bool isSame = convert->equals(pvNew,pvField);
|
||||
if(isSame) return false;
|
||||
convert->copy(pvNew,pvField);
|
||||
return raiseMonitor;
|
||||
}
|
||||
private:
|
||||
PVFieldPtr pvField;
|
||||
bool raiseMonitor;
|
||||
};
|
||||
class OnChangePluginCreator : public MonitorPluginCreator
|
||||
{
|
||||
public:
|
||||
virtual std::string &getName(){return pluginName;}
|
||||
virtual MonitorPluginPtr create(
|
||||
FieldConstPtr const &field,
|
||||
StructureConstPtr const &top,
|
||||
PVStructurePtr const &pvFieldOptions)
|
||||
{
|
||||
OnChangePluginPtr plugin(new OnChangePlugin());
|
||||
bool result = plugin->init(field,top,pvFieldOptions);
|
||||
if(!result) return MonitorPluginPtr();
|
||||
return plugin;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
void ExampleMonitorPlugin::create()
|
||||
{
|
||||
static OnChangePluginCreatorPtr plugin;
|
||||
static Mutex mutex;
|
||||
Lock xx(mutex);
|
||||
if(plugin==NULL) {
|
||||
plugin = OnChangePluginCreatorPtr(new OnChangePluginCreator());
|
||||
MonitorPluginManager::get()->addPlugin(pluginName,plugin);
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
BIN
documentation/examples.zip
Normal file
BIN
documentation/examples.zip
Normal file
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -18,7 +18,7 @@ getFieldCreate()->createFieldBuilder()->
|
||||
createStructure();
|
||||
|
||||
// create a structure (cntd.)
|
||||
PVStructure::const_shared_pointer enum_t =
|
||||
StructureConstPtr enum_t =
|
||||
getFieldCreate()->createFieldBuilder()->
|
||||
setId("enum_t")->
|
||||
add("index", pvInt)->
|
||||
@@ -26,13 +26,13 @@ PVStructure::const_shared_pointer enum_t =
|
||||
createStructure();
|
||||
|
||||
// create a structure (cntd.)
|
||||
PVStructure::const_shared_pointer ntEnum =
|
||||
StructureConstPtr ntEnum =
|
||||
getFieldCreate()->createFieldBuilder()->
|
||||
setId("uri:ev4:nt/2012/pwd/NTEnum")->
|
||||
setId("epics:nt/NTEnum:1.0")->
|
||||
add("value", enum_t)->
|
||||
addNestedStructure("timeStamp")->
|
||||
setId("time_t")->
|
||||
add("secsPastEpoch", pvLong)->
|
||||
add("secondsPastEpoch", pvLong)->
|
||||
add("nanoseconds", pvInt)->
|
||||
add("userTag", pvInt)->
|
||||
endNested()->
|
||||
|
||||
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
@@ -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<double>, 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<Field>
|
||||
{
|
||||
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 &toString(Field::const_reference field, std::ostream& o);
|
||||
</font>
|
||||
|
||||
class Scalar : public Field{
|
||||
public:
|
||||
POINTER_DEFINITIONS(Scalar);
|
||||
virtual ~Scalar();
|
||||
typedef Scalar& reference;
|
||||
typedef const Scalar& 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& reference;
|
||||
typedef const ScalarArray& 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& reference;
|
||||
typedef const Structure& const_reference;
|
||||
|
||||
std::size_t getNumberFields() const {return numberFields;}
|
||||
FieldConstPtr getField(String const & fieldName) const;
|
||||
FieldConstPtr getField(std::size_t index) const;
|
||||
std::size_t getFieldIndex(String const &fieldName) const;
|
||||
FieldConstPtrArray const & getFields() const {return fields;}
|
||||
StringArray const & 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 &newName);
|
||||
virtual void toString(StringBuilder buf,int indentLevel) const;
|
||||
virtual String getID() const;
|
||||
</font>
|
||||
...
|
||||
};
|
||||
|
||||
class StructureArray : public Field{
|
||||
public:
|
||||
POINTER_DEFINITIONS(StructureArray);
|
||||
typedef StructureArray& reference;
|
||||
typedef const StructureArray& 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 & structure) const;
|
||||
StructureConstPtr createStructure (
|
||||
StringArray const & fieldNames,
|
||||
FieldConstPtrArray const & fields) const;
|
||||
StructureConstPtr createStructure (
|
||||
String const &id,
|
||||
StringArray const & fieldNames,
|
||||
FieldConstPtrArray const & fields) const;
|
||||
FieldConstPtr deserialize(ByteBuffer* buffer, DeserializableControl* control) const;
|
||||
<font color = "red">
|
||||
// following will be removed
|
||||
StructureConstPtr appendField(
|
||||
StructureConstPtr const & structure,
|
||||
String const &fieldName, FieldConstPtr const & field) const;
|
||||
StructureConstPtr appendFields(
|
||||
StructureConstPtr const & structure,
|
||||
StringArray const & fieldNames,
|
||||
FieldConstPtrArray const & fields) const;
|
||||
</font>
|
||||
...
|
||||
};
|
||||
|
||||
extern FieldCreatePtr getFieldCreate();
|
||||
</pre>
|
||||
<h3>Data Interfaces</h3>
|
||||
<pre>
|
||||
class PVField
|
||||
: virtual public Serializable,
|
||||
public std::tr1::enable_shared_from_this<PVField>
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVField);
|
||||
virtual ~PVField();
|
||||
inline const String &getFieldName() const ;
|
||||
virtual void setRequester(RequesterPtr const &prequester);
|
||||
std::size_t getFieldOffset() const;
|
||||
std::size_t getNextFieldOffset() const;
|
||||
std::size_t getNumberFields() const;
|
||||
const FieldConstPtr & getField() const ;
|
||||
PVStructure * getParent() const
|
||||
void postPut() ;
|
||||
void setPostHandler(PostHandlerPtr const &postHandler);
|
||||
// following will be removed
|
||||
<font color = "red">
|
||||
virtual void message(String message,MessageType messageType);
|
||||
void replacePVField(const PVFieldPtr& newPVField);
|
||||
String getFullName() const;
|
||||
virtual bool equals(PVField &pv);
|
||||
PVAuxInfoPtr & getPVAuxInfo()
|
||||
bool isImmutable() const;
|
||||
virtual void setImmutable();
|
||||
void replacePVField(const PVFieldPtr& newPVField);
|
||||
void renameField(String const &newName);
|
||||
virtual void toString(StringBuilder buf) ;
|
||||
virtual void toString(StringBuilder buf,int indentLevel);
|
||||
std::ostream& dumpValue(std::ostream& o) const;
|
||||
</font>
|
||||
...
|
||||
};
|
||||
|
||||
<font color = "blue">
|
||||
// The following is a new class
|
||||
class PVFieldToString {
|
||||
String toString(const PVFieldPtr &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 &reference;
|
||||
typedef const PVScalar& const_reference;
|
||||
|
||||
const ScalarConstPtr getScalar() const ;
|
||||
...
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
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& dumpValue(std::ostream& o)
|
||||
void operator>>=(T& value) const;
|
||||
void operator<<=(T value);
|
||||
</font>
|
||||
...
|
||||
}
|
||||
|
||||
// PVString is special case, since it implements SerializableArray
|
||||
class PVString : public PVScalarValue<String>, 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& dumpValue(std::ostream& o, std::size_t index) const = 0;
|
||||
</font>
|
||||
...
|
||||
};
|
||||
|
||||
class PVScalarArray : public PVArray {
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVScalarArray);
|
||||
virtual ~PVScalarArray();
|
||||
typedef PVScalarArray &reference;
|
||||
typedef const PVScalarArray& const_reference;
|
||||
|
||||
const ScalarArrayConstPtr getScalarArray() const ;
|
||||
<font color = "red">
|
||||
// following will be removed
|
||||
virtual std::ostream& dumpValue(std::ostream& o, size_t index) const = 0;
|
||||
</font>
|
||||
...
|
||||
}
|
||||
|
||||
<font color = "red">
|
||||
// following will be removed
|
||||
template<typename T>
|
||||
class PVArrayData {
|
||||
private:
|
||||
std::vector<T> init;
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVArrayData);
|
||||
typedef T value_type;
|
||||
typedef T* pointer;
|
||||
typedef const T* const_pointer;
|
||||
std::vector<T> & data;
|
||||
std::size_t offset;
|
||||
PVArrayData()
|
||||
: data(init)
|
||||
{}
|
||||
};
|
||||
</font>
|
||||
|
||||
template<typename T>
|
||||
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<T> svector;</font>
|
||||
<font color = "blue">typedef shared_vector<const T> const_svector; </font>
|
||||
|
||||
virtual ~PVValueArray() {}
|
||||
// following are added
|
||||
<font color = "blue">svector get();</font>
|
||||
<font color = "blue">void swap(svector& value);</font>
|
||||
<font color = "red">
|
||||
// following are removed
|
||||
typedef PVValueArray & reference;
|
||||
typedef const PVValueArray & const_reference;
|
||||
typedef PVArrayData<T> ArrayDataType;
|
||||
typedef std::vector<T> vector;
|
||||
typedef const std::vector<T> const_vector;
|
||||
typedef std::tr1::shared_ptr<vector> shared_vector;
|
||||
|
||||
virtual std::size_t get(
|
||||
std::size_t offset, std::size_t length, ArrayDataType &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 &from, std::size_t fromOffset);
|
||||
virtual void shareData(
|
||||
shared_vector const & value,
|
||||
std::size_t capacity,
|
||||
std::size_t length) = 0;
|
||||
virtual pointer get() = 0;
|
||||
virtual pointer get() const = 0;
|
||||
virtual vector const & getVector() = 0;
|
||||
virtual shared_vector const & getSharedVector() = 0;
|
||||
std::ostream& dumpValue(std::ostream& o) const;
|
||||
std::ostream& dumpValue(std::ostream& o, size_t index) const;
|
||||
</font>
|
||||
...
|
||||
};
|
||||
|
||||
typedef PVValueArray<uint8> PVBooleanArray;
|
||||
typedef std::tr1::shared_ptr<PVBooleanArray> PVBooleanArrayPtr;
|
||||
...
|
||||
typedef PVValueArray<String> PVStringArray;
|
||||
typedef std::tr1::shared_ptr<PVStringArray> PVStringArrayPtr;
|
||||
|
||||
class PVStructure : public PVField,public BitSetSerializable {
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVStructure);
|
||||
virtual ~PVStructure();
|
||||
typedef PVStructure & reference;
|
||||
typedef const PVStructure & const_reference;
|
||||
|
||||
StructureConstPtr getStructure() const;
|
||||
const PVFieldPtrArray & getPVFields() const;
|
||||
PVFieldPtr getSubField(String const &fieldName) const;
|
||||
PVFieldPtr getSubField(std::size_t fieldOffset) const;
|
||||
PVBooleanPtr getBooleanField(String const &fieldName) ;
|
||||
PVBytePtr getByteField(String const &fieldName) ;
|
||||
PVShortPtr getShortField(String const &fieldName) ;
|
||||
PVIntPtr getIntField(String const &fieldName) ;
|
||||
PVLongPtr getLongField(String const &fieldName) ;
|
||||
PVUBytePtr getUByteField(String const &fieldName) ;
|
||||
PVUShortPtr getUShortField(String const &fieldName) ;
|
||||
PVUIntPtr getUIntField(String const &fieldName) ;
|
||||
PVULongPtr getULongField(String const &fieldName) ;
|
||||
PVFloatPtr getFloatField(String const &fieldName) ;
|
||||
PVDoublePtr getDoubleField(String const &fieldName) ;
|
||||
PVStringPtr getStringField(String const &fieldName) ;
|
||||
PVStructurePtr getStructureField(String const &fieldName) ;
|
||||
PVScalarArrayPtr getScalarArrayField(
|
||||
String const &fieldName,ScalarType elementType) ;
|
||||
PVStructureArrayPtr getStructureArrayField(String const &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 & structure);
|
||||
PVStructure(StructureConstPtr const & structure,PVFieldPtrArray const & pvFields);
|
||||
<font color = "red">
|
||||
// following are removed
|
||||
void appendPVField(
|
||||
String const &fieldName,
|
||||
PVFieldPtr const & pvField);
|
||||
void appendPVFields(
|
||||
StringArray const & fieldNames,
|
||||
PVFieldPtrArray const & pvFields);
|
||||
void removePVField(String const &fieldName);
|
||||
virtual void setImmutable();
|
||||
String getExtendsStructureName() const;
|
||||
bool putExtendsStructureName(
|
||||
String const &extendsStructureName);
|
||||
</font>
|
||||
};
|
||||
|
||||
<font color = "red">
|
||||
// following will be removed
|
||||
typedef PVArrayData<PVStructurePtr> 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<PVStructurePtr> svector;
|
||||
typedef shared_vector<const PVStructurePtr> 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 & value);</font>
|
||||
<font color = "red">
|
||||
// following are removed
|
||||
typedef PVArrayData<PVStructurePtr> ArrayDataType;
|
||||
typedef std::vector<PVStructurePtr> vector;
|
||||
typedef const std::vector<PVStructurePtr> const_vector;
|
||||
typedef std::tr1::shared_ptr<vector> shared_vector;
|
||||
typedef PVStructureArray &reference;
|
||||
typedef const PVStructureArray& 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 &data);
|
||||
virtual std::size_t put(std::size_t offset,std::size_t length,
|
||||
const_vector const & from, std::size_t fromOffset);
|
||||
virtual void shareData(
|
||||
shared_vector const & value,
|
||||
std::size_t capacity,
|
||||
std::size_t length);
|
||||
virtual pointer get() { return &((*value.get())[0]); }
|
||||
virtual pointer get() const { return &((*value.get())[0]); }
|
||||
virtual vector const & getVector() {return *value;}
|
||||
virtual shared_vector const & getSharedVector() {return value;}
|
||||
</font>
|
||||
...
|
||||
};
|
||||
|
||||
class PVDataCreate {
|
||||
public:
|
||||
static PVDataCreatePtr getPVDataCreate();
|
||||
PVFieldPtr createPVField(FieldConstPtr const & field);
|
||||
PVFieldPtr createPVField(PVFieldPtr const & fieldToClone);
|
||||
PVScalarPtr createPVScalar(ScalarConstPtr const & scalar);
|
||||
PVScalarPtr createPVScalar(ScalarType scalarType);
|
||||
PVScalarPtr createPVScalar(PVScalarPtr const & scalarToClone);
|
||||
PVScalarArrayPtr createPVScalarArray(ScalarArrayConstPtr const & scalarArray);
|
||||
PVScalarArrayPtr createPVScalarArray(ScalarType elementType);
|
||||
PVScalarArrayPtr createPVScalarArray(PVScalarArrayPtr const & scalarArrayToClone);
|
||||
PVStructureArrayPtr createPVStructureArray(StructureArrayConstPtr const & structureArray);
|
||||
PVStructurePtr createPVStructure(StructureConstPtr const & structure);
|
||||
PVStructurePtr createPVStructure(
|
||||
StringArray const & fieldNames,PVFieldPtrArray const & pvFields);
|
||||
PVStructurePtr createPVStructure(PVStructurePtr const & structToClone);
|
||||
...
|
||||
};
|
||||
|
||||
extern PVDataCreatePtr getPVDataCreate();
|
||||
</pre>
|
||||
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -4,10 +4,41 @@
|
||||
# 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
|
||||
|
||||
# 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 MB
|
||||
|
||||
DEFAULT_BASE=3.15.4
|
||||
BASE=${BASE:-${DEFAULT_BASE}}
|
||||
MB=${MB:-"NO_MICROBENCH"}
|
||||
|
||||
###########################################
|
||||
# Fetch and unpack dependencies
|
||||
|
||||
@@ -17,10 +48,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 +66,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
74
jenkins/cloudbees_doc
Normal 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
|
||||
@@ -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
|
||||
@@ -1 +0,0 @@
|
||||
// ADD PREDEFINED MACROS HERE!
|
||||
@@ -1 +0,0 @@
|
||||
[General]
|
||||
211
pvDataCPP.files
211
pvDataCPP.files
@@ -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
|
||||
@@ -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
|
||||
@@ -3,15 +3,13 @@
|
||||
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
|
||||
|
||||
@@ -19,5 +17,8 @@ LIBRARY = pvData
|
||||
|
||||
pvData_LIBS += Com
|
||||
|
||||
# shared library ABI version.
|
||||
SHRLIB_VERSION ?= 6.0
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
|
||||
|
||||
9
src/copy/Makefile
Normal file
9
src/copy/Makefile
Normal 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
486
src/copy/createRequest.cpp
Normal 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 epics { namespace pvData {
|
||||
|
||||
static PVDataCreatePtr pvDataCreate = getPVDataCreate();
|
||||
static FieldCreatePtr fieldCreate = getFieldCreate();
|
||||
|
||||
class CreateRequestImpl : public CreateRequest {
|
||||
private:
|
||||
|
||||
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;
|
||||
|
||||
|
||||
public:
|
||||
CreateRequestImpl()
|
||||
{
|
||||
fullFieldName = "";
|
||||
}
|
||||
private:
|
||||
|
||||
|
||||
void removeBlanks(string& str)
|
||||
{
|
||||
while(true) {
|
||||
string::size_type pos = str.find_first_of(' ');
|
||||
if(pos==string::npos) return;
|
||||
str.erase(pos,1);
|
||||
}
|
||||
}
|
||||
|
||||
size_t findMatchingBrace(string& request, size_t index, int numOpen) {
|
||||
size_t openBrace = request.find('{', index+1);
|
||||
size_t closeBrace = request.find('}', index+1);
|
||||
if(openBrace == string::npos && closeBrace == string::npos){
|
||||
message = request + " mismatched {}";
|
||||
throw std::logic_error("message");
|
||||
}
|
||||
if (openBrace != string::npos && openBrace!=0) {
|
||||
if(openBrace<closeBrace) return findMatchingBrace(request,openBrace,numOpen+1);
|
||||
if(numOpen==1) return closeBrace;
|
||||
return findMatchingBrace(request,closeBrace,numOpen-1);
|
||||
}
|
||||
if(numOpen==1) return closeBrace;
|
||||
return findMatchingBrace(request,closeBrace,numOpen-1);
|
||||
}
|
||||
|
||||
size_t findMatchingBracket(string& request, size_t index) {
|
||||
for(size_t i=index+1; i< request.size(); ++i) {
|
||||
if(request[i] == ']') {
|
||||
if(i==index+1) {
|
||||
message = request + " mismatched []";
|
||||
throw std::logic_error("message");
|
||||
}
|
||||
return i;
|
||||
}
|
||||
}
|
||||
message = request + " missing ]";
|
||||
throw std::logic_error("message");
|
||||
}
|
||||
|
||||
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::logic_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) {
|
||||
message = item + " illegal option " + request;
|
||||
throw std::logic_error("message");
|
||||
}
|
||||
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::logic_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::logic_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::logic_error("illegal syntax " + request);
|
||||
}
|
||||
string subRequest = request.substr(end+1,endBrace-1 -end -1);
|
||||
if(subRequest.size()<1) {
|
||||
throw std::logic_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::logic_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;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
virtual PVStructurePtr createRequest(
|
||||
string const & crequest)
|
||||
{
|
||||
try {
|
||||
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;
|
||||
message = oss.str();
|
||||
return PVStructurePtr();
|
||||
}
|
||||
if(numBrace!=0) {
|
||||
ostringstream oss;
|
||||
oss << "mismatched {} " << numBrace;
|
||||
message = oss.str();
|
||||
return PVStructurePtr();
|
||||
}
|
||||
if(numBracket!=0) {
|
||||
ostringstream oss;
|
||||
oss << "mismatched [] " << numBracket;
|
||||
message = oss.str();
|
||||
return PVStructurePtr();
|
||||
}
|
||||
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) {
|
||||
message = request.substr(offsetRecord) +
|
||||
"record[ does not have matching ]";
|
||||
return PVStructurePtr();
|
||||
}
|
||||
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) {
|
||||
message = request.substr(offsetField)
|
||||
+ " field( does not have matching )";
|
||||
return PVStructurePtr();
|
||||
}
|
||||
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) {
|
||||
message = request.substr(offsetField)
|
||||
+ " getField( does not have matching )";
|
||||
return PVStructurePtr();
|
||||
}
|
||||
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) {
|
||||
message = request.substr(offsetField)
|
||||
+ " putField( does not have matching )";
|
||||
return PVStructurePtr();
|
||||
}
|
||||
if(closeParan>openParan+1) {
|
||||
createSubNode(node,request.substr(openParan+1,closeParan-openParan-1));
|
||||
}
|
||||
top.push_back(node);
|
||||
}
|
||||
} catch (std::exception &e) {
|
||||
string xxx = e.what();
|
||||
message = "while creating Structure exception " + xxx;
|
||||
return PVStructurePtr();
|
||||
}
|
||||
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;
|
||||
} catch (std::exception &e) {
|
||||
message = e.what();
|
||||
return PVStructurePtr();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
CreateRequest::shared_pointer CreateRequest::create()
|
||||
{
|
||||
CreateRequest::shared_pointer createRequest(new CreateRequestImpl());
|
||||
return createRequest;
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
59
src/copy/pv/createRequest.h
Normal file
59
src/copy/pv/createRequest.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*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();
|
||||
virtual ~CreateRequest() {};
|
||||
/**
|
||||
* Create a request structure for the create calls in Channel.
|
||||
* See the package overview documentation for details.
|
||||
* @param request The field request. See the package overview documentation for details.
|
||||
* @return The request PVStructure if a valid request was given.
|
||||
* If a NULL PVStructure is returned then getMessage will return
|
||||
* the reason.
|
||||
*/
|
||||
virtual PVStructure::shared_pointer createRequest(std::string const & request) = 0;
|
||||
/**
|
||||
* Get the error message of createRequest returns NULL
|
||||
* return the error message
|
||||
*/
|
||||
std::string getMessage() {return message;}
|
||||
protected:
|
||||
CreateRequest() {}
|
||||
std::string message;
|
||||
};
|
||||
|
||||
|
||||
}}
|
||||
|
||||
#endif /* CREATEREQUEST_H */
|
||||
|
||||
232
src/copy/pv/pvCopy.h
Normal file
232
src/copy/pv/pvCopy.h
Normal 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(){}
|
||||
virtual void destroy();
|
||||
/**
|
||||
* Get the top-level structure of master
|
||||
* @returns The master top-level structure.
|
||||
* This should not be modified.
|
||||
*/
|
||||
PVStructurePtr getPVMaster();
|
||||
/**
|
||||
* Traverse all the fields in master.
|
||||
* @param callback This is called for each field on master.
|
||||
*/
|
||||
void traverseMaster(PVCopyTraverseMasterCallbackPtr const & callback)
|
||||
{
|
||||
traverseMaster(headNode,callback);
|
||||
}
|
||||
/**
|
||||
* Get the introspection interface for a PVStructure for e copy.
|
||||
*/
|
||||
StructureConstPtr getStructure();
|
||||
/**
|
||||
* Create a copy instance. Monitors keep a queue of monitor elements.
|
||||
* Since each element needs a PVStructure, multiple top-level structures will be created.
|
||||
*/
|
||||
PVStructurePtr createPVStructure();
|
||||
/**
|
||||
* Given a field in pvMaster. return the offset in copy for the same field.
|
||||
* A value of std::string::npos means that the copy does not have this field.
|
||||
* @param masterPVField The field in master.
|
||||
*/
|
||||
std::size_t getCopyOffset(PVFieldPtr const &masterPVField);
|
||||
/**
|
||||
* Given a field in pvMaster. return the offset in copy for the same field.
|
||||
* A value of std::string::npos means that the copy does not have this field.
|
||||
* @param masterPVStructure A structure in master that has masterPVField.
|
||||
* @param masterPVField The field in master.
|
||||
*/
|
||||
std::size_t getCopyOffset(
|
||||
PVStructurePtr const &masterPVStructure,
|
||||
PVFieldPtr const &masterPVField);
|
||||
/**
|
||||
* Given 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 ©PVStructure,
|
||||
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 ©PVStructure,
|
||||
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 ©PVStructure,
|
||||
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 ©PVStructure,
|
||||
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 */
|
||||
656
src/copy/pvCopy.cpp
Normal file
656
src/copy/pvCopy.cpp
Normal file
@@ -0,0 +1,656 @@
|
||||
/* 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, ' ');
|
||||
}
|
||||
|
||||
static PVCopyPtr NULLPVCopy;
|
||||
static FieldConstPtr NULLField;
|
||||
static StructureConstPtr NULLStructure;
|
||||
static PVStructurePtr NULLPVStructure;
|
||||
static CopyNodePtr NULLCopyNode;
|
||||
static CopyMasterNodePtr NULLCopyMasterNode;
|
||||
|
||||
struct CopyNode {
|
||||
CopyNode()
|
||||
: isStructure(false),
|
||||
structureOffset(0),
|
||||
nfields(0)
|
||||
{}
|
||||
bool isStructure;
|
||||
size_t structureOffset; // In the copy
|
||||
size_t nfields;
|
||||
PVStructurePtr options;
|
||||
};
|
||||
|
||||
struct CopyMasterNode : public CopyNode{
|
||||
PVFieldPtr masterPVField;
|
||||
};
|
||||
|
||||
typedef std::vector<CopyNodePtr> CopyNodePtrArray;
|
||||
typedef std::tr1::shared_ptr<CopyNodePtrArray> CopyNodePtrArrayPtr;
|
||||
|
||||
struct CopyStructureNode : public CopyNode {
|
||||
CopyNodePtrArrayPtr nodes;
|
||||
};
|
||||
|
||||
PVCopyPtr PVCopy::create(
|
||||
PVStructurePtr const &pvMaster,
|
||||
PVStructurePtr const &pvRequest,
|
||||
string const & structureName)
|
||||
{
|
||||
PVStructurePtr pvStructure(pvRequest);
|
||||
if(structureName.size()>0) {
|
||||
if(pvRequest->getStructure()->getNumberFields()>0) {
|
||||
pvStructure = pvRequest->getSubField<PVStructure>(structureName);
|
||||
if(!pvStructure) return NULLPVCopy;
|
||||
}
|
||||
} else if(pvStructure->getSubField<PVStructure>("field")) {
|
||||
pvStructure = pvRequest->getSubField<PVStructure>("field");
|
||||
}
|
||||
PVCopyPtr pvCopy = PVCopyPtr(new PVCopy(pvMaster));
|
||||
bool result = pvCopy->init(pvStructure);
|
||||
if(!result) pvCopy.reset();
|
||||
return pvCopy;
|
||||
}
|
||||
|
||||
PVCopy::PVCopy(
|
||||
PVStructurePtr const &pvMaster)
|
||||
: pvMaster(pvMaster)
|
||||
{
|
||||
}
|
||||
|
||||
void PVCopy::destroy()
|
||||
{
|
||||
headNode.reset();
|
||||
}
|
||||
|
||||
PVStructurePtr PVCopy::getPVMaster()
|
||||
{
|
||||
return pvMaster;
|
||||
}
|
||||
|
||||
void PVCopy::traverseMaster(CopyNodePtr const &innode, PVCopyTraverseMasterCallbackPtr const & callback)
|
||||
{
|
||||
CopyNodePtr node = innode;
|
||||
if(!node->isStructure) {
|
||||
CopyMasterNodePtr masterNode = static_pointer_cast<CopyMasterNode>(node);
|
||||
callback->nextMasterPVField(masterNode->masterPVField);
|
||||
return;
|
||||
}
|
||||
CopyStructureNodePtr structNode = static_pointer_cast<CopyStructureNode>(node);
|
||||
CopyNodePtrArrayPtr nodes = structNode->nodes;
|
||||
for(size_t i=0; i< nodes->size(); i++) {
|
||||
node = (*nodes)[i];
|
||||
traverseMaster(node,callback);
|
||||
}
|
||||
}
|
||||
|
||||
StructureConstPtr PVCopy::getStructure()
|
||||
{
|
||||
return structure;
|
||||
}
|
||||
|
||||
PVStructurePtr PVCopy::createPVStructure()
|
||||
{
|
||||
if(cacheInitStructure) {
|
||||
PVStructurePtr save = cacheInitStructure;
|
||||
cacheInitStructure.reset();
|
||||
return save;
|
||||
}
|
||||
PVStructurePtr pvStructure =
|
||||
getPVDataCreate()->createPVStructure(structure);
|
||||
return pvStructure;
|
||||
}
|
||||
|
||||
PVStructurePtr PVCopy::getOptions(std::size_t fieldOffset)
|
||||
{
|
||||
if(fieldOffset==0) return headNode->options;
|
||||
CopyNodePtr node = headNode;
|
||||
while(true) {
|
||||
if(!node->isStructure) {
|
||||
if(node->structureOffset==fieldOffset) return node->options;
|
||||
return NULLPVStructure;
|
||||
}
|
||||
CopyStructureNodePtr structNode = static_pointer_cast<CopyStructureNode>(node);
|
||||
CopyNodePtrArrayPtr nodes = structNode->nodes;
|
||||
boolean okToContinue = false;
|
||||
for(size_t i=0; i< nodes->size(); i++) {
|
||||
node = (*nodes)[i];
|
||||
size_t soff = node->structureOffset;
|
||||
if(fieldOffset>=soff && fieldOffset<soff+node->nfields) {
|
||||
if(fieldOffset==soff) return node->options;
|
||||
if(!node->isStructure) {
|
||||
return NULLPVStructure;
|
||||
}
|
||||
okToContinue = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(okToContinue) continue;
|
||||
throw std::invalid_argument("fieldOffset not valid");
|
||||
}
|
||||
}
|
||||
|
||||
size_t PVCopy::getCopyOffset(PVFieldPtr const &masterPVField)
|
||||
{
|
||||
if(masterPVField->getFieldOffset()==0) return 0;
|
||||
if(!headNode->isStructure) {
|
||||
CopyMasterNodePtr masterNode = static_pointer_cast<CopyMasterNode>(headNode);
|
||||
if((masterNode->masterPVField.get())==masterPVField.get()) {
|
||||
return headNode->structureOffset;
|
||||
}
|
||||
PVStructure * parent = masterPVField->getParent();
|
||||
size_t offsetParent = parent->getFieldOffset();
|
||||
size_t off = masterPVField->getFieldOffset();
|
||||
size_t offdiff = off -offsetParent;
|
||||
if(offdiff<masterNode->nfields) return headNode->structureOffset + offdiff;
|
||||
return string::npos;
|
||||
}
|
||||
CopyStructureNodePtr node = static_pointer_cast<CopyStructureNode>(headNode);
|
||||
CopyMasterNodePtr masterNode = getCopyOffset(node,masterPVField);
|
||||
if(masterNode) 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 ©PVStructure,
|
||||
BitSetPtr const &bitSet)
|
||||
{
|
||||
bitSet->clear();
|
||||
bitSet->set(0);
|
||||
updateCopyFromBitSet(copyPVStructure,bitSet);
|
||||
}
|
||||
|
||||
void PVCopy::updateCopySetBitSet(
|
||||
PVStructurePtr const ©PVStructure,
|
||||
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 ©PVStructure,
|
||||
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 ©PVStructure,
|
||||
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 NULLStructure;
|
||||
FieldConstPtrArray fields; fields.reserve(length);
|
||||
StringArray fieldNames; fields.reserve(length);
|
||||
for(size_t i=0; i<length; ++i) {
|
||||
string const &fieldName = fromRequestFieldNames[i];
|
||||
PVFieldPtr pvMasterField = pvMaster->getSubField(fieldName);
|
||||
if(!pvMasterField) continue;
|
||||
FieldConstPtr field = pvMasterField->getField();
|
||||
if(field->getType()==epics::pvData::structure) {
|
||||
PVStructurePtr pvRequestStructure = static_pointer_cast<PVStructure>(
|
||||
pvFromRequestFields[i]);
|
||||
if(pvRequestStructure->getNumberFields()>0) {
|
||||
StringArray const &names = pvRequestStructure->getStructure()->
|
||||
getFieldNames();
|
||||
size_t num = names.size();
|
||||
if(num>0 && names[0].compare("_options")==0) --num;
|
||||
if(num>0) {
|
||||
if(pvMasterField->getField()->getType()!=epics::pvData::structure) continue;
|
||||
fieldNames.push_back(fieldName);
|
||||
fields.push_back(createStructure(
|
||||
static_pointer_cast<PVStructure>(pvMasterField),
|
||||
pvRequestStructure));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
fieldNames.push_back(fieldName);
|
||||
fields.push_back(field);
|
||||
}
|
||||
size_t numsubfields = fields.size();
|
||||
if(numsubfields==0) return NULLStructure;
|
||||
return getFieldCreate()->createStructure(fieldNames, fields);
|
||||
}
|
||||
|
||||
CopyNodePtr PVCopy::createStructureNodes(
|
||||
PVStructurePtr const &pvMasterStructure,
|
||||
PVStructurePtr const &pvFromRequest,
|
||||
PVStructurePtr const &pvFromCopy)
|
||||
{
|
||||
PVFieldPtrArray const & copyPVFields = pvFromCopy->getPVFields();
|
||||
PVStructurePtr pvOptions;
|
||||
PVFieldPtr pvField = pvFromRequest->getSubField("_options");
|
||||
if(pvField) 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 NULLCopyMasterNode;
|
||||
}
|
||||
|
||||
CopyMasterNodePtr PVCopy::getMasterNode(
|
||||
CopyStructureNodePtr const &structureNode,
|
||||
std::size_t structureOffset)
|
||||
{
|
||||
CopyNodePtrArrayPtr nodes = structureNode->nodes;
|
||||
for(size_t i=0; i< nodes->size(); i++) {
|
||||
CopyNodePtr node = (*nodes)[i];
|
||||
if(structureOffset>=(node->structureOffset + node->nfields)) continue;
|
||||
if(!node->isStructure) {
|
||||
CopyMasterNodePtr masterNode =
|
||||
static_pointer_cast<CopyMasterNode>(node);
|
||||
return masterNode;
|
||||
}
|
||||
CopyStructureNodePtr subNode =
|
||||
static_pointer_cast<CopyStructureNode>(node);
|
||||
return getMasterNode(subNode,structureOffset);
|
||||
}
|
||||
return NULLCopyMasterNode;
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}}
|
||||
@@ -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,18 @@
|
||||
#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>
|
||||
|
||||
using std::tr1::static_pointer_cast;
|
||||
using std::size_t;
|
||||
using std::string;
|
||||
using std::min;
|
||||
|
||||
namespace epics { namespace pvData {
|
||||
@@ -43,7 +44,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;
|
||||
@@ -83,7 +84,7 @@ template<typename T>
|
||||
BasePVScalar<T>::BasePVScalar(ScalarConstPtr const & scalar)
|
||||
: PVScalarValue<T>(scalar),value(0)
|
||||
{}
|
||||
//Note: '0' is a suitable default for all POD types (not String)
|
||||
//Note: '0' is a suitable default for all POD types (not string)
|
||||
|
||||
template<typename T>
|
||||
BasePVScalar<T>::~BasePVScalar() {}
|
||||
@@ -128,14 +129,14 @@ typedef BasePVScalar<double> BasePVDouble;
|
||||
// BasePVString is special case, since it implements SerializableArray
|
||||
class BasePVString : public PVString {
|
||||
public:
|
||||
typedef String value_type;
|
||||
typedef String* pointer;
|
||||
typedef const String* const_pointer;
|
||||
typedef string value_type;
|
||||
typedef string* pointer;
|
||||
typedef const string* const_pointer;
|
||||
|
||||
BasePVString(ScalarConstPtr const & scalar);
|
||||
virtual ~BasePVString();
|
||||
virtual String get() const ;
|
||||
virtual void put(String val);
|
||||
virtual string get() const ;
|
||||
virtual void put(string val);
|
||||
virtual void serialize(ByteBuffer *pbuffer,
|
||||
SerializableControl *pflusher) const;
|
||||
virtual void deserialize(ByteBuffer *pbuffer,
|
||||
@@ -143,19 +144,29 @@ public:
|
||||
virtual void serialize(ByteBuffer *pbuffer,
|
||||
SerializableControl *pflusher, size_t offset, size_t count) const;
|
||||
private:
|
||||
String value;
|
||||
string value;
|
||||
std::size_t maxLength;
|
||||
};
|
||||
|
||||
BasePVString::BasePVString(ScalarConstPtr const & scalar)
|
||||
: PVString(scalar),value()
|
||||
{}
|
||||
{
|
||||
BoundedStringConstPtr boundedString = std::tr1::dynamic_pointer_cast<const BoundedString>(scalar);
|
||||
if (boundedString.get())
|
||||
maxLength = boundedString->getMaximumLength();
|
||||
else
|
||||
maxLength = 0;
|
||||
}
|
||||
|
||||
BasePVString::~BasePVString() {}
|
||||
|
||||
String BasePVString::get() const { return value;}
|
||||
string BasePVString::get() const { return value;}
|
||||
|
||||
void BasePVString::put(String val)
|
||||
void BasePVString::put(string val)
|
||||
{
|
||||
if (maxLength > 0 && val.length() > maxLength)
|
||||
throw std::overflow_error("string too long");
|
||||
|
||||
value = val;
|
||||
postPut();
|
||||
}
|
||||
@@ -189,6 +200,19 @@ void BasePVString::serialize(ByteBuffer *pbuffer,
|
||||
SerializeHelper::serializeSubstring(value, offset, count, pbuffer, pflusher);
|
||||
}
|
||||
|
||||
void PVArray::checkLength(size_t len)
|
||||
{
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
/** Default storage for arrays
|
||||
*/
|
||||
template<typename T>
|
||||
@@ -230,7 +254,14 @@ DefaultPVArray<T>::DefaultPVArray(ScalarArrayConstPtr const & scalarArray)
|
||||
: PVValueArray<T>(scalarArray),
|
||||
value()
|
||||
|
||||
{ }
|
||||
{
|
||||
ArrayConstPtr array = this->getArray();
|
||||
if (array->getArraySizeType() == Array::fixed)
|
||||
{
|
||||
// this->setLength(array->getMaximumCapacity());
|
||||
this->setCapacityMutable(false);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
DefaultPVArray<T>::~DefaultPVArray()
|
||||
@@ -239,18 +270,25 @@ template<typename T>
|
||||
void DefaultPVArray<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 DefaultPVArray<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);
|
||||
@@ -259,6 +297,8 @@ void DefaultPVArray<T>::setLength(size_t length)
|
||||
template<typename T>
|
||||
void DefaultPVArray<T>::replace(const const_svector& next)
|
||||
{
|
||||
this->checkLength(next.size());
|
||||
|
||||
value = next;
|
||||
this->postPut();
|
||||
}
|
||||
@@ -266,8 +306,10 @@ void DefaultPVArray<T>::replace(const const_svector& next)
|
||||
template<typename T>
|
||||
void DefaultPVArray<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);
|
||||
}
|
||||
@@ -282,7 +324,10 @@ void DefaultPVArray<T>::serialize(ByteBuffer *pbuffer,
|
||||
template<typename T>
|
||||
void DefaultPVArray<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,6 +365,7 @@ void DefaultPVArray<T>::deserialize(ByteBuffer *pbuffer,
|
||||
remaining -= n2read;
|
||||
}
|
||||
value = freeze(nextvalue);
|
||||
// TODO !!!
|
||||
// inform about the change?
|
||||
PVField::postPut();
|
||||
}
|
||||
@@ -333,7 +379,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 +412,15 @@ void DefaultPVArray<T>::serialize(ByteBuffer *pbuffer,
|
||||
}
|
||||
}
|
||||
|
||||
// specializations for String
|
||||
// specializations for string
|
||||
|
||||
template<>
|
||||
void DefaultPVArray<String>::deserialize(ByteBuffer *pbuffer,
|
||||
void DefaultPVArray<string>::deserialize(ByteBuffer *pbuffer,
|
||||
DeserializableControl *pcontrol) {
|
||||
size_t size = SerializeHelper::readSize(pbuffer, pcontrol);
|
||||
|
||||
size_t size = this->getArray()->getArraySizeType() == Array::fixed ?
|
||||
this->getArray()->getMaximumCapacity() :
|
||||
SerializeHelper::readSize(pbuffer, pcontrol);
|
||||
|
||||
svector nextvalue(thaw(value));
|
||||
|
||||
@@ -378,7 +431,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,15 +442,17 @@ void DefaultPVArray<String>::deserialize(ByteBuffer *pbuffer,
|
||||
}
|
||||
|
||||
template<>
|
||||
void DefaultPVArray<String>::serialize(ByteBuffer *pbuffer,
|
||||
void DefaultPVArray<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);
|
||||
}
|
||||
@@ -414,7 +469,7 @@ typedef DefaultPVArray<uint32> BasePVUIntArray;
|
||||
typedef DefaultPVArray<uint64> BasePVULongArray;
|
||||
typedef DefaultPVArray<float> BasePVFloatArray;
|
||||
typedef DefaultPVArray<double> BasePVDoubleArray;
|
||||
typedef DefaultPVArray<String> BasePVStringArray;
|
||||
typedef DefaultPVArray<string> BasePVStringArray;
|
||||
|
||||
// Factory
|
||||
|
||||
@@ -472,7 +527,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 +537,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 +552,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;
|
||||
}
|
||||
}
|
||||
@@ -547,17 +602,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;
|
||||
}
|
||||
|
||||
@@ -607,16 +652,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 +703,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 +712,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;
|
||||
}
|
||||
|
||||
@@ -706,3 +741,12 @@ PVDataCreatePtr getPVDataCreate() {
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
namespace std{
|
||||
std::ostream& operator<<(std::ostream& o, const epics::pvData::PVField *ptr)
|
||||
{
|
||||
if(ptr) return o << *ptr;
|
||||
return o << "nullptr";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,21 +11,21 @@
|
||||
#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>
|
||||
|
||||
using std::tr1::const_pointer_cast;
|
||||
using std::size_t;
|
||||
using std::string;
|
||||
|
||||
namespace epics { namespace pvData {
|
||||
|
||||
|
||||
PVField::PVField(FieldConstPtr field)
|
||||
: notImplemented("not implemented"),
|
||||
parent(NULL),field(field),
|
||||
: parent(NULL),field(field),
|
||||
fieldOffset(0), nextFieldOffset(0),
|
||||
immutable(false)
|
||||
{
|
||||
@@ -35,49 +34,6 @@ PVField::PVField(FieldConstPtr field)
|
||||
PVField::~PVField()
|
||||
{ }
|
||||
|
||||
void PVField::message(
|
||||
String message,
|
||||
MessageType messageType,
|
||||
String fullFieldName)
|
||||
{
|
||||
if(parent!=NULL) {
|
||||
if(fullFieldName.length()>0) {
|
||||
fullFieldName = fieldName + '.' + fullFieldName;
|
||||
} else {
|
||||
fullFieldName = fieldName;
|
||||
}
|
||||
parent->message(message,messageType,fullFieldName);
|
||||
return;
|
||||
}
|
||||
message = fullFieldName + " " + message;
|
||||
if(requester) {
|
||||
requester->message(message,messageType);
|
||||
} else {
|
||||
printf("%s %s %s\n",
|
||||
getMessageTypeName(messageType).c_str(),
|
||||
fieldName.c_str(),
|
||||
message.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void PVField::message(String message,MessageType messageType)
|
||||
{
|
||||
PVField::message(message,messageType,"");
|
||||
}
|
||||
|
||||
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,12 +53,6 @@ size_t PVField::getNumberFields() const
|
||||
return (nextFieldOffset - fieldOffset);
|
||||
}
|
||||
|
||||
PVAuxInfoPtr & PVField::getPVAuxInfo(){
|
||||
if(pvAuxInfo.get()==NULL) {
|
||||
pvAuxInfo = PVAuxInfoPtr(new PVAuxInfo(this));
|
||||
}
|
||||
return pvAuxInfo;
|
||||
}
|
||||
|
||||
bool PVField::isImmutable() const {return immutable;}
|
||||
|
||||
@@ -112,46 +62,6 @@ 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();
|
||||
|
||||
string ret(fieldName);
|
||||
for(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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,12 +15,12 @@
|
||||
#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 {
|
||||
|
||||
@@ -44,23 +43,18 @@ 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 +69,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]);
|
||||
@@ -109,9 +103,13 @@ const PVFieldPtrArray & PVStructure::getPVFields() const
|
||||
return pvFields;
|
||||
}
|
||||
|
||||
PVFieldPtr PVStructure::getSubField(String const &fieldName) const
|
||||
PVFieldPtr PVStructure::getSubField(const char * fieldName) const
|
||||
{
|
||||
return findSubField(fieldName,this);
|
||||
PVField * field = getSubFieldImpl(fieldName, false);
|
||||
if (field)
|
||||
return field->shared_from_this();
|
||||
else
|
||||
return PVFieldPtr();
|
||||
}
|
||||
|
||||
|
||||
@@ -134,225 +132,113 @@ PVFieldPtr PVStructure::getSubField(size_t fieldOffset) const
|
||||
throw std::logic_error("PVStructure.getSubField: Logic error");
|
||||
}
|
||||
|
||||
void PVStructure::fixParentStructure()
|
||||
PVFieldPtr PVStructure::getSubFieldT(std::size_t fieldOffset) 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;
|
||||
PVFieldPtr pvField = getSubField(fieldOffset);
|
||||
if (pvField.get())
|
||||
return pvField;
|
||||
else
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "Failed to get field with offset "
|
||||
<< fieldOffset << "(Invalid offset)" ;
|
||||
throw std::runtime_error(ss.str());
|
||||
}
|
||||
}
|
||||
|
||||
PVField* PVStructure::getSubFieldImpl(const char *name, bool throws) const
|
||||
{
|
||||
const PVStructure *parent = this;
|
||||
if(!name)
|
||||
{
|
||||
if (throws)
|
||||
throw std::invalid_argument("Failed to get field: (Field name is NULL string)");
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
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 NULL;
|
||||
}
|
||||
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 NULL;
|
||||
}
|
||||
|
||||
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 NULL;
|
||||
}
|
||||
|
||||
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 NULL;
|
||||
}
|
||||
child = NULL;
|
||||
name = sep+1; // skip past '.'
|
||||
// loop around to new parent
|
||||
|
||||
} else {
|
||||
fields[i] = oldFields[i];
|
||||
return child;
|
||||
}
|
||||
}
|
||||
FieldConstPtr field = getFieldCreate()->createStructure(
|
||||
parentStructure->getID(),fieldNames,fields);
|
||||
parent->replaceField(field);
|
||||
parent->fixParentStructure();
|
||||
}
|
||||
|
||||
void PVStructure::appendPVField(
|
||||
String const &fieldName,
|
||||
PVFieldPtr const & pvField)
|
||||
{
|
||||
size_t origLength = pvFields.size();
|
||||
size_t newLength = origLength+1;
|
||||
PVFieldPtrArray * xxx = const_cast<PVFieldPtrArray *>(&pvFields);
|
||||
xxx->push_back(pvField);
|
||||
FieldConstPtr field = getFieldCreate()->appendField(
|
||||
structurePtr,fieldName,pvField->getField());
|
||||
replaceField(field);
|
||||
structurePtr = static_pointer_cast<const Structure>(field);
|
||||
StringArray fieldNames = structurePtr->getFieldNames();
|
||||
for(size_t i=0; i<newLength; i++) {
|
||||
pvFields[i]->setParentAndName(this,fieldNames[i]);
|
||||
}
|
||||
fixParentStructure();
|
||||
}
|
||||
|
||||
void PVStructure::appendPVFields(
|
||||
StringArray const & fieldNames,
|
||||
PVFieldPtrArray const & pvFields)
|
||||
{
|
||||
size_t origLength = this->pvFields.size();
|
||||
size_t extra = fieldNames.size();
|
||||
if(extra==0) return;
|
||||
size_t newLength = origLength + extra;
|
||||
PVFieldPtrArray * xxx = const_cast<PVFieldPtrArray *>(&this->pvFields);
|
||||
xxx->reserve(newLength);
|
||||
for(size_t i=0; i<extra; i++) {
|
||||
xxx->push_back(pvFields[i]);
|
||||
}
|
||||
FieldConstPtrArray fields;
|
||||
fields.reserve(extra);
|
||||
for(size_t i=0; i<extra; i++) fields.push_back(pvFields[i]->getField());
|
||||
FieldConstPtr field = getFieldCreate()->appendFields(
|
||||
structurePtr,fieldNames,fields);
|
||||
replaceField(field);
|
||||
structurePtr = static_pointer_cast<const Structure>(field);
|
||||
StringArray names = structurePtr->getFieldNames();
|
||||
for(size_t i=0; i<newLength; i++) {
|
||||
(*xxx)[i]->setParentAndName(this,names[i]);
|
||||
}
|
||||
fixParentStructure();
|
||||
}
|
||||
|
||||
void PVStructure::removePVField(String const &fieldName)
|
||||
{
|
||||
PVFieldPtr pvField = getSubField(fieldName);
|
||||
if(pvField.get()==NULL) {
|
||||
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;
|
||||
}
|
||||
|
||||
void PVStructure::serialize(ByteBuffer *pbuffer,
|
||||
SerializableControl *pflusher) const {
|
||||
@@ -371,9 +257,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
|
||||
@@ -443,44 +328,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 +351,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
@@ -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,18 +15,20 @@
|
||||
#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;
|
||||
|
||||
PVDataCreatePtr PVUnion::pvDataCreate(getPVDataCreate());
|
||||
|
||||
PVUnion::PVUnion(UnionConstPtr const & unionPtr)
|
||||
: PVField(unionPtr),
|
||||
unionPtr(unionPtr),
|
||||
@@ -58,11 +59,11 @@ 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);
|
||||
}
|
||||
@@ -86,12 +87,12 @@ PVFieldPtr PVUnion::select(int32 index)
|
||||
|
||||
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)
|
||||
@@ -126,9 +127,10 @@ void PVUnion::set(int32 index, PVFieldPtr const & value)
|
||||
|
||||
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)
|
||||
@@ -142,10 +144,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 +169,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 +179,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
|
||||
@@ -207,4 +217,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)
|
||||
{
|
||||
|
||||
PVFieldPtr 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
}}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
@@ -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 */
|
||||
@@ -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*)▮
|
||||
|
||||
/* 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
17
src/factory/pv/factory.h
Normal 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 */
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
@@ -2,30 +2,29 @@
|
||||
|
||||
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/requester.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/messageQueue.h
|
||||
INC += pv/destroyable.h
|
||||
INC += pv/status.h
|
||||
INC += pv/sharedPtr.h
|
||||
INC += pv/localStaticLock.h
|
||||
INC += pv/typeCast.h
|
||||
INC += pv/sharedVector.h
|
||||
INC += pv/templateMeta.h
|
||||
INC += pv/current_function.h
|
||||
|
||||
LIBSRCS += byteBuffer.cpp
|
||||
LIBSRCS += bitSet.cpp
|
||||
|
||||
@@ -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,88 +48,59 @@ 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);
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void BitSet::flip(uint32 bitIndex) {
|
||||
|
||||
uint32 wordIdx = wordIndex(bitIndex);
|
||||
uint32 wordIdx = WORD_INDEX(bitIndex);
|
||||
expandTo(wordIdx);
|
||||
|
||||
words[wordIdx] ^= (((uint64)1) << (bitIndex % BITS_PER_WORD));
|
||||
words[wordIdx] ^= (((uint64)1) << WORD_OFFSET(bitIndex));
|
||||
|
||||
recalculateWordsInUse();
|
||||
}
|
||||
|
||||
void BitSet::set(uint32 bitIndex) {
|
||||
|
||||
uint32 wordIdx = wordIndex(bitIndex);
|
||||
uint32 wordIdx = WORD_INDEX(bitIndex);
|
||||
expandTo(wordIdx);
|
||||
|
||||
words[wordIdx] |= (((uint64)1) << (bitIndex % BITS_PER_WORD));
|
||||
words[wordIdx] |= (((uint64)1) << WORD_OFFSET(bitIndex));
|
||||
}
|
||||
|
||||
void BitSet::clear(uint32 bitIndex) {
|
||||
|
||||
uint32 wordIdx = wordIndex(bitIndex);
|
||||
if (wordIdx >= wordsInUse)
|
||||
uint32 wordIdx = WORD_INDEX(bitIndex);
|
||||
if (wordIdx >= words.size())
|
||||
return;
|
||||
|
||||
words[wordIdx] &= ~(((uint64)1) << (bitIndex % BITS_PER_WORD));
|
||||
words[wordIdx] &= ~(((uint64)1) << WORD_OFFSET(bitIndex));
|
||||
|
||||
recalculateWordsInUse();
|
||||
}
|
||||
@@ -117,14 +113,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 +148,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 +157,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 +166,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 +175,63 @@ 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;
|
||||
}
|
||||
|
||||
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 +239,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 +267,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 +283,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;
|
||||
}
|
||||
|
||||
}};
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
@@ -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,15 @@
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
|
||||
#include <epicsEvent.h>
|
||||
#include <epicsMutex.h>
|
||||
#include <epicsThread.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/executor.h>
|
||||
|
||||
using std::string;
|
||||
|
||||
namespace epics { namespace pvData {
|
||||
|
||||
// special instance to stop the executor thread
|
||||
@@ -31,7 +36,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 +57,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 +85,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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
/* 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.
|
||||
/*
|
||||
* Copyright information and license terms for this software can be
|
||||
* found in the file LICENSE that is included with the distribution
|
||||
*/
|
||||
/**
|
||||
* @author mrk
|
||||
@@ -12,13 +11,15 @@
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/messageQueue.h>
|
||||
|
||||
using std::string;
|
||||
|
||||
namespace epics { namespace pvData {
|
||||
|
||||
MessageNode::MessageNode()
|
||||
: messageType(infoMessage)
|
||||
{}
|
||||
|
||||
String MessageNode::getMessage() const
|
||||
string MessageNode::getMessage() const
|
||||
{
|
||||
return message;
|
||||
}
|
||||
@@ -59,7 +60,7 @@ void MessageQueue::release() {
|
||||
releaseUsed(lastGet);
|
||||
lastGet.reset();
|
||||
}
|
||||
bool MessageQueue::put(String message,MessageType messageType,bool replaceLast)
|
||||
bool MessageQueue::put(string message,MessageType messageType,bool replaceLast)
|
||||
{
|
||||
MessageNodePtr node = getFree();
|
||||
if(node.get()!= NULL) {
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}}}
|
||||
|
||||
@@ -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,7 @@
|
||||
#ifndef BITSET_H
|
||||
#define BITSET_H
|
||||
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
#include <pv/pvType.h>
|
||||
#include <pv/serialize.h>
|
||||
@@ -24,16 +23,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 +42,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,14 +52,14 @@ 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
|
||||
*/
|
||||
@@ -78,14 +79,14 @@ namespace epics { namespace pvData {
|
||||
void 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);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@@ -101,9 +102,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 +111,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 +129,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,23 +144,23 @@ 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
|
||||
@@ -170,9 +170,9 @@ namespace epics { namespace pvData {
|
||||
/**
|
||||
* Performs a logical <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
|
||||
*/
|
||||
@@ -181,9 +181,9 @@ namespace epics { namespace pvData {
|
||||
/**
|
||||
* Performs a logical <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
|
||||
*/
|
||||
@@ -192,13 +192,13 @@ namespace epics { namespace pvData {
|
||||
/**
|
||||
* Performs a logical <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 +206,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 +228,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 +235,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 +287,8 @@ namespace epics { namespace pvData {
|
||||
static uint32 bitCount(uint64 i);
|
||||
|
||||
};
|
||||
|
||||
epicsShareExtern std::ostream& operator<<(std::ostream& o, const BitSet& b);
|
||||
|
||||
}}
|
||||
#endif /* BITSET_H */
|
||||
@@ -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,24 +10,15 @@
|
||||
#define BYTEBUFFER_H
|
||||
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
#define byteBufferepicsExportSharedSymbols
|
||||
#undef epicsExportSharedSymbols
|
||||
#endif
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <epicsEndian.h>
|
||||
|
||||
#ifdef byteBufferepicsExportSharedSymbols
|
||||
#define epicsExportSharedSymbols
|
||||
#undef byteBufferepicsExportSharedSymbols
|
||||
#endif
|
||||
#include <shareLib.h>
|
||||
|
||||
#include <pv/pvType.h>
|
||||
#include <pv/epicsException.h>
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
namespace epics {
|
||||
namespace pvData {
|
||||
@@ -144,6 +134,24 @@ inline int64 swap(int64 val)
|
||||
return swap64(val);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline uint16 swap(uint16 val)
|
||||
{
|
||||
return swap16(val);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline uint32 swap(uint32 val)
|
||||
{
|
||||
return swap32(val);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline uint64 swap(uint64 val)
|
||||
{
|
||||
return swap64(val);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline float swap(float val)
|
||||
{
|
||||
@@ -188,8 +196,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 +214,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 +238,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 +247,7 @@ public:
|
||||
*/
|
||||
~ByteBuffer()
|
||||
{
|
||||
if (_buffer && !_wrapped) free(_buffer);
|
||||
if (_buffer && !_wrapped) std::free(_buffer);
|
||||
}
|
||||
/**
|
||||
* Set the byte order.
|
||||
@@ -252,7 +264,7 @@ public:
|
||||
* Get the raw buffer data.
|
||||
* @return the raw buffer data.
|
||||
*/
|
||||
inline const char* getBuffer()
|
||||
inline const char* getBuffer() const
|
||||
{
|
||||
return _buffer;
|
||||
}
|
||||
@@ -284,7 +296,7 @@ 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));
|
||||
}
|
||||
@@ -304,7 +316,7 @@ public:
|
||||
*
|
||||
* @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));
|
||||
}
|
||||
@@ -325,7 +337,7 @@ public:
|
||||
*
|
||||
* @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));
|
||||
}
|
||||
@@ -334,7 +346,7 @@ public:
|
||||
*
|
||||
* @return The size of the raw data buffer.
|
||||
*/
|
||||
inline std::size_t getSize()
|
||||
inline std::size_t getSize() const
|
||||
{
|
||||
return _size;
|
||||
}
|
||||
@@ -354,7 +366,7 @@ public:
|
||||
template<typename T>
|
||||
inline void put(std::size_t index, T value);
|
||||
/**
|
||||
* 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,7 +380,7 @@ 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.
|
||||
@@ -380,9 +392,9 @@ public:
|
||||
* 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,
|
||||
*/
|
||||
inline void put(const char* src, std::size_t src_offset, std::size_t count) {
|
||||
//if(count>getRemaining()) THROW_BASE_EXCEPTION("buffer overflow");
|
||||
@@ -393,9 +405,9 @@ 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.
|
||||
*/
|
||||
inline void get(char* dest, std::size_t dest_offset, std::size_t count) {
|
||||
//if(count>getRemaining()) THROW_BASE_EXCEPTION("buffer overflow");
|
||||
@@ -403,7 +415,7 @@ public:
|
||||
_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,7 +437,7 @@ public:
|
||||
* @return (false,true) if (is, is not) the EPICS_BYTE_ORDER
|
||||
*/
|
||||
template<typename T>
|
||||
inline bool reverse()
|
||||
inline bool reverse() const
|
||||
{
|
||||
return _reverseEndianess;
|
||||
}
|
||||
@@ -618,54 +630,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;
|
||||
}
|
||||
@@ -695,7 +707,7 @@ private:
|
||||
}
|
||||
else
|
||||
{
|
||||
// NOTE: this check and branching does not always payoff
|
||||
// NOTE: this check and branching does not always pay off
|
||||
if (ADAPTIVE_ACCESS && is_aligned(_position, sizeof(T)))
|
||||
{
|
||||
*((T*)_position) = value;
|
||||
@@ -738,12 +750,12 @@ private:
|
||||
|
||||
if (UNALIGNED_ACCESS)
|
||||
{
|
||||
// NOTE: some CPU handle unaligned access preety good (e.g. x86)
|
||||
// NOTE: some CPU handle unaligned access pretty good (e.g. x86)
|
||||
*((T*)(_buffer + index)) = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
// NOTE: this check and branching does not always payoff
|
||||
// NOTE: this check and branching does not always pay off
|
||||
if (ADAPTIVE_ACCESS && is_aligned(_position, sizeof(T)))
|
||||
{
|
||||
*((T*)(_buffer + index)) = value;
|
||||
@@ -786,13 +798,13 @@ private:
|
||||
|
||||
if (UNALIGNED_ACCESS)
|
||||
{
|
||||
// NOTE: some CPU handle unaligned access preety good (e.g. x86)
|
||||
// NOTE: some CPU handle unaligned access pretty good (e.g. x86)
|
||||
value = *((T*)_position);
|
||||
_position += sizeof(T);
|
||||
}
|
||||
else
|
||||
{
|
||||
// NOTE: this check and branching does not always payoff
|
||||
// NOTE: this check and branching does not always pay off
|
||||
if (ADAPTIVE_ACCESS && is_aligned(_position, sizeof(T)))
|
||||
{
|
||||
value = *((T*)_position);
|
||||
@@ -838,12 +850,12 @@ private:
|
||||
|
||||
if (UNALIGNED_ACCESS)
|
||||
{
|
||||
// NOTE: some CPU handle unaligned access preety good (e.g. x86)
|
||||
// NOTE: some CPU handle unaligned access pretty good (e.g. x86)
|
||||
value = *((T*)(_buffer + index));
|
||||
}
|
||||
else
|
||||
{
|
||||
// NOTE: this check and branching does not always payoff
|
||||
// NOTE: this check and branching does not always pay off
|
||||
if (ADAPTIVE_ACCESS && is_aligned(_position, sizeof(T)))
|
||||
{
|
||||
value = *((T*)(_buffer + index));
|
||||
@@ -890,7 +902,7 @@ private:
|
||||
memcpy(_position, values, n);
|
||||
_position += n;
|
||||
|
||||
// ... so that we can be fast changing endianess
|
||||
// ... so that we can be fast changing endianness
|
||||
if (ENDIANESS_SUPPORT && reverse<T>())
|
||||
{
|
||||
for (std::size_t i = 0; i < count; i++)
|
||||
@@ -918,7 +930,7 @@ private:
|
||||
memcpy(values, _position, n);
|
||||
_position += n;
|
||||
|
||||
// ... so that we can be fast changing endianess
|
||||
// ... so that we can be fast changing endianness
|
||||
if (ENDIANESS_SUPPORT && reverse<T>())
|
||||
{
|
||||
for (std::size_t i = 0; i < count; i++)
|
||||
0
src/misc/current_function.h → src/misc/pv/current_function.h
Executable file → Normal file
0
src/misc/current_function.h → src/misc/pv/current_function.h
Executable file → Normal file
@@ -1,8 +1,7 @@
|
||||
/* 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.
|
||||
/*
|
||||
* Copyright information and license terms for this software can be
|
||||
* found in the file LICENSE that is included with the distribution
|
||||
*/
|
||||
/**
|
||||
* @author mse
|
||||
@@ -18,7 +17,8 @@ namespace epics { namespace pvData {
|
||||
|
||||
|
||||
/**
|
||||
* Instance declaring destroy method.
|
||||
* @brief Instance declaring destroy method.
|
||||
*
|
||||
* @author mse
|
||||
*/
|
||||
class epicsShareClass Destroyable {
|
||||
@@ -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,7 +175,7 @@ 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)
|
||||
|
||||
@@ -185,7 +185,7 @@ do { \
|
||||
# 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
68
src/misc/pv/event.h
Normal 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 */
|
||||
@@ -1,8 +1,7 @@
|
||||
/* 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.
|
||||
/*
|
||||
* Copyright information and license terms for this software can be
|
||||
* found in the file LICENSE that is included with the distribution
|
||||
*/
|
||||
/**
|
||||
* @author mrk
|
||||
@@ -27,22 +26,56 @@ 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 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 Executor : public Runnable{
|
||||
public:
|
||||
POINTER_DEFINITIONS(Executor);
|
||||
Executor(String threadName,ThreadPriority priority);
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param threadName name for the executor thread.
|
||||
* @param priority The thread priority.
|
||||
*/
|
||||
Executor(std::string const & threadName,ThreadPriority priority);
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
~Executor();
|
||||
void execute(CommandPtr const &node);
|
||||
/**
|
||||
*
|
||||
* 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;
|
||||
@@ -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
|
||||
@@ -1,8 +1,7 @@
|
||||
/* lock.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 mrk
|
||||
@@ -12,21 +11,11 @@
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
#define lockepicsExportSharedSymbols
|
||||
#undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include <epicsMutex.h>
|
||||
|
||||
#ifdef lockepicsExportSharedSymbols
|
||||
#define epicsExportSharedSymbols
|
||||
#undef lockepicsExportSharedSymbols
|
||||
#endif
|
||||
#include <shareLib.h>
|
||||
|
||||
#include <pv/noDefaultMethods.h>
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
/* This is based on item 14 of
|
||||
* Effective C++, Third Edition, Scott Meyers
|
||||
@@ -38,12 +27,30 @@ namespace epics { namespace pvData {
|
||||
|
||||
typedef epicsMutex Mutex;
|
||||
|
||||
/**
|
||||
* @brief A lock for multithreading
|
||||
*
|
||||
* This is based on item 14 of
|
||||
* * Effective C++, Third Edition, Scott Meyers
|
||||
*/
|
||||
class epicsShareClass Lock : private NoDefaultMethods {
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
* @param m The mutex for the facility being locked.
|
||||
*/
|
||||
explicit Lock(Mutex &m)
|
||||
: mutexPtr(m), locked(true)
|
||||
{ mutexPtr.lock();}
|
||||
/**
|
||||
* Destructor
|
||||
* Note that destructor does an automatic unlock.
|
||||
*/
|
||||
~Lock(){unlock();}
|
||||
/**
|
||||
* Take the lock
|
||||
* Recursive locks are supported but each lock must be matched with an unlock.
|
||||
*/
|
||||
void lock()
|
||||
{
|
||||
if(!locked)
|
||||
@@ -52,6 +59,9 @@ public:
|
||||
locked = true;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* release the lock.
|
||||
*/
|
||||
void unlock()
|
||||
{
|
||||
if(locked)
|
||||
@@ -60,6 +70,10 @@ public:
|
||||
locked=false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* If lock is not held take the lock.
|
||||
* @return (false,true) if caller (does not have, has) the lock.
|
||||
*/
|
||||
bool tryLock()
|
||||
{
|
||||
if(locked) return true;
|
||||
@@ -69,6 +83,10 @@ public:
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* See if caller has the lock,
|
||||
* @return (false,true) if caller (does not have, has) the lock.
|
||||
*/
|
||||
bool ownsLock() const{return locked;}
|
||||
private:
|
||||
Mutex &mutexPtr;
|
||||
128
src/misc/pv/messageQueue.h
Normal file
128
src/misc/pv/messageQueue.h
Normal file
@@ -0,0 +1,128 @@
|
||||
/* messageQueue.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 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;
|
||||
|
||||
/**
|
||||
* @brief A node that can be put on a MessageQueue.
|
||||
*
|
||||
*/
|
||||
class epicsShareClass MessageNode {
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
MessageNode();
|
||||
/**
|
||||
*
|
||||
* Get the message value.
|
||||
* @return The message value.
|
||||
*/
|
||||
std::string getMessage() const;
|
||||
/**
|
||||
* Get the message type.
|
||||
* @return The message type which is defined in Requester.
|
||||
*/
|
||||
MessageType getMessageType() const;
|
||||
private:
|
||||
std::string message;
|
||||
MessageType messageType;
|
||||
friend class MessageQueue;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A bounded queue for messages.
|
||||
*
|
||||
*
|
||||
*/
|
||||
class epicsShareClass MessageQueue : public Queue<MessageNode> {
|
||||
public:
|
||||
POINTER_DEFINITIONS(MessageQueue);
|
||||
/**
|
||||
* Factory method to create a MessageQueue.
|
||||
* @param size The number of MessageNodes in the queue.
|
||||
* @return shared_ptr to MessageQueue.
|
||||
*/
|
||||
static MessageQueuePtr create(int size);
|
||||
/**
|
||||
* Constructor
|
||||
* @param nodeArray an array of shared_ptr to MessageNodes,
|
||||
*/
|
||||
MessageQueue(MessageNodePtrArray &nodeArray);
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~MessageQueue();
|
||||
/**
|
||||
* get the next MessageNode of the queue.
|
||||
* @return A shared_ptr to the MessageNode.
|
||||
* This will be a null pointer if queue is empty.
|
||||
* If get is successful then release for this MessageNode
|
||||
* must be called before another get can be issued.
|
||||
*/
|
||||
MessageNodePtr &get();
|
||||
/**
|
||||
* Release the MessageNode that was returned by the previous call to get.
|
||||
*/
|
||||
void release();
|
||||
/**
|
||||
*
|
||||
* put a message into the message queue
|
||||
* @param message The message string.
|
||||
* @param messageType The message type as defined in Requester,
|
||||
* @param replaceLast If true and queue is full then replace.
|
||||
* @return (false,true) if a message (was not, was) put in queiue.
|
||||
*/
|
||||
bool put(std::string message,MessageType messageType,bool replaceLast);
|
||||
/**
|
||||
* Is queue empty?
|
||||
* @return (false,true) if (is not, is) empty.
|
||||
*/
|
||||
bool isEmpty() ;
|
||||
/**
|
||||
* Is queue full?
|
||||
* @return (false,true) if (is not, is) full.
|
||||
*/
|
||||
bool isFull() ;
|
||||
/**
|
||||
*
|
||||
* Clear number of times queue was overrun and return the number
|
||||
* of times the queue was overrun.
|
||||
*/
|
||||
int getClearOverrun();
|
||||
private:
|
||||
MessageNodePtr nullNode;
|
||||
MessageNodePtr lastGet;
|
||||
MessageNodePtr lastPut;
|
||||
uint32 overrun;
|
||||
};
|
||||
|
||||
}}
|
||||
#endif /* MESSAGEQUEUE_H */
|
||||
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
/* 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.
|
||||
/*
|
||||
* Copyright information and license terms for this software can be
|
||||
* found in the file LICENSE that is included with the distribution
|
||||
*/
|
||||
/**
|
||||
* @author mrk
|
||||
@@ -17,17 +16,26 @@ namespace epics { namespace pvData {
|
||||
* Effective C++, Third Edition, Scott Meyers
|
||||
*/
|
||||
|
||||
|
||||
class epicsShareClass NoDefaultMethods {
|
||||
protected:
|
||||
// allow by derived objects
|
||||
/**
|
||||
* @brief Base class for not allowing default methods.
|
||||
*
|
||||
* Note that copy constructor a copy methods are declared private.
|
||||
*/
|
||||
class epicsShareClass NoDefaultMethods {
|
||||
protected:
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
NoDefaultMethods(){};
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
~NoDefaultMethods(){}
|
||||
private:
|
||||
// do not implment
|
||||
// do not implement
|
||||
NoDefaultMethods(const NoDefaultMethods&);
|
||||
NoDefaultMethods & operator=(const NoDefaultMethods &);
|
||||
};
|
||||
};
|
||||
|
||||
}}
|
||||
#endif /* NO_DEFAULT_METHODS_H */
|
||||
@@ -1,8 +1,7 @@
|
||||
/* queue.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 mrk
|
||||
@@ -18,6 +17,12 @@
|
||||
|
||||
namespace epics { namespace pvData {
|
||||
|
||||
/**
|
||||
* @brief Template class for a bounded queue.
|
||||
*
|
||||
* An instance can make a queueElement be any class desired
|
||||
* but must create a std::vector of shared_ptr to queueElements.
|
||||
*/
|
||||
template <typename T>
|
||||
class Queue
|
||||
{
|
||||
@@ -25,15 +30,58 @@ public:
|
||||
POINTER_DEFINITIONS(Queue);
|
||||
typedef std::tr1::shared_ptr<T> queueElementPtr;
|
||||
typedef std::vector<queueElementPtr> queueElementPtrArray;
|
||||
Queue(queueElementPtrArray &);
|
||||
/**
|
||||
* Constructor
|
||||
* @param elementArray The vector of shared_ptr to queue elements.
|
||||
*/
|
||||
Queue(queueElementPtrArray & elementArray);
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~Queue();
|
||||
/**
|
||||
* Clear the queue.
|
||||
*/
|
||||
void clear();
|
||||
/**
|
||||
* get the capacity of the queue, i. e. number of queue elements,
|
||||
* @return The capacity.
|
||||
*/
|
||||
int capacity();
|
||||
/**
|
||||
* Get the number of free elements in the queue.
|
||||
* @return The number.
|
||||
*/
|
||||
int getNumberFree();
|
||||
/**
|
||||
* Get the number of used elements in the queue.
|
||||
* This is the number that have been setUsed but not released.
|
||||
* @return The number.
|
||||
*/
|
||||
int getNumberUsed();
|
||||
/**
|
||||
* Get the next free element.
|
||||
* @return a shared_ptr to the queue element.
|
||||
* This is null if queue was full.
|
||||
*/
|
||||
queueElementPtr & getFree();
|
||||
/**
|
||||
* Set the element returned by getFree as used.
|
||||
* Until this is called getUsed will not return it.
|
||||
* @param element The element. It must be the element returned
|
||||
* by the most recent call to getUsed.
|
||||
*/
|
||||
void setUsed(queueElementPtr const &element);
|
||||
/**
|
||||
* Get the oldest used element;
|
||||
* @return a shared_ptr to the queue element.
|
||||
* This is null if no used element is available.`
|
||||
*/
|
||||
queueElementPtr & getUsed();
|
||||
/**
|
||||
* Release the element obtained by the most recent call to getUsed.
|
||||
* @param element The element.
|
||||
*/
|
||||
void releaseUsed(queueElementPtr const &element);
|
||||
private:
|
||||
queueElementPtr nullElement;
|
||||
71
src/misc/pv/requester.h
Normal file
71
src/misc/pv/requester.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/* requester.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 REQUESTER_H
|
||||
#define REQUESTER_H
|
||||
#include <string>
|
||||
|
||||
#include <pv/pvType.h>
|
||||
#include <pv/sharedPtr.h>
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
namespace epics { namespace pvData {
|
||||
|
||||
class Requester;
|
||||
typedef std::tr1::shared_ptr<Requester> RequesterPtr;
|
||||
|
||||
enum MessageType {
|
||||
infoMessage,warningMessage,errorMessage,fatalErrorMessage
|
||||
};
|
||||
#define MESSAGE_TYPE_COUNT 4
|
||||
|
||||
epicsShareExtern std::string getMessageTypeName(MessageType messageType);
|
||||
|
||||
/**
|
||||
* @brief Callback class for passing messages to a requester.
|
||||
*
|
||||
* This is used by many other classes and also extended by other classes.
|
||||
* The request is passed a message and a messageType.
|
||||
* A message is just a string and a messageType is:
|
||||
@code
|
||||
enum MessageType {
|
||||
infoMessage,warningMessage,errorMessage,fatalErrorMessage
|
||||
};
|
||||
@endcode
|
||||
*
|
||||
*/
|
||||
|
||||
class epicsShareClass Requester {
|
||||
public:
|
||||
POINTER_DEFINITIONS(Requester);
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~Requester(){}
|
||||
/**
|
||||
* The requester must have a name.
|
||||
* @return The requester's name.
|
||||
*/
|
||||
virtual std::string getRequesterName() = 0;
|
||||
/**
|
||||
*
|
||||
* A message for the requester.
|
||||
* @param message The message.
|
||||
* @param messageType The type of message:
|
||||
@code
|
||||
enum MessageType {
|
||||
infoMessage,warningMessage,errorMessage,fatalErrorMessage
|
||||
};
|
||||
@endcode
|
||||
*/
|
||||
virtual void message(std::string const & message,MessageType messageType);
|
||||
};
|
||||
|
||||
}}
|
||||
#endif /* REQUESTER_H */
|
||||
253
src/misc/pv/serialize.h
Normal file
253
src/misc/pv/serialize.h
Normal file
@@ -0,0 +1,253 @@
|
||||
/* serialize.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 SERIALIZE_H
|
||||
#define SERIALIZE_H
|
||||
|
||||
#include <epicsTypes.h>
|
||||
|
||||
#include <pv/byteBuffer.h>
|
||||
#include <pv/sharedPtr.h>
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
namespace epics { namespace pvData {
|
||||
|
||||
class SerializableControl;
|
||||
class DeserializableControl;
|
||||
class Serializable;
|
||||
class BitSetSerializable;
|
||||
class SerializableArray;
|
||||
class BitSet;
|
||||
class Field;
|
||||
|
||||
/**
|
||||
* @brief Callback class for serialization.
|
||||
*
|
||||
* This must be provided by code that calls serialize.
|
||||
*/
|
||||
class epicsShareClass SerializableControl {
|
||||
public:
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~SerializableControl(){}
|
||||
/**
|
||||
* Done with this buffer. Flush it.
|
||||
*/
|
||||
virtual void flushSerializeBuffer() =0;
|
||||
/**
|
||||
* Make sure buffer has at least size bytes remaining.
|
||||
* If not flush existing buffer and provide a new one.
|
||||
* @param size The number of bytes.
|
||||
*/
|
||||
virtual void ensureBuffer(std::size_t size) =0;
|
||||
/**
|
||||
* Add pad bytes to buffer.
|
||||
* @param alignment alignment required.
|
||||
*/
|
||||
virtual void alignBuffer(std::size_t alignment) =0;
|
||||
/**
|
||||
* Method for serializing primitive array data.
|
||||
* Hook for supplying custom serialization implementation.
|
||||
* The serialization implementation need not be provided.
|
||||
* Returns true if method performs serialization, false otherwise.
|
||||
* This should only be used for arrays of primitive types,
|
||||
* i. e. boolean, byte,..., double.
|
||||
* It cannot be called for string, structure, or union arrays.
|
||||
* @param existingBuffer the existing buffer from the caller.
|
||||
* @param toSerialize location of data to be put into buffer.
|
||||
* @param elementCount number of elements.
|
||||
* @param elementSize element size.
|
||||
* @returns true if serialization performed, else false.
|
||||
*/
|
||||
virtual bool directSerialize(
|
||||
ByteBuffer *existingBuffer,
|
||||
const char* toSerialize,
|
||||
std::size_t elementCount,
|
||||
std::size_t elementSize) = 0;
|
||||
/**
|
||||
* serialize via cache
|
||||
* @param field instance to be serialized
|
||||
* @param buffer buffer to be serialized to
|
||||
*/
|
||||
virtual void cachedSerialize(
|
||||
std::tr1::shared_ptr<const Field> const & field,
|
||||
ByteBuffer* buffer) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Callback class for deserialization.
|
||||
*
|
||||
* This must be provided by code that calls deserialize.
|
||||
*/
|
||||
class epicsShareClass DeserializableControl {
|
||||
public:
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~DeserializableControl(){}
|
||||
/**
|
||||
* Helper method.
|
||||
* Ensures specified size of bytes, provides it if necessary.
|
||||
* @param size The number of bytes.
|
||||
*/
|
||||
virtual void ensureData(std::size_t size) =0;
|
||||
/**
|
||||
* Align buffer.
|
||||
* Note that this takes care only current buffer alignment.
|
||||
* If streaming protocol is used,
|
||||
* care must be taken that entire stream is aligned.
|
||||
* @param alignment size in bytes, must be power of two.
|
||||
*/
|
||||
virtual void alignData(std::size_t alignment) =0;
|
||||
/**
|
||||
* Method for deserializing array data.
|
||||
* Hook for supplying custom deserialization implementation.
|
||||
* The deserialization implementation need not be provided.
|
||||
* Returns true if method performs deserialization, false otherwise.
|
||||
* This should only be used for arrays of primitive types.
|
||||
* i.e. boolean, byte,..., double.
|
||||
* It cannot be called for string, structure, or union arrays.
|
||||
* @param existingBuffer the existing buffer from the caller.
|
||||
* @param deserializeTo location of data.
|
||||
* @param elementCount number of elements.
|
||||
* @param elementSize element size.
|
||||
* @returns true if deserialization performed, else false.
|
||||
*/
|
||||
virtual bool directDeserialize(
|
||||
ByteBuffer *existingBuffer,
|
||||
char* deserializeTo,
|
||||
std::size_t elementCount,
|
||||
std::size_t elementSize) = 0;
|
||||
/**
|
||||
* deserialize via cache
|
||||
* @param buffer buffer to be deserialized from
|
||||
*/
|
||||
virtual std::tr1::shared_ptr<const Field> cachedDeserialize(
|
||||
ByteBuffer* buffer) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Base class for serialization.
|
||||
*
|
||||
*/
|
||||
class epicsShareClass Serializable {
|
||||
public:
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~Serializable(){}
|
||||
/**
|
||||
* Serialize field into given buffer.
|
||||
* @param buffer serialization buffer.
|
||||
* @param flusher flush interface.
|
||||
*/
|
||||
virtual void serialize(ByteBuffer *buffer,
|
||||
SerializableControl *flusher) const = 0;
|
||||
/**
|
||||
* Deserialize buffer.
|
||||
* @param buffer serialization buffer.
|
||||
* @param flusher deserialization control.
|
||||
*/
|
||||
virtual void deserialize(ByteBuffer *buffer,
|
||||
DeserializableControl *flusher) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Push serialize and append to the provided byte vector.
|
||||
* No caching is done. Only complete serialization.
|
||||
*
|
||||
* @param S A Serializable object
|
||||
* @param byteOrder Byte order to write (EPICS_ENDIAN_LITTLE or EPICS_ENDIAN_BIG)
|
||||
* @param out The output vector. Results are appended
|
||||
*/
|
||||
void epicsShareFunc serializeToVector(const Serializable *S,
|
||||
int byteOrder,
|
||||
std::vector<epicsUInt8>& out);
|
||||
|
||||
/**
|
||||
* @brief deserializeFromBuffer Deserialize into S from provided vector
|
||||
* @param S A Serializeable object. The current contents will be replaced
|
||||
* @param in The input buffer (byte order of this buffer is used)
|
||||
* @throws std::logic_error if input buffer is too small. State of S is then undefined.
|
||||
*/
|
||||
void epicsShareFunc deserializeFromBuffer(Serializable *S,
|
||||
ByteBuffer& in);
|
||||
|
||||
/**
|
||||
* @brief deserializeFromBuffer Deserialize into S from provided vector
|
||||
* @param S A Serializeable object. The current contents will be replaced
|
||||
* @param byteOrder Byte order to write (EPICS_ENDIAN_LITTLE or EPICS_ENDIAN_BIG)
|
||||
* @param in The input vector
|
||||
* @throws std::logic_error if input buffer is too small. State of S is then undefined.
|
||||
*/
|
||||
inline void deserializeFromVector(Serializable *S,
|
||||
int byteOrder,
|
||||
const std::vector<epicsUInt8>& in)
|
||||
{
|
||||
ByteBuffer B((char*)&in[0], in.size(), byteOrder); // we promise not the modify 'in'
|
||||
deserializeFromBuffer(S, B);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Class for serializing bitSets.
|
||||
*
|
||||
*/
|
||||
class epicsShareClass BitSetSerializable {
|
||||
public:
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~BitSetSerializable(){}
|
||||
/**
|
||||
* Serialize field into given buffer.
|
||||
* @param buffer serialization buffer.
|
||||
* @param flusher flush interface.
|
||||
* @param bitSet The bitSet to serialize.
|
||||
*/
|
||||
virtual void serialize(ByteBuffer *buffer,
|
||||
SerializableControl *flusher,BitSet *bitSet) const = 0;
|
||||
/**
|
||||
* Deserialize buffer.
|
||||
* @param buffer serialization buffer.
|
||||
* @param flusher deserialization control.
|
||||
* @param bitSet The bitSet to deserialize.
|
||||
*/
|
||||
virtual void deserialize(ByteBuffer *buffer,
|
||||
DeserializableControl *flusher,BitSet *bitSet) = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Class for serializing arrays.
|
||||
*
|
||||
*/
|
||||
class epicsShareClass SerializableArray : public virtual Serializable {
|
||||
public:
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~SerializableArray(){}
|
||||
using Serializable::serialize;
|
||||
/**
|
||||
* Serialize field into given buffer.
|
||||
* @param buffer serialization buffer.
|
||||
* @param flusher flush interface.
|
||||
* @param offset offset in elements.
|
||||
* @param count number of elements
|
||||
*/
|
||||
virtual void serialize(
|
||||
ByteBuffer *buffer,
|
||||
SerializableControl *flusher,
|
||||
std::size_t offset,
|
||||
std::size_t count) const = 0;
|
||||
};
|
||||
|
||||
}}
|
||||
#endif /* SERIALIZE_H */
|
||||
@@ -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
|
||||
*/
|
||||
/*
|
||||
* serializeHelper.h
|
||||
@@ -23,53 +22,63 @@
|
||||
namespace epics {
|
||||
namespace pvData {
|
||||
|
||||
/**
|
||||
* @brief Serialization helper.
|
||||
*
|
||||
*/
|
||||
class epicsShareClass SerializeHelper : public NoDefaultMethods {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Serialize array size.
|
||||
* Serialize the specified array size into the specified
|
||||
* buffer, flushing when necessary.
|
||||
* The specified SerializableControl manages any flushing
|
||||
* required.
|
||||
*
|
||||
* @param[in] s size to encode
|
||||
* @param[in] buffer serialization buffer
|
||||
* @param[in] flusher flusher
|
||||
* @param[in] flusher SerializableControl to manage the flushing
|
||||
*/
|
||||
static void writeSize(std::size_t s, ByteBuffer* buffer,
|
||||
SerializableControl* flusher);
|
||||
|
||||
/**
|
||||
* Deserialize array size.
|
||||
* The specified DeserializableControl ensures
|
||||
* sufficient bytes are available.
|
||||
*
|
||||
* @param[in] buffer deserialization buffer.
|
||||
* @param[in] control the DeserializableControl.
|
||||
* @returns array size.
|
||||
*/
|
||||
static std::size_t readSize(ByteBuffer* buffer,
|
||||
DeserializableControl* control);
|
||||
|
||||
/**
|
||||
* String serialization helper method.
|
||||
* std::string serialization helper method.
|
||||
*
|
||||
* @param[in] value String to serialize
|
||||
* @param[in] value std::string to serialize
|
||||
* @param[in] buffer serialization buffer
|
||||
* @param[in] flusher flusher
|
||||
*/
|
||||
static void serializeString(const String& value, ByteBuffer* buffer,
|
||||
static void serializeString(const std::string& value, ByteBuffer* buffer,
|
||||
SerializableControl* flusher);
|
||||
|
||||
/**
|
||||
* String serialization helper method.
|
||||
* std::string serialization helper method.
|
||||
*
|
||||
* @param[in] value String to serialize
|
||||
* @param[in] offset start of the substring in {@code value}
|
||||
* @param[in] value std::string to serialize
|
||||
* @param[in] offset start of the substring in value
|
||||
* @param[in] count the number of characters to write
|
||||
* @param[in] buffer serialization buffer
|
||||
* @param[in] flusher flusher
|
||||
*/
|
||||
static void serializeSubstring(const String& value, std::size_t offset,
|
||||
static void serializeSubstring(const std::string& value, std::size_t offset,
|
||||
std::size_t count, ByteBuffer* buffer,
|
||||
SerializableControl* flusher);
|
||||
|
||||
/**
|
||||
* String deserialization helper method.
|
||||
* std::string deserialization helper method.
|
||||
* TODO This method cannot return "null", but Java implementation
|
||||
* could have serialized "null" value as well. We need to decide
|
||||
* how to deserialize "null".
|
||||
@@ -82,7 +91,7 @@ namespace epics {
|
||||
* could have serialized "null" value as well. We need to decide
|
||||
* how to deserialize "null".
|
||||
*/
|
||||
static String deserializeString(ByteBuffer* buffer,
|
||||
static std::string deserializeString(ByteBuffer* buffer,
|
||||
DeserializableControl* control);
|
||||
|
||||
private:
|
||||
@@ -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 Michael Davidsaver
|
||||
@@ -26,7 +25,7 @@
|
||||
|
||||
// where should we look?
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__>=4 && !defined(__vxworks)
|
||||
#if defined(__GNUC__) && __GNUC__>=4 && !defined(vxWorks)
|
||||
// GCC >=4.0.0
|
||||
# define SHARED_FROM_TR1
|
||||
|
||||
@@ -44,6 +43,25 @@
|
||||
# undef SHARED_FROM_TR1
|
||||
#endif
|
||||
|
||||
#if defined(__clang__)
|
||||
# undef SHARED_FROM_BOOST
|
||||
# undef SHARED_FROM_TR1
|
||||
|
||||
#include <memory>
|
||||
|
||||
// import std classes into std::tr1
|
||||
namespace std {
|
||||
namespace tr1 {
|
||||
using std::shared_ptr;
|
||||
using std::weak_ptr;
|
||||
using std::static_pointer_cast;
|
||||
using std::dynamic_pointer_cast;
|
||||
using std::const_pointer_cast;
|
||||
using std::enable_shared_from_this;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// go and get it
|
||||
|
||||
#if defined(SHARED_FROM_TR1)
|
||||
@@ -1,13 +1,12 @@
|
||||
/* sharedVector.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
|
||||
*/
|
||||
#ifndef SHAREDVECTOR_H
|
||||
#define SHAREDVECTOR_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#if defined(_WIN32) && !defined(NOMINMAX)
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
|
||||
@@ -230,7 +229,7 @@ namespace detail {
|
||||
};
|
||||
}
|
||||
|
||||
/** @brief A holder for a contigious piece of memory.
|
||||
/** @brief A holder for a contiguous piece of memory.
|
||||
*
|
||||
* Data is shared, but offset and length are not.
|
||||
* This allows one vector to have access to only a
|
||||
@@ -326,7 +325,7 @@ public:
|
||||
//! Internal for static_shared_vector_cast
|
||||
template<typename FROM>
|
||||
shared_vector(const shared_vector<FROM> &src,
|
||||
typename meta::is_void<FROM, detail::_shared_vector_cast_tag>::type)
|
||||
detail::_shared_vector_cast_tag)
|
||||
:base_t(std::tr1::static_pointer_cast<E>(src.dataPtr()),
|
||||
src.dataOffset()/sizeof(E),
|
||||
src.dataCount()/sizeof(E))
|
||||
@@ -427,13 +426,13 @@ public:
|
||||
* owner of the data array.
|
||||
*
|
||||
* If a copy is needed, memory is allocated with new[]. If this is
|
||||
* not desireable then do something like the following.
|
||||
* not desirable then do something like the following.
|
||||
@code
|
||||
shared_vector<E> original(...);
|
||||
|
||||
if(!original.unique()){
|
||||
shared_vector<E> temp(myallocator(original.size()),
|
||||
0, original.size());
|
||||
std::tr1::shared_ptr<E> sptr(myalloc(original.size()), myfree);
|
||||
shared_vector<E> temp(sptr, 0, original.size());
|
||||
std::copy(original.begin(), original.end(), temp.begin());
|
||||
original.swap(temp);
|
||||
}
|
||||
@@ -527,16 +526,37 @@ public:
|
||||
|
||||
};
|
||||
|
||||
//! Specialization for storing untyped pointers
|
||||
//! Does not allow access or iteration of contents
|
||||
//! other than as void* or const void*
|
||||
/**
|
||||
* @brief Specialization for storing untyped pointers.
|
||||
*
|
||||
* Does not allow access or iteration of contents
|
||||
* other than as void* or const void*
|
||||
*
|
||||
* In order to support shared_vector_convert<>()
|
||||
* information about the type of the underlying allocation
|
||||
* is stored.
|
||||
* This is implicitly set by static_shared_vector_cast<>()
|
||||
* and may be explicitly checked/changed using
|
||||
* original_type()/set_original_type().
|
||||
*
|
||||
* A shared_vector<void> directly constructed
|
||||
* from a smart pointer does not have an associated
|
||||
* original_type().
|
||||
* Use epics::pvData::ScalarTypeFunc::allocArray()
|
||||
* to convienently allocate an array with a known
|
||||
* original_type().
|
||||
*/
|
||||
template<typename E>
|
||||
class shared_vector<E, typename meta::is_void<E>::type >
|
||||
: public detail::shared_vector_base<E>
|
||||
{
|
||||
typedef detail::shared_vector_base<E> base_t;
|
||||
ScalarType m_vtype;
|
||||
|
||||
// allow specialization for all E to be friends
|
||||
template<typename E1, class Enable1> friend class shared_vector;
|
||||
public:
|
||||
typedef E value_type;
|
||||
typedef E* pointer;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef size_t size_type;
|
||||
@@ -563,7 +583,7 @@ public:
|
||||
//! Internal for static_shared_vector_cast
|
||||
template<typename FROM>
|
||||
shared_vector(const shared_vector<FROM> &src,
|
||||
typename meta::is_not_void<FROM, detail::_shared_vector_cast_tag>::type)
|
||||
detail::_shared_vector_cast_tag)
|
||||
:base_t(std::tr1::static_pointer_cast<E>(src.dataPtr()),
|
||||
src.dataOffset()*sizeof(FROM),
|
||||
src.dataCount()*sizeof(FROM))
|
||||
@@ -572,12 +592,12 @@ public:
|
||||
|
||||
shared_vector(shared_vector<void>& O,
|
||||
detail::_shared_vector_freeze_tag t)
|
||||
:base_t(O,t)
|
||||
:base_t(O,t), m_vtype(O.m_vtype)
|
||||
{}
|
||||
|
||||
shared_vector(shared_vector<const void>& O,
|
||||
detail::_shared_vector_thaw_tag t)
|
||||
:base_t(O,t)
|
||||
:base_t(O,t), m_vtype(O.m_vtype)
|
||||
{}
|
||||
|
||||
shared_vector& operator=(const shared_vector& o)
|
||||
@@ -599,6 +619,64 @@ public:
|
||||
ScalarType original_type() const {return m_vtype;}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
template<typename TO, typename FROM, class Enable = void>
|
||||
struct static_shared_vector_caster { /* no default */ };
|
||||
// from void to non-void with same const-ness
|
||||
template<typename TO>
|
||||
struct static_shared_vector_caster<TO, void,
|
||||
typename meta::_and<meta::same_const<TO,void>, meta::is_not_void<TO> >::type> {
|
||||
static inline shared_vector<TO> op(const shared_vector<void>& src) {
|
||||
return shared_vector<TO>(src, detail::_shared_vector_cast_tag());
|
||||
}
|
||||
};
|
||||
template<typename TO>
|
||||
struct static_shared_vector_caster<TO, const void,
|
||||
typename meta::_and<meta::same_const<TO,const void>, meta::is_not_void<TO> >::type> {
|
||||
static inline shared_vector<TO> op(const shared_vector<const void>& src) {
|
||||
return shared_vector<TO>(src, detail::_shared_vector_cast_tag());
|
||||
}
|
||||
};
|
||||
// from non-void to void with same const-ness
|
||||
template<typename FROM>
|
||||
struct static_shared_vector_caster<void, FROM,
|
||||
typename meta::_and<meta::same_const<void,FROM>, meta::is_not_void<FROM> >::type> {
|
||||
static FORCE_INLINE shared_vector<void> op(const shared_vector<FROM>& src) {
|
||||
return shared_vector<void>(src, detail::_shared_vector_cast_tag());
|
||||
}
|
||||
};
|
||||
template<typename FROM>
|
||||
struct static_shared_vector_caster<const void, FROM,
|
||||
typename meta::_and<meta::same_const<const void,FROM>, meta::is_not_void<FROM> >::type> {
|
||||
static FORCE_INLINE shared_vector<const void> op(const shared_vector<FROM>& src) {
|
||||
return shared_vector<const void>(src, detail::_shared_vector_cast_tag());
|
||||
}
|
||||
};
|
||||
|
||||
// cast to same type, no-op
|
||||
template<typename TOFRO>
|
||||
struct static_shared_vector_caster<TOFRO,TOFRO,void> {
|
||||
static FORCE_INLINE const shared_vector<TOFRO>& op(const shared_vector<TOFRO>& src) {
|
||||
return src;
|
||||
}
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
/** @brief Allow casting of shared_vector between types
|
||||
*
|
||||
* Currently only to/from void is implemented.
|
||||
*
|
||||
@warning Casting from void is undefined unless the offset and length
|
||||
* are integer multiples of the size of the destination type.
|
||||
*/
|
||||
template<typename TO, typename FROM>
|
||||
static FORCE_INLINE
|
||||
shared_vector<TO>
|
||||
static_shared_vector_cast(const shared_vector<FROM>& src)
|
||||
{
|
||||
return detail::static_shared_vector_caster<TO,FROM>::op(src);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
// Default to type conversion using castUnsafe (C++ type casting) on each element
|
||||
@@ -631,7 +709,7 @@ namespace detail {
|
||||
return shared_vector<TO>(src, detail::_shared_vector_cast_tag());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// convert from void uses original type or throws an exception.
|
||||
template<typename TO, typename FROM>
|
||||
struct shared_vector_converter<TO,FROM,
|
||||
@@ -659,30 +737,16 @@ namespace detail {
|
||||
};
|
||||
}
|
||||
|
||||
/** @brief Allow casting of shared_vector between types
|
||||
*
|
||||
* Currently only to/from void is implemented.
|
||||
*
|
||||
@warning Casting from void is undefined unless the offset and length
|
||||
* are integer multiples of the size of the destination type.
|
||||
*/
|
||||
template<typename TO, typename FROM>
|
||||
static FORCE_INLINE
|
||||
shared_vector<TO>
|
||||
static_shared_vector_cast(const shared_vector<FROM>& src,
|
||||
typename meta::same_const<TO,FROM,int>::type = 0)
|
||||
{
|
||||
return shared_vector<TO>(src, detail::_shared_vector_cast_tag());
|
||||
}
|
||||
|
||||
/** @brief Allow converting of shared_vector between types
|
||||
*
|
||||
* Conversion utilizes castUnsafe<TO,FROM>().
|
||||
*
|
||||
* Converting to/from void is supported. Convert to void
|
||||
* is an alias for static_shared_vector_cast<void>().
|
||||
* Convert from void utilizes shared_vector<void>::original_type()
|
||||
* and throws std::runtime_error if this is not valid.
|
||||
* Convert from void utilizes shared_vector<void>::original_type().
|
||||
*
|
||||
* @throws std::runtime_error if cast is not valid.
|
||||
* @throws std::bad_alloc for out of memory condition
|
||||
*/
|
||||
template<typename TO, typename FROM>
|
||||
static FORCE_INLINE
|
||||
@@ -858,10 +922,13 @@ std::ostream& operator<<(std::ostream& strm, const epics::pvData::shared_vector<
|
||||
* shared_vector has additional constructors from raw pointers
|
||||
* and shared_ptr s.
|
||||
*
|
||||
* The copy constructor and assignment operator allow implicit
|
||||
* casting from type 'shared_vector<T>' to 'shared_vector<const T>'.
|
||||
* Implicit casting is not allowed. Instead use
|
||||
* const_shared_vector_cast()/freeze()/thaw() (@ref vectorconst)
|
||||
* to casting between 'T' and 'const T'.
|
||||
* Use static_shared_vector_cast() to cast between
|
||||
* void and non-void (same const-ness).
|
||||
*
|
||||
* To faciliate safe modification the methods unique() and
|
||||
* To facilitate safe modification the methods unique() and
|
||||
* make_unique() are provided.
|
||||
*
|
||||
* The slice() method selects a sub-set of the shared_vector.
|
||||
@@ -961,17 +1028,15 @@ Type #2 is constant reference to a mutable value.
|
||||
Type #3 is a mutable reference to a constant value.
|
||||
Type #4 is a constant reference to a constant value.
|
||||
|
||||
Casting between const and non-const references of the same value type
|
||||
is governed by the normal C++ casting rules.
|
||||
|
||||
Casting between const and non-const values does @b not follow the normal
|
||||
C++ casting rules.
|
||||
C++ casting rules (no implicit cast).
|
||||
|
||||
For casting between shared_vector<T> and shared_vector<const T>
|
||||
explicit casting operations are required. These operations are
|
||||
@b freeze() (non-const to const) and @b thaw() (const to non-const).
|
||||
|
||||
A shared_vector<const T> is "frozen" as its value can not be modified.
|
||||
A 'shared_vector<const T>' is "frozen" as its value can not be modified.
|
||||
However it can still be sliced because the reference is not const.
|
||||
|
||||
These functions are defined like:
|
||||
|
||||
@@ -995,17 +1060,18 @@ The following guarantees are provided by both functions:
|
||||
# The returned reference points to a value which is only referenced by
|
||||
shared_vectors with the same value const-ness as the returned reference.
|
||||
|
||||
Please note that the argument of both freeze and thaw is a non-const
|
||||
@note The argument of both freeze() and thaw() is a non-const
|
||||
reference which will always be cleared.
|
||||
|
||||
@section vfreeze Freezing
|
||||
|
||||
The act of freezing a shared_vector requires that the shared_vector
|
||||
passed in must be unique() or an exception is thrown. This is
|
||||
done to reduce the possibility of accidental copying.
|
||||
passed in must be unique() or an exception is thrown.
|
||||
No copy is made.
|
||||
|
||||
This possibility can be avoided by calling the make_unique() on a
|
||||
The possibility of an exception can be avoided by calling the make_unique() on a
|
||||
shared_vector before passing it to freeze().
|
||||
This will make a copy if necessary.
|
||||
|
||||
@section vthaw Thawing
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
/* status.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,6 +9,8 @@
|
||||
#ifndef STATUS_H
|
||||
#define STATUS_H
|
||||
|
||||
#include <ostream>
|
||||
|
||||
#include <pv/serialize.h>
|
||||
#include <pv/byteBuffer.h>
|
||||
#include <pv/sharedPtr.h>
|
||||
@@ -19,7 +20,9 @@
|
||||
namespace epics { namespace pvData {
|
||||
|
||||
/**
|
||||
* Status.
|
||||
* @brief Status.
|
||||
*
|
||||
* This is a class for returning status to clients.
|
||||
* @author mse
|
||||
*/
|
||||
class epicsShareClass Status : public epics::pvData::Serializable {
|
||||
@@ -51,12 +54,12 @@ namespace epics { namespace pvData {
|
||||
/**
|
||||
* Create non-OK status.
|
||||
*/
|
||||
Status(StatusType type, epics::pvData::String const & message);
|
||||
Status(StatusType type, std::string const & message);
|
||||
|
||||
/**
|
||||
* Create non-OK status.
|
||||
*/
|
||||
Status(StatusType type, epics::pvData::String const & message, epics::pvData::String const & stackDump);
|
||||
Status(StatusType type, std::string const & message, std::string const & stackDump);
|
||||
|
||||
~Status();
|
||||
|
||||
@@ -70,13 +73,13 @@ namespace epics { namespace pvData {
|
||||
* Get error message describing an error. Required if error status.
|
||||
* @return error message.
|
||||
*/
|
||||
epics::pvData::String getMessage() const;
|
||||
std::string getMessage() const;
|
||||
|
||||
/**
|
||||
* Get stack dump where error (exception) happened. Optional.
|
||||
* @return stack dump.
|
||||
*/
|
||||
epics::pvData::String getStackDump() const;
|
||||
std::string getStackDump() const;
|
||||
|
||||
/**
|
||||
* Convenient OK test. Same as <code>(getType() == StatusType.OK)</code>.
|
||||
@@ -93,20 +96,21 @@ namespace epics { namespace pvData {
|
||||
*/
|
||||
bool isSuccess() const;
|
||||
|
||||
String toString() const;
|
||||
void toString(StringBuilder buffer, int indentLevel = 0) const;
|
||||
|
||||
void serialize(ByteBuffer *buffer, SerializableControl *flusher) const;
|
||||
void deserialize(ByteBuffer *buffer, DeserializableControl *flusher);
|
||||
|
||||
void dump(std::ostream& o) const;
|
||||
|
||||
private:
|
||||
|
||||
static epics::pvData::String m_emptyString;
|
||||
|
||||
|
||||
StatusType m_statusType;
|
||||
String m_message;
|
||||
String m_stackDump;
|
||||
std::string m_message;
|
||||
std::string m_stackDump;
|
||||
|
||||
};
|
||||
|
||||
epicsShareExtern std::ostream& operator<<(std::ostream& o, const Status& status);
|
||||
epicsShareExtern std::ostream& operator<<(std::ostream& o, const Status::StatusType& statusType);
|
||||
|
||||
}}
|
||||
#endif /* STATUS_H */
|
||||
@@ -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
|
||||
*/
|
||||
/** C++ Template meta programming helpers
|
||||
*/
|
||||
@@ -11,7 +10,9 @@
|
||||
// gently nudge the compiler to inline our wrappers
|
||||
// Warning: Only use this when the template body is *small*.
|
||||
// You have been warned!
|
||||
#if defined(__GNUC__) && __GNUC__>=3
|
||||
#if defined(__MINGW32__)
|
||||
# define FORCE_INLINE inline
|
||||
#elif defined(__GNUC__) && __GNUC__>=3
|
||||
# define FORCE_INLINE __attribute__((always_inline)) inline
|
||||
#elif defined(_MSC_VER)
|
||||
# define FORCE_INLINE __forceinline
|
||||
296
src/misc/pv/thread.h
Normal file
296
src/misc/pv/thread.h
Normal file
@@ -0,0 +1,296 @@
|
||||
/* thread.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 THREAD_H
|
||||
#define THREAD_H
|
||||
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
||||
#if __cplusplus>=201103L
|
||||
#include <functional>
|
||||
#endif
|
||||
|
||||
#include <epicsThread.h>
|
||||
#include <shareLib.h>
|
||||
|
||||
#include <pv/noDefaultMethods.h>
|
||||
#include <pv/pvType.h>
|
||||
|
||||
|
||||
namespace epics { namespace pvData {
|
||||
|
||||
enum ThreadPriority {
|
||||
lowestPriority =epicsThreadPriorityLow,
|
||||
lowerPriority =epicsThreadPriorityLow + 15,
|
||||
lowPriority =epicsThreadPriorityMedium - 15,
|
||||
middlePriority =epicsThreadPriorityMedium,
|
||||
highPriority =epicsThreadPriorityMedium + 15,
|
||||
higherPriority =epicsThreadPriorityHigh - 15,
|
||||
highestPriority =epicsThreadPriorityHigh
|
||||
};
|
||||
|
||||
class Thread;
|
||||
typedef std::tr1::shared_ptr<Thread> ThreadPtr;
|
||||
typedef std::tr1::shared_ptr<epicsThread> EpicsThreadPtr;
|
||||
|
||||
typedef epicsThreadRunable Runnable;
|
||||
|
||||
//! Helper for those cases where a class should have more than one runnable
|
||||
template<typename C>
|
||||
class epicsShareClass RunnableMethod : public Runnable, private NoDefaultMethods
|
||||
{
|
||||
typedef void (C::*meth_t)();
|
||||
C *inst;
|
||||
meth_t meth;
|
||||
|
||||
virtual void run()
|
||||
{
|
||||
(inst->*meth)();
|
||||
}
|
||||
public:
|
||||
RunnableMethod(C* inst, void (C::*meth)())
|
||||
:inst(inst), meth(meth)
|
||||
{}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
struct FuncRunner : public epicsThreadRunable
|
||||
{
|
||||
typedef void (*fn_t)(void*);
|
||||
fn_t fn;
|
||||
void *arg;
|
||||
FuncRunner(fn_t f, void *a) :fn(f), arg(a) {}
|
||||
virtual ~FuncRunner(){}
|
||||
virtual void run()
|
||||
{
|
||||
(*fn)(arg);
|
||||
}
|
||||
};
|
||||
template<typename C>
|
||||
struct MethRunner : public epicsThreadRunable
|
||||
{
|
||||
typedef void(C::*fn_t)();
|
||||
fn_t fn;
|
||||
C* inst;
|
||||
MethRunner(C* i, fn_t f) :fn(f), inst(i) {}
|
||||
virtual ~MethRunner() {}
|
||||
virtual void run()
|
||||
{
|
||||
(inst->*fn)();
|
||||
}
|
||||
};
|
||||
#if __cplusplus>=201103L
|
||||
struct BindRunner : public epicsThreadRunable
|
||||
{
|
||||
typedef std::function<void()> fn_t;
|
||||
fn_t fn;
|
||||
BindRunner(const fn_t f) : fn(f) {}
|
||||
virtual ~BindRunner() {}
|
||||
virtual void run()
|
||||
{
|
||||
fn();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* @brief C++ wrapper for epicsThread from EPICS base.
|
||||
*
|
||||
*/
|
||||
class epicsShareClass Thread : public epicsThread, private NoDefaultMethods {
|
||||
public:
|
||||
/** @brief Holds all the configuration necessary to launch a @class Thread
|
||||
*
|
||||
* The defaults may be used except for the runnable, which must be given
|
||||
* either in the constructor, or the @method run() method.
|
||||
*
|
||||
* @note Instances of @class Config may not be reused.
|
||||
*
|
||||
* Defaults:
|
||||
* name: ""
|
||||
* priority: epicsThreadPriorityLow (aka epics::pvData::lowestPriority)
|
||||
* stack size: epicsThreadStackSmall
|
||||
* auto start: true
|
||||
* runner: nil (must be set explictly)
|
||||
*
|
||||
@code
|
||||
stuct bar { void meth(); ... } X;
|
||||
// with a static thread name
|
||||
Thread foo(Thread::Config(&X, &bar::meth)
|
||||
.name("example")
|
||||
.prio(epicsThreadPriorityHigh));
|
||||
|
||||
// with a constructed thread name
|
||||
Thread foo(Thread::Config(&X, &bar::meth)
|
||||
.prio(epicsThreadPriorityHigh)
|
||||
<<"example"<<1);
|
||||
@endcode
|
||||
*/
|
||||
class epicsShareClass Config
|
||||
{
|
||||
unsigned int p_prio, p_stack;
|
||||
std::ostringstream p_strm;
|
||||
bool p_autostart;
|
||||
Runnable *p_runner;
|
||||
#if __cplusplus>=201103L
|
||||
typedef std::unique_ptr<Runnable> p_owned_runner_t;
|
||||
#else
|
||||
typedef std::auto_ptr<Runnable> p_owned_runner_t;
|
||||
#endif
|
||||
p_owned_runner_t p_owned_runner;
|
||||
friend class Thread;
|
||||
Runnable& x_getrunner()
|
||||
{
|
||||
if(!this->p_runner)
|
||||
throw std::logic_error("Thread::Config missing run()");
|
||||
return *this->p_runner;
|
||||
}
|
||||
void x_setdefault()
|
||||
{
|
||||
this->p_prio = epicsThreadPriorityLow;
|
||||
this->p_autostart = true;
|
||||
this->p_runner = NULL;
|
||||
(*this).stack(epicsThreadStackSmall);
|
||||
}
|
||||
|
||||
public:
|
||||
Config() {this->x_setdefault();}
|
||||
Config(Runnable *r) {this->x_setdefault();this->run(r);}
|
||||
Config(void(*fn)(void*), void *ptr) {this->x_setdefault();this->run(fn, ptr);}
|
||||
template<typename C>
|
||||
Config(C* inst, void(C::*meth)()) {this->x_setdefault();this->run(inst, meth);}
|
||||
#if __cplusplus>=201103L
|
||||
Config(const std::function<void()>& fn) {this->x_setdefault();this->run(fn);}
|
||||
#endif
|
||||
|
||||
inline Config& name(const std::string& n)
|
||||
{ this->p_strm.str(n); return *this; }
|
||||
inline Config& prio(unsigned int p)
|
||||
{ this->p_prio = p; return *this; }
|
||||
inline Config& stack(epicsThreadStackSizeClass s)
|
||||
{ this->p_stack = epicsThreadGetStackSize(s); return *this; }
|
||||
inline Config& autostart(bool a)
|
||||
{ this->p_autostart = a; return *this; }
|
||||
|
||||
//! Thread will execute Runnable::run()
|
||||
Config& run(Runnable* r)
|
||||
{ this->p_runner = r; return *this; }
|
||||
//! Thread will execute (*fn)(ptr)
|
||||
Config& run(void(*fn)(void*), void *ptr)
|
||||
{
|
||||
this->p_owned_runner.reset(new detail::FuncRunner(fn, ptr));
|
||||
this->p_runner = this->p_owned_runner.get();
|
||||
return *this;
|
||||
}
|
||||
//! Thread will execute (inst->*meth)()
|
||||
template<typename C>
|
||||
Config& run(C* inst, void(C::*meth)())
|
||||
{
|
||||
this->p_owned_runner.reset(new detail::MethRunner<C>(inst, meth));
|
||||
this->p_runner = this->p_owned_runner.get();
|
||||
return *this;
|
||||
}
|
||||
#if __cplusplus>=201103L
|
||||
Config& run(const std::function<void()>& fn)
|
||||
{
|
||||
this->p_owned_runner.reset(new detail::BindRunner(fn));
|
||||
this->p_runner = this->p_owned_runner.get();
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
//! Append to thread name string. Argument must be understood by std::ostream::operator<<
|
||||
template<typename T>
|
||||
Config& operator<<(T x) { this->p_strm<<x; return *this; }
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* Constructor
|
||||
* @param name thread name.
|
||||
* @param priority priority is one of:
|
||||
@code
|
||||
enum ThreadPriority {
|
||||
lowestPriority, lowerPriority, lowPriority,
|
||||
middlePriority,
|
||||
highPriority, higherPriority, highestPriority
|
||||
};
|
||||
@endcode
|
||||
* @param runnable this is a c function
|
||||
* @param stkcls stack size as specified by epicsThreadStackSizeClass
|
||||
*/
|
||||
Thread(std::string name,
|
||||
ThreadPriority priority,
|
||||
Runnable *runnable,
|
||||
epicsThreadStackSizeClass stkcls=epicsThreadStackSmall)
|
||||
:epicsThread(*runnable,
|
||||
name.c_str(),
|
||||
epicsThreadGetStackSize(stkcls),
|
||||
priority)
|
||||
{
|
||||
this->start();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Constructor
|
||||
* @param runnable this is a c function
|
||||
* @name thread name.
|
||||
* @param stkcls stack size as specified by epicsThreadStackSizeClass
|
||||
* @param priority priority is one of:
|
||||
@code
|
||||
enum ThreadPriority {
|
||||
lowestPriority, lowerPriority, lowPriority,
|
||||
middlePriority,
|
||||
highPriority, higherPriority, highestPriority
|
||||
};
|
||||
@endcode
|
||||
*/
|
||||
Thread(Runnable &runnable,
|
||||
std::string name,
|
||||
unsigned int stksize,
|
||||
unsigned int priority=lowestPriority)
|
||||
:epicsThread(runnable,
|
||||
name.c_str(),
|
||||
stksize,
|
||||
priority)
|
||||
{
|
||||
this->start();
|
||||
}
|
||||
|
||||
//! @brief Create a new thread using the given @class Config
|
||||
//! @throws std::logic_error for improper @class Config (ie. missing runner)
|
||||
Thread(Config& c)
|
||||
:epicsThread(c.x_getrunner(), c.p_strm.str().c_str(),
|
||||
c.p_stack, c.p_prio)
|
||||
{
|
||||
#if __cplusplus>=201103L
|
||||
p_owned = std::move(c.p_owned_runner);
|
||||
#else
|
||||
p_owned = c.p_owned_runner;
|
||||
#endif
|
||||
if(c.p_autostart)
|
||||
this->start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
~Thread()
|
||||
{
|
||||
this->exitWait();
|
||||
}
|
||||
|
||||
Config::p_owned_runner_t p_owned;
|
||||
};
|
||||
|
||||
|
||||
}}
|
||||
#endif /* THREAD_H */
|
||||
@@ -1,8 +1,7 @@
|
||||
/* timeFunction.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 mrk
|
||||
@@ -21,19 +20,46 @@ class TimeFunction;
|
||||
typedef std::tr1::shared_ptr<TimeFunctionRequester> TimeFunctionRequesterPtr;
|
||||
typedef std::tr1::shared_ptr<TimeFunction> TimeFunctionPtr;
|
||||
|
||||
/**
|
||||
* @brief Class that must be implemented by timeFunction requester.
|
||||
*
|
||||
*/
|
||||
class epicsShareClass TimeFunctionRequester {
|
||||
public:
|
||||
POINTER_DEFINITIONS(TimeFunctionRequester);
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~TimeFunctionRequester(){}
|
||||
/**
|
||||
* function to be timed.
|
||||
* It will get called multiple times.
|
||||
*/
|
||||
virtual void function() = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Class for measuring time it takes to execute a function.
|
||||
*
|
||||
*/
|
||||
class epicsShareClass TimeFunction {
|
||||
public:
|
||||
POINTER_DEFINITIONS(TimeFunction);
|
||||
/**
|
||||
* Constructor
|
||||
* @param requester The class that has a function method.
|
||||
*/
|
||||
TimeFunction(TimeFunctionRequesterPtr const & requester);
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
~TimeFunction();
|
||||
/**
|
||||
* Time the function.
|
||||
* @return the time in seconds to execute the function.
|
||||
* Note that the function may be called many times.
|
||||
*/
|
||||
double timeCall();
|
||||
private:
|
||||
TimeFunctionRequesterPtr requester;
|
||||
134
src/misc/pv/timer.h
Normal file
134
src/misc/pv/timer.h
Normal file
@@ -0,0 +1,134 @@
|
||||
/* timer.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 TIMER_H
|
||||
#define TIMER_H
|
||||
#include <memory>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <pv/pvType.h>
|
||||
#include <pv/thread.h>
|
||||
#include <pv/timeStamp.h>
|
||||
#include <pv/event.h>
|
||||
#include <pv/lock.h>
|
||||
#include <pv/sharedPtr.h>
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
namespace epics { namespace pvData {
|
||||
|
||||
class TimerCallback;
|
||||
class Timer;
|
||||
typedef std::tr1::shared_ptr<TimerCallback> TimerCallbackPtr;
|
||||
typedef std::tr1::shared_ptr<Timer> TimerPtr;
|
||||
|
||||
/**
|
||||
* @brief Class that must be implemented by code that makes Timer requests.
|
||||
*
|
||||
*/
|
||||
class epicsShareClass TimerCallback {
|
||||
public:
|
||||
POINTER_DEFINITIONS(TimerCallback);
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
TimerCallback();
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~TimerCallback(){}
|
||||
/**
|
||||
* The method that is called when a timer expires.
|
||||
*/
|
||||
virtual void callback() = 0;
|
||||
/**
|
||||
* The timer has stopped.
|
||||
*/
|
||||
virtual void timerStopped() = 0;
|
||||
private:
|
||||
TimerCallbackPtr next;
|
||||
TimeStamp timeToRun;
|
||||
double period;
|
||||
bool onList;
|
||||
friend class Timer;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Support for delayed or periodic callback execution.
|
||||
*
|
||||
*/
|
||||
class epicsShareClass Timer : public Runnable {
|
||||
public:
|
||||
POINTER_DEFINITIONS(Timer);
|
||||
/**
|
||||
* Constructor
|
||||
* @param threadName name for the timer thread.
|
||||
* @param priority thread priority
|
||||
*/
|
||||
Timer(std::string threadName, ThreadPriority priority);
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~Timer();
|
||||
/**
|
||||
* The thread run method. This is called automatically.
|
||||
*/
|
||||
virtual void run();
|
||||
/**
|
||||
* schedule a callback after a delay.
|
||||
* @param timerCallback the timerCallback instance.
|
||||
* @param delay number of seconds before calling callback.
|
||||
*/
|
||||
void scheduleAfterDelay(
|
||||
TimerCallbackPtr const &timerCallback,
|
||||
double delay);
|
||||
/**
|
||||
* schedule a periodic callback.`
|
||||
* @param timerCallback the timerCallback instance.
|
||||
* @param delay number of seconds before first callback.
|
||||
* @param period time in seconds between each callback.
|
||||
*/
|
||||
void schedulePeriodic(
|
||||
TimerCallbackPtr const &timerCallback,
|
||||
double delay,
|
||||
double period);
|
||||
/**
|
||||
* cancel a callback.
|
||||
* @param timerCallback the timerCallback to cancel.
|
||||
*/
|
||||
void cancel(TimerCallbackPtr const &timerCallback);
|
||||
/**
|
||||
* Is the callback scheduled to be called?
|
||||
* @param timerCallback the timerCallback.
|
||||
* @return (false,true) if (not, is) scheduled.
|
||||
*/
|
||||
bool isScheduled(TimerCallbackPtr const &timerCallback);
|
||||
/**
|
||||
* show the elements in the timer queue.
|
||||
* @param o The output stream for the output
|
||||
*/
|
||||
void dump(std::ostream& o);
|
||||
|
||||
private:
|
||||
void addElement(TimerCallbackPtr const &timerCallback);
|
||||
TimerCallbackPtr head;
|
||||
Mutex mutex;
|
||||
Event waitForWork;
|
||||
Event waitForDone;
|
||||
bool alive;
|
||||
Thread thread;
|
||||
};
|
||||
|
||||
epicsShareExtern std::ostream& operator<<(std::ostream& o, Timer& timer);
|
||||
|
||||
}}
|
||||
#endif /* TIMER_H */
|
||||
@@ -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: Michael Davidsaver */
|
||||
#ifndef PVTYPECAST_H
|
||||
@@ -10,28 +9,16 @@
|
||||
#include <stdexcept>
|
||||
#include <sstream>
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
#define typeCastepicsExportSharedSymbols
|
||||
#undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include <epicsConvert.h>
|
||||
|
||||
#ifdef typeCastepicsExportSharedSymbols
|
||||
#define epicsExportSharedSymbols
|
||||
#undef typeCastepicsExportSharedSymbols
|
||||
#endif
|
||||
#include <shareLib.h>
|
||||
|
||||
#include <pv/pvType.h>
|
||||
#include <pv/pvIntrospect.h>
|
||||
#include <pv/templateMeta.h>
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
namespace epics { namespace pvData {
|
||||
|
||||
typedef std::string String;
|
||||
|
||||
namespace detail {
|
||||
// parseToPOD wraps the epicsParse*() functions in one name
|
||||
// and throws exceptions
|
||||
@@ -48,12 +35,12 @@ namespace detail {
|
||||
epicsShareExtern void parseToPOD(const std::string&, double *out);
|
||||
|
||||
/* want to pass POD types by value,
|
||||
* and String by const reference
|
||||
* and std::string by const reference
|
||||
*/
|
||||
template<typename ARG>
|
||||
struct cast_arg { typedef ARG arg; };
|
||||
template<>
|
||||
struct cast_arg<String> { typedef const String& arg; };
|
||||
struct cast_arg<std::string> { typedef const std::string& arg; };
|
||||
|
||||
// Handle mangling of type/value when printing
|
||||
template<typename T>
|
||||
@@ -61,7 +48,7 @@ namespace detail {
|
||||
typedef T return_t;
|
||||
static FORCE_INLINE return_t op(const T& i) { return i; }
|
||||
};
|
||||
// trick std::ostream into treating char's as numbers
|
||||
// trick std::ostream into treating chars as numbers
|
||||
// by promoting char to int
|
||||
template<>
|
||||
struct print_convolute<int8> {
|
||||
@@ -98,10 +85,10 @@ namespace detail {
|
||||
};
|
||||
|
||||
// print POD to string
|
||||
// when String!=FROM
|
||||
// when std::string!=FROM
|
||||
template<typename FROM>
|
||||
struct cast_helper<String, FROM, typename meta::not_same_type<String,FROM>::type> {
|
||||
static String op(FROM from) {
|
||||
struct cast_helper<std::string, FROM, typename meta::not_same_type<std::string,FROM>::type> {
|
||||
static std::string op(FROM from) {
|
||||
std::ostringstream strm;
|
||||
strm << print_convolute<FROM>::op(from);
|
||||
if(strm.fail())
|
||||
@@ -111,10 +98,10 @@ namespace detail {
|
||||
};
|
||||
|
||||
// parse POD from string
|
||||
// TO!=String
|
||||
// TO!=std::string
|
||||
template<typename TO>
|
||||
struct cast_helper<TO, String, typename meta::not_same_type<TO,String>::type> {
|
||||
static FORCE_INLINE TO op(const String& from) {
|
||||
struct cast_helper<TO, std::string, typename meta::not_same_type<TO,std::string>::type> {
|
||||
static FORCE_INLINE TO op(const std::string& from) {
|
||||
TO ret;
|
||||
parseToPOD(from, &ret);
|
||||
return ret;
|
||||
@@ -127,7 +114,7 @@ namespace detail {
|
||||
*
|
||||
* Supported types: uint8_t, int8_t, uint16_t, int16_t,
|
||||
* uint32_t, int32_t, uint64_t, int64_t,
|
||||
* float, double, String
|
||||
* float, double, std::string
|
||||
*
|
||||
* As defined in pvType.h
|
||||
*
|
||||
@@ -144,7 +131,7 @@ namespace detail {
|
||||
* - float -> double
|
||||
*
|
||||
* Conversions where out of range inputs always produce
|
||||
* a defined result, but may not be reversable.
|
||||
* a defined result, but may not be reversible.
|
||||
*
|
||||
* - double -> float. When abs(value) is outside the range
|
||||
* [FLT_MIN, FLT_MAX] the value is clipped to FLT_MIN or FLT_MAX
|
||||
@@ -153,9 +140,9 @@ namespace detail {
|
||||
* Conversions where invalid or out of range inputs result
|
||||
* in an exception.
|
||||
*
|
||||
* - non-String -> String
|
||||
* - String -> non-String
|
||||
* - String -> String (throws only std::bad_alloc)
|
||||
* - non-std::string -> std::string
|
||||
* - std::string -> non-std::string
|
||||
* - std::string -> std::string (throws only std::bad_alloc)
|
||||
*
|
||||
* Conversions where out of range inputs produce undefined
|
||||
* results.
|
||||
@@ -169,7 +156,7 @@ namespace detail {
|
||||
* too large to be represented by the integer type
|
||||
* is not defined.
|
||||
*
|
||||
@section stringf String formats
|
||||
@section stringf std::string formats
|
||||
*
|
||||
* - Numbers beginning with 1-9 are parsed as base-10.
|
||||
* - Numbers beginning with '0x' are parsed as base-16
|
||||
@@ -1,24 +1,28 @@
|
||||
/* requester.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
|
||||
*/
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
|
||||
#include <epicsMutex.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/lock.h>
|
||||
#include <pv/requester.h>
|
||||
|
||||
using std::string;
|
||||
|
||||
namespace epics { namespace pvData {
|
||||
|
||||
static StringArray messageTypeName(MESSAGE_TYPE_COUNT);
|
||||
|
||||
String getMessageTypeName(MessageType messageType)
|
||||
string getMessageTypeName(MessageType messageType)
|
||||
{
|
||||
// TODO not thread-safe
|
||||
static Mutex mutex;
|
||||
@@ -32,6 +36,9 @@ String getMessageTypeName(MessageType messageType)
|
||||
return messageTypeName[messageType];
|
||||
}
|
||||
|
||||
|
||||
void Requester::message(std::string const & message,MessageType messageType)
|
||||
{
|
||||
std::cerr << "[" << getRequesterName() << "] message(" << message << ", " << getMessageTypeName(messageType) << ")\n";
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
/* requester.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 REQUESTER_H
|
||||
#define REQUESTER_H
|
||||
#include <string>
|
||||
|
||||
#include <pv/pvType.h>
|
||||
#include <pv/sharedPtr.h>
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
namespace epics { namespace pvData {
|
||||
|
||||
class Requester;
|
||||
typedef std::tr1::shared_ptr<Requester> RequesterPtr;
|
||||
|
||||
enum MessageType {
|
||||
infoMessage,warningMessage,errorMessage,fatalErrorMessage
|
||||
};
|
||||
#define MESSAGE_TYPE_COUNT 4
|
||||
|
||||
epicsShareExtern String getMessageTypeName(MessageType messageType);
|
||||
|
||||
class epicsShareClass Requester {
|
||||
public:
|
||||
POINTER_DEFINITIONS(Requester);
|
||||
virtual ~Requester(){}
|
||||
virtual String getRequesterName() = 0;
|
||||
virtual void message(String const & message,MessageType messageType) = 0;
|
||||
};
|
||||
|
||||
}}
|
||||
#endif /* REQUESTER_H */
|
||||
@@ -1,76 +0,0 @@
|
||||
/* serialize.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 SERIALIZE_H
|
||||
#define SERIALIZE_H
|
||||
|
||||
#include <pv/byteBuffer.h>
|
||||
#include <pv/sharedPtr.h>
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
namespace epics { namespace pvData {
|
||||
|
||||
class SerializableControl;
|
||||
class DeserializableControl;
|
||||
class Serializable;
|
||||
class BitSetSerializable;
|
||||
class SerializableArray;
|
||||
class BitSet;
|
||||
class Field;
|
||||
|
||||
class epicsShareClass SerializableControl {
|
||||
public:
|
||||
virtual ~SerializableControl(){}
|
||||
virtual void flushSerializeBuffer() =0;
|
||||
virtual void ensureBuffer(std::size_t size) =0;
|
||||
virtual void alignBuffer(std::size_t alignment) =0;
|
||||
virtual bool directSerialize(ByteBuffer *existingBuffer, const char* toSerialize,
|
||||
std::size_t elementCount, std::size_t elementSize) = 0;
|
||||
virtual void cachedSerialize(std::tr1::shared_ptr<const Field> const & field, ByteBuffer* buffer) = 0;
|
||||
};
|
||||
|
||||
class epicsShareClass DeserializableControl {
|
||||
public:
|
||||
virtual ~DeserializableControl(){}
|
||||
virtual void ensureData(std::size_t size) =0;
|
||||
virtual void alignData(std::size_t alignment) =0;
|
||||
virtual bool directDeserialize(ByteBuffer *existingBuffer, char* deserializeTo,
|
||||
std::size_t elementCount, std::size_t elementSize) = 0;
|
||||
virtual std::tr1::shared_ptr<const Field> cachedDeserialize(ByteBuffer* buffer) = 0;
|
||||
};
|
||||
|
||||
class epicsShareClass Serializable {
|
||||
public:
|
||||
virtual ~Serializable(){}
|
||||
virtual void serialize(ByteBuffer *buffer,
|
||||
SerializableControl *flusher) const = 0;
|
||||
virtual void deserialize(ByteBuffer *buffer,
|
||||
DeserializableControl *flusher) = 0;
|
||||
};
|
||||
|
||||
class epicsShareClass BitSetSerializable {
|
||||
public:
|
||||
virtual ~BitSetSerializable(){}
|
||||
virtual void serialize(ByteBuffer *buffer,
|
||||
SerializableControl *flusher,BitSet *bitSet) const = 0;
|
||||
virtual void deserialize(ByteBuffer *buffer,
|
||||
DeserializableControl *flusher,BitSet *bitSet) = 0;
|
||||
};
|
||||
|
||||
|
||||
class epicsShareClass SerializableArray : virtual public Serializable {
|
||||
public:
|
||||
virtual ~SerializableArray(){}
|
||||
virtual void serialize(ByteBuffer *buffer,
|
||||
SerializableControl *flusher, std::size_t offset, std::size_t count) const = 0;
|
||||
};
|
||||
|
||||
}}
|
||||
#endif /* SERIALIZE_H */
|
||||
@@ -1,19 +1,21 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
/*
|
||||
* serializeHelper.cpp
|
||||
*
|
||||
* Created on: Oct 22, 2010
|
||||
* Author: Miha vitorovic
|
||||
* Author: Miha Vitorovic
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <epicsEndian.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/pvType.h>
|
||||
#include <pv/byteBuffer.h>
|
||||
#include <pv/epicsException.h>
|
||||
#include <pv/byteBuffer.h>
|
||||
#include <pv/serializeHelper.h>
|
||||
@@ -57,7 +59,7 @@ namespace epics {
|
||||
return (std::size_t)(b<0 ? b+256 : b);
|
||||
}
|
||||
|
||||
void SerializeHelper::serializeString(const String& value,
|
||||
void SerializeHelper::serializeString(const string& value,
|
||||
ByteBuffer* buffer, SerializableControl* flusher) {
|
||||
std::size_t len = value.length();
|
||||
SerializeHelper::writeSize(len, buffer, flusher);
|
||||
@@ -74,7 +76,7 @@ namespace epics {
|
||||
}
|
||||
}
|
||||
|
||||
void SerializeHelper::serializeSubstring(const String& value,
|
||||
void SerializeHelper::serializeSubstring(const string& value,
|
||||
std::size_t offset, std::size_t count, ByteBuffer* buffer,
|
||||
SerializableControl* flusher) {
|
||||
/*if(offset<0)
|
||||
@@ -97,9 +99,9 @@ namespace epics {
|
||||
}
|
||||
}
|
||||
|
||||
static String emptyString;
|
||||
static string emptyStringtring;
|
||||
|
||||
String SerializeHelper::deserializeString(ByteBuffer* buffer,
|
||||
string SerializeHelper::deserializeString(ByteBuffer* buffer,
|
||||
DeserializableControl* control) {
|
||||
|
||||
std::size_t size = SerializeHelper::readSize(buffer, control);
|
||||
@@ -109,13 +111,13 @@ namespace epics {
|
||||
{
|
||||
// entire string is in buffer, simply create a string out of it (copy)
|
||||
std::size_t pos = buffer->getPosition();
|
||||
String str(buffer->getArray()+pos, size);
|
||||
string str(buffer->getArray()+pos, size);
|
||||
buffer->setPosition(pos+size);
|
||||
return str;
|
||||
}
|
||||
else
|
||||
{
|
||||
String str;
|
||||
string str;
|
||||
str.reserve(size);
|
||||
try {
|
||||
std::size_t i = 0;
|
||||
@@ -137,8 +139,134 @@ namespace epics {
|
||||
}
|
||||
}
|
||||
else
|
||||
return emptyString;
|
||||
return emptyStringtring;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
using namespace epics::pvData;
|
||||
|
||||
struct ToString : public epics::pvData::SerializableControl
|
||||
{
|
||||
typedef std::vector<epicsUInt8> buf_type;
|
||||
buf_type buf;
|
||||
buf_type& out;
|
||||
ByteBuffer bufwrap;
|
||||
|
||||
ToString(buf_type& out, int byteOrder = EPICS_BYTE_ORDER)
|
||||
:buf(16*1024)
|
||||
,out(out)
|
||||
,bufwrap((char*)&buf[0], buf.size(), byteOrder)
|
||||
{}
|
||||
|
||||
virtual void flushSerializeBuffer()
|
||||
{
|
||||
size_t N = out.size();
|
||||
out.resize(out.size()+bufwrap.getPosition());
|
||||
std::copy(buf.begin(),
|
||||
buf.begin()+bufwrap.getPosition(),
|
||||
out.begin()+N);
|
||||
bufwrap.clear();
|
||||
}
|
||||
|
||||
virtual void ensureBuffer(std::size_t size)
|
||||
{
|
||||
flushSerializeBuffer();
|
||||
assert(bufwrap.getRemaining()>0);
|
||||
}
|
||||
|
||||
virtual void alignBuffer(std::size_t alignment)
|
||||
{
|
||||
if(bufwrap.getRemaining()<alignment)
|
||||
flushSerializeBuffer();
|
||||
assert(bufwrap.getRemaining()>=alignment);
|
||||
bufwrap.align(alignment);
|
||||
}
|
||||
|
||||
virtual bool directSerialize(
|
||||
ByteBuffer *existingBuffer,
|
||||
const char* toSerialize,
|
||||
std::size_t elementCount,
|
||||
std::size_t elementSize)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void cachedSerialize(
|
||||
std::tr1::shared_ptr<const Field> const & field,
|
||||
ByteBuffer* buffer)
|
||||
{
|
||||
field->serialize(buffer, this);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace epics {
|
||||
namespace pvData {
|
||||
void serializeToVector(const Serializable *S,
|
||||
int byteOrder,
|
||||
std::vector<epicsUInt8>& out)
|
||||
{
|
||||
ToString TS(out, byteOrder);
|
||||
S->serialize(&TS.bufwrap, &TS);
|
||||
TS.flushSerializeBuffer();
|
||||
assert(TS.bufwrap.getPosition()==0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct FromString : public epics::pvData::DeserializableControl
|
||||
{
|
||||
ByteBuffer &buf;
|
||||
epics::pvData::FieldCreatePtr create;
|
||||
|
||||
FromString(ByteBuffer& b)
|
||||
:buf(b)
|
||||
,create(epics::pvData::getFieldCreate())
|
||||
{}
|
||||
|
||||
virtual void ensureData(std::size_t size)
|
||||
{
|
||||
if(size>buf.getRemaining())
|
||||
throw std::logic_error("Incomplete buffer");
|
||||
}
|
||||
|
||||
virtual void alignData(std::size_t alignment)
|
||||
{
|
||||
size_t pos = buf.getPosition(), k = alignment-1;
|
||||
if(pos&k) {
|
||||
std::size_t npad = alignment-(pos&k);
|
||||
ensureData(npad);
|
||||
buf.align(alignment);
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool directDeserialize(
|
||||
ByteBuffer *existingBuffer,
|
||||
char* deserializeTo,
|
||||
std::size_t elementCount,
|
||||
std::size_t elementSize)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
virtual std::tr1::shared_ptr<const Field> cachedDeserialize(
|
||||
ByteBuffer* buffer)
|
||||
{
|
||||
return create->deserialize(buffer, this);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace epics {
|
||||
namespace pvData {
|
||||
void deserializeFromBuffer(Serializable *S,
|
||||
ByteBuffer& buf)
|
||||
{
|
||||
FromString F(buf);
|
||||
S->deserialize(&buf, &F);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
/*pvData.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.
|
||||
/*status.cpp*/
|
||||
/*
|
||||
* Copyright information and license terms for this software can be
|
||||
* found in the file LICENSE that is included with the distribution
|
||||
*/
|
||||
/**
|
||||
* @author mrk
|
||||
@@ -12,10 +11,11 @@
|
||||
#include <pv/serializeHelper.h>
|
||||
#include <pv/status.h>
|
||||
|
||||
using std::string;
|
||||
|
||||
namespace epics { namespace pvData {
|
||||
|
||||
const char* Status::StatusTypeName[] = { "OK", "WARNING", "ERROR", "FATAL" };
|
||||
epics::pvData::String Status::m_emptyString;
|
||||
|
||||
Status Status::Ok;
|
||||
|
||||
@@ -26,7 +26,7 @@ Status::Status() :
|
||||
{
|
||||
}
|
||||
|
||||
Status::Status(StatusType type, String const & message) :
|
||||
Status::Status(StatusType type, string const & message) :
|
||||
m_statusType(type), m_message(message)
|
||||
{
|
||||
if (type == STATUSTYPE_OK)
|
||||
@@ -35,7 +35,7 @@ Status::Status(StatusType type, String const & message) :
|
||||
//PVDATA_REFCOUNT_MONITOR_CONSTRUCT(status);
|
||||
}
|
||||
|
||||
Status::Status(StatusType type, String const & message, String const & stackDump) :
|
||||
Status::Status(StatusType type, string const & message, string const & stackDump) :
|
||||
m_statusType(type), m_message(message), m_stackDump(stackDump)
|
||||
{
|
||||
if (type == STATUSTYPE_OK)
|
||||
@@ -54,12 +54,12 @@ Status::StatusType Status::getType() const
|
||||
}
|
||||
|
||||
|
||||
epics::pvData::String Status::getMessage() const
|
||||
string Status::getMessage() const
|
||||
{
|
||||
return m_message;
|
||||
}
|
||||
|
||||
epics::pvData::String Status::getStackDump() const
|
||||
string Status::getStackDump() const
|
||||
{
|
||||
return m_stackDump;
|
||||
}
|
||||
@@ -100,7 +100,8 @@ void Status::deserialize(ByteBuffer *buffer, DeserializableControl *flusher)
|
||||
if (m_statusType != STATUSTYPE_OK)
|
||||
{
|
||||
m_statusType = STATUSTYPE_OK;
|
||||
m_message = m_stackDump = m_emptyString;
|
||||
m_message.clear();
|
||||
m_stackDump.clear();
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -111,29 +112,26 @@ void Status::deserialize(ByteBuffer *buffer, DeserializableControl *flusher)
|
||||
}
|
||||
}
|
||||
|
||||
String Status::toString() const
|
||||
void Status::dump(std::ostream& o) const
|
||||
{
|
||||
String str;
|
||||
toString(&str, 0);
|
||||
return str;
|
||||
o << "Status [type=" << Status::StatusTypeName[m_statusType];
|
||||
if (!m_message.empty())
|
||||
o << ", message=" << m_message;
|
||||
if (!m_stackDump.empty())
|
||||
o << ", stackDump=" << std::endl << m_stackDump;
|
||||
o << ']';
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& o, const Status& status)
|
||||
{
|
||||
status.dump(o);
|
||||
return o;
|
||||
}
|
||||
|
||||
void Status::toString(StringBuilder buffer, int /*indentLevel*/) const
|
||||
std::ostream& operator<<(std::ostream& o, const Status::StatusType& statusType)
|
||||
{
|
||||
*buffer += "Status [type=";
|
||||
*buffer += StatusTypeName[m_statusType];
|
||||
if (!m_message.empty())
|
||||
{
|
||||
*buffer += ", message=";
|
||||
*buffer += m_message;
|
||||
}
|
||||
if (!m_stackDump.empty())
|
||||
{
|
||||
*buffer += ", stackDump=";
|
||||
*buffer += '\n';
|
||||
*buffer += m_stackDump;
|
||||
}
|
||||
*buffer += ']';
|
||||
o << Status::StatusTypeName[statusType];
|
||||
return o;
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
/* thread.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 THREAD_H
|
||||
#define THREAD_H
|
||||
|
||||
#include <memory>
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
#define threadepicsExportSharedSymbols
|
||||
#undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include <epicsThread.h>
|
||||
|
||||
#ifdef threadepicsExportSharedSymbols
|
||||
#define epicsExportSharedSymbols
|
||||
#undef threadepicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include <pv/noDefaultMethods.h>
|
||||
#include <pv/pvType.h>
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
namespace epics { namespace pvData {
|
||||
|
||||
enum ThreadPriority {
|
||||
lowestPriority =epicsThreadPriorityLow,
|
||||
lowerPriority =epicsThreadPriorityLow + 15,
|
||||
lowPriority =epicsThreadPriorityMedium - 15,
|
||||
middlePriority =epicsThreadPriorityMedium,
|
||||
highPriority =epicsThreadPriorityMedium + 15,
|
||||
higherPriority =epicsThreadPriorityHigh - 15,
|
||||
highestPriority =epicsThreadPriorityHigh
|
||||
};
|
||||
|
||||
class Thread;
|
||||
typedef std::tr1::shared_ptr<Thread> ThreadPtr;
|
||||
typedef std::tr1::shared_ptr<epicsThread> EpicsThreadPtr;
|
||||
|
||||
typedef epicsThreadRunable Runnable;
|
||||
|
||||
class epicsShareClass Thread : public epicsThread, private NoDefaultMethods {
|
||||
public:
|
||||
|
||||
Thread(String name,
|
||||
ThreadPriority priority,
|
||||
Runnable *runnable,
|
||||
epicsThreadStackSizeClass stkcls=epicsThreadStackSmall)
|
||||
:epicsThread(*runnable,
|
||||
name.c_str(),
|
||||
epicsThreadGetStackSize(stkcls),
|
||||
priority)
|
||||
{
|
||||
this->start();
|
||||
}
|
||||
|
||||
Thread(Runnable &runnable,
|
||||
String name,
|
||||
unsigned int stksize,
|
||||
unsigned int priority=lowestPriority)
|
||||
:epicsThread(runnable,
|
||||
name.c_str(),
|
||||
stksize,
|
||||
priority)
|
||||
{
|
||||
this->start();
|
||||
}
|
||||
|
||||
~Thread()
|
||||
{
|
||||
this->exitWait();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}}
|
||||
#endif /* THREAD_H */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user