diff --git a/documentation/Doxyfile b/documentation/Doxyfile new file mode 100644 index 0000000..55df4dd --- /dev/null +++ b/documentation/Doxyfile @@ -0,0 +1,1621 @@ +# Doxyfile 1.7.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = pvDataCPP + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = xyz + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = .. + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = YES + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this +# tag. The format is ext=language, where ext is a file extension, and language +# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, +# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions +# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = YES + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen to replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penality. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will rougly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = NO + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespace are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. The create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = ../pvDataApp + +# 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 +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = YES + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the stylesheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list. + +USE_INLINE_TREES = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvances is that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = ./pvDataCPP.tag + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = YES + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will write a font called FreeSans.ttf to the output +# directory and reference it in all dot files that doxygen generates. This +# font does not include all possible unicode characters however, so when you need +# these (or just want a differently looking font) you can specify the font name +# using DOT_FONTNAME. You need need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = FreeSans.ttf + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = YES + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/documentation/pvArray.html b/documentation/pvArray.html new file mode 100644 index 0000000..b5c53c3 --- /dev/null +++ b/documentation/pvArray.html @@ -0,0 +1,1842 @@ + + + + + + EPICS pvArray + + + + + + + + +
+

EPICS Array

+ + +

EPICS v4 Working Group, Working Draft, 28-Jun-2013

+ +
+
Latest version:
+
pvArray.html +
+
This version:
+
none
+
Previous version:
+
None
+
Editors:
+
Marty Kraimer, BNL
+ Michael Davidsaver, BNL
+
+ + +
+
+ + +
+

Table of Contents

+
+
+ + +

Changes

+

Since the last version of this document the following changes have +been made to the proposed interface definitionsi for PVValueArray:

+
+
put(const svector &from)
+
This has been removed. shareData can be used instead.
+
get
+
The get methods has been replaced by two methods. + One allows write access to array elements and the other does not. +
+
+

The stream operator++ methods were changed so that they only appear +in PVField. All the complexity should be hidden in the implementation +and, perhaps like Java, in the convert facility.

+

A few minor changes were made because of mistakes in documenting +existing API descriptions.

+

Introduction

+

This is the documentation for pvData.h as defined by pvDataCPP-md. +When complete it will be merged into pvDataCPP.html. +This document proposes an implementation of the PVXXX interfaces that are +different than the existing pvDataCPP-md interfaces. +See the next section for a comparison of the four interface descriptions. +The main reason for proposing a different definition is the primary +purpose for pvData: +

pvData (Process Variable Data) defines and implements an efficent +way to store, access, and communicate memory resident data structures.
+This statement appears as the first sentence of pvDataJava.html. +A few sentances later the document makes clear that communication +includes network communication. +Thus pvData provides an interface for network accessible structured data. +If the interfaces for C++ and Java are similar then +someone who understands the interface in one of the languages +and knows both languages will quickly understand the interface of the other language. +With only a few exceptions the naming and other conventions do +not follow the C++ standard library conventions. +The pvData.h API is similar to the definition for Java. +The differences are mainly related to language differences. +Some differences are: +
+
shared pointers
+
Java has a garbage collector. In C++ the implementation manages + memory. An important tool is std::tr1::shared_ptr.
+
PVArray
+
The Java garbage collector allows raw data arrays, e. g. int[], + to be shared. For C++ a shared_vector holds the raw data. +
+
ostream replaces toString
+
In Java every object has method toString(). + For C++ stream operator<< replaces toString
+
shared_vector
+
This is similar to std::vector but uses a shared_ptr to wrap the raw + data and also supports a window into the raw data. It does follow the + naming and other conventions for C++ standard library containers. + Code that wants to use features of the C++ standard library + like iterators and algorithms can get the shared_vector. +
+
+

There is one big difference from the existing Java API: +The method PVValueArray::get. +As an example the Java definition for PVDoubleArray is currently: +

+    int get(int offset, int length, DoubleArrayData data);
+
+This document assumes this will be replaced by: +
+    double[] get();
+
+

The existing version allowed the data source to provide the array in chunks. +The new version assumes that the data source always provides contiguous storage +for the entire raw array. If this is accepted it simplifies a lot of code. +

+

Three topics not discussed in this document are: +

+
pvDataCreate
+
There should be a new method something like: +
+PVScalarArrayPtr createPVScalarArray(const PVScalarArray &, size_t offset, size_t length);
+      
+ This will share the raw data array but allow a new window. +
+
convert
+
This will be changed to do conversions itself instead of calling + methods like getAs. It will again support methods toXXXArray and fromXXXArray. + Templates should be used to minimize the code required.
+
PVStructureArray
+
This should also be able to use shared_vector to hold elements.
+
+

+

PVXXX: pvDataJava, pvDataCPP, pvDataCPP-md, and proposed interface

+

The following compares the definitions of the following: PVField, +PVScalar and extensions, PVArray and extensions. +PVStructureArray is not discussed. +

+

PVField

+

This is the base for all the PVXXX iterfaces. +It provides basic methods for allowing network transfer and for +traversing structured data. +The pvDataJava and pvDataCPP definitions are similar. +pvDataCPP-md added method getFullName. +The proposed interface is like the existing pvDataCPP except that +the dumpValue method is replaced by the stream operator<<. +

+

Java

+
interface PVField extends Requester, Serializable {
+    String getFieldName();
+    void setRequester(Requester requester);
+    int getFieldOffset();
+    int getNextFieldOffset();
+    int getNumberFields();
+    PVAuxInfo getPVAuxInfo();
+    boolean isImmutable();
+    void setImmutable();
+    Field getField();
+    PVStructure getParent();
+    void renameField(String newName);
+    void postPut(); // calls PVRecordField.postPut if this is a field of a record
+    void setPostHandler(PostHandler postHandler);
+    void toString(StringBuilder buf);
+    void toString(StringBuilder buf,int indentLevel);
+    String toString();
+}
+

pvDataCPP

+
class PVField
+: virtual public Serializable,
+  public std::tr1::enable_shared_from_this<PVField>
+{
+public:
+   POINTER_DEFINITIONS(PVField);
+   virtual ~PVField();
+   virtual void message(String message,MessageType messageType);
+   String getFieldName() const ;
+   virtual void setRequester(RequesterPtr const &prequester);
+   std::size_t getFieldOffset() const;
+   std::size_t getNextFieldOffset() const;
+   std::size_t getNumberFields() const;
+   PVAuxInfoPtr & getPVAuxInfo()
+   bool isImmutable() const;
+   virtual void setImmutable();
+   const FieldConstPtr & getField() const ;
+   PVStructure * getParent() const
+   void replacePVField(const PVFieldPtr&  newPVField);
+   void renameField(String const &newName);
+   void postPut() ;
+   void setPostHandler(PostHandlerPtr const &postHandler);
+   virtual bool equals(PVField &pv);
+   virtual void toString(StringBuilder buf) ;
+   virtual void toString(StringBuilder buf,int indentLevel);
+   virtual std::ostream& dumpValue(std::ostream& o) const =0;
+ ...
+}
+
+std::ostream& operator<<(std::ostream& o, const PVFieldPtr & f);
+
+

pvDataCPP-md

+
class PVField
+: virtual public Serializable,
+  public std::tr1::enable_shared_from_this<PVField>
+{
+public:
+   POINTER_DEFINITIONS(PVField);
+   virtual ~PVField();
+   virtual void message(String message,MessageType messageType);
+   String getFieldName() const ;
+   virtual void setRequester(RequesterPtr const &prequester);
+   std::size_t getFieldOffset() const;
+   std::size_t getNextFieldOffset() const;
+   std::size_t getNumberFields() const;
+   PVAuxInfoPtr & getPVAuxInfo()
+   bool isImmutable() const;
+   virtual void setImmutable();
+   const FieldConstPtr & getField() const ;
+   PVStructure * getParent() const
+   void replacePVField(const PVFieldPtr&  newPVField);
+   void renameField(String const &newName);
+   void postPut() ;
+   void setPostHandler(PostHandlerPtr const &postHandler);
+   virtual bool equals(PVField &pv);
+   virtual void toString(StringBuilder buf) ;
+   virtual void toString(StringBuilder buf,int indentLevel);
+   std::ostream& dumpValue(std::ostream& o) const;
+   // not in pvDataCPP
+   String getFullName() const;
+ ...
+}
+
+std::ostream& operator<<(std::ostream& o, const PVFieldPtr & f);
+
+

proposed

+
+class PVField
+: virtual public Serializable,
+  public std::tr1::enable_shared_from_this
+{
+public:
+    POINTER_DEFINITIONS(PVField);
+    virtual ~PVField();
+    virtual void message(String message,MessageType messageType);
+    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;
+    PVAuxInfoPtr & getPVAuxInfo();
+    bool isImmutable() const;
+    void setImmutable();
+    const FieldConstPtr & getField() const;
+    PVStructure * getParent() const;
+    void replacePVField(const PVFieldPtr&  newPVField);
+    void renameField(String const & newName);
+    void postPut();
+    void setPostHandler(PostHandlerPtr const &postHandler);
+    virtual bool equals(PVField &pv);
+    void toString(StringBuilder buf) ;
+    void toString(StringBuilder buf,int indentLevel);
+    std::ostream& operator<<(std::ostream& o) const;
+...
+};
+
+
+

PVScalar

+

The Java and pvDataCPP versions differ in that Java has an interface definition +for each scalar type, i. e. PVBoolean, ..., PVString, +and the CPP versions provide a template PVValue for the implementation.

+

+pvDataCPP-md differs from pvDataCPP in that it implements three additional +methods: +

+
getAs
+
This is used to implement the Convert::toXXX methods. + This belongs in the Convert implementation not in PVScalar.
+
putFrom
+
This is used to implement the Convert::fromXXX scalar methods. + This belongs in the Convert implementation not in PVScalar.
+
assign
+
This does the same thing as the Convert::fromXXX methods except + that it does not go through Convert. + This belongs in the Convert implementation not in PVScalar.
+
+

+

The proposed version is like the pvDataCPP version except for dumpValue +and the stream interators.

+

pvDataJava

+
+interface PVScalar extends PVField {
+    Scalar getScalar();
+}
+
+interface PVBoolean extends PVScalar {
+    boolean get();
+    void put(boolean value);
+}
+
+interface PVByte extends PVScalar {
+    byte get();
+    void put(byte value);
+}
+...
+interface PVDouble extends PVScalar {
+    double get();
+    void put(double value);
+}
+interface PVString extends PVScalar, SerializableArray {
+    String get();
+    void put(String value);
+}
+
+

pvDataCPP

+
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;
+    std::ostream& dumpValue(std::ostream& o) const
+    void operator>>=(T& value) const;
+    void operator<<=(T value);
+ ...
+}
+
+typedef PVScalarValue PVBoolean;
+typedef PVScalarValue PVByte;
+...typedef PVScalarValue PVDouble;
+typedef std::tr1::shared_ptr PVBooleanPtr;
+typedef std::tr1::shared_ptr PVBytePtr;
+...
+typedef std::tr1::shared_ptr PVDoublePtr;
+
+
+// PVString is special case, since it implements SerializableArray
+class PVString : public PVScalarValue<String>, SerializableArray {
+public:
+    virtual ~PVString() {}
+ ...
+};
+ +

pvDataCPP-md

+
class PVScalar : public PVField {
+public:
+    POINTER_DEFINITIONS(PVScalar);
+    virtual ~PVScalar();
+    typedef PVScalar &reference;
+    typedef const PVScalar& const_reference;
+    const ScalarConstPtr getScalar() const ;
+
+    // not in pvDataCPP
+    template<ScalarType ID>
+    inline typename ScalarTypeTraits<ID>::type getAs() const;
+
+    virtual void getAs(void *, ScalarType) const = 0;
+    template<ScalarType ID>
+    inline void putFrom(typename ScalarTypeTraits<ID>::type val)
+
+    virtual void putFrom(const void *, ScalarType) = 0;
+    virtual void assign(const PVScalar&) = 0;
+
+ ...
+}
+
+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;
+    std::ostream& dumpValue(std::ostream& o) const
+    void operator>>=(T& value) const;
+    void operator<<=(T value);
+
+    // not in pvDataCPP
+    static const ScalarType typeCode;
+ ...
+}
+
+typedef PVScalarValue PVBoolean;
+typedef PVScalarValue PVByte;
+...typedef PVScalarValue PVDouble;
+typedef std::tr1::shared_ptr PVBooleanPtr;
+typedef std::tr1::shared_ptr PVBytePtr;
+...
+typedef std::tr1::shared_ptr PVDoublePtr;
+
+
+// PVString is special case, since it implements SerializableArray
+class PVString : public PVScalarValue<String>, SerializableArray {
+public:
+    virtual ~PVString() {}
+ ...
+};
+

proposed

+
+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;
+
+    void operator>>=(T& value) const;
+    void operator<<=(T value);
+...
+};
+typedef PVScalarValue<uint8> PVBoolean;
+typedef PVScalarValue<int8> PVByte;
+typedef PVScalarValue<double> PVDouble;
+...
+typedef std::tr1::shared_ptr<PVBoolean> PVBooleanPtr;
+typedef std::tr1::shared_ptr<PVByte> PVBytePtr;
+...
+typedef std::tr1::shared_ptr<PVDouble> PVDoublePtr;
+
+// PVString is special case, since it implements SerializableArray
+class PVString : public PVScalarValue<String>, SerializableArray {
+public:
+    virtual ~PVString() {}
+ ...
+};
+
+

PVArray

+

The Java and pvDataCPP versions differ in that Java has an interface definition +for each scalarArray type, i. e. PVBooleanArray, ..., PVStringArray, +and the CPP versions provide a template PVValueArray for the implementation.

+

+pvDataCPP-md differs from pvDataCPP in that it implements additional +methods: +

+
getAs
+
This is used to implement the Convert::toXXXArray methods. + This belongs in the Convert implementation not in PVArray.
+
putFrom
+
This is used to implement the Convert::fromXXXArray scalar methods. + This belongs in the Convert implementation not in PVArray.
+
assign
+
This does the same thing as the Convert::fromXXXArray methods except + that it does not go through Convert. + This belongs in the Convert implementation not in PVArray.
+
copyOut
+
This is used to copy data to a raw array.
+
copyIn
+
This is used to copy data in from a raw array. +
+

+

The proposed version is differs from pvJava, pvDataCPP, and pvCPP-md. +It is like the Java version if the Java get method is simplified as discussed above. +For example PVDoubleArray::get becomes: +

+    double[] get();
+
+The corresponding C++ version becomes: +
+    const svector & get();
+    const const_svector & get() const;
+
+

+

The remaining difference is that dumpValue is replaced by the stream operator<<.

+

The main difference from the pvDataJava version is that PVValueArray "wraps" shared_vector. +Thus shared_vector takes the place of the raw arrays in Java. +This allows the C++ interface to be more similar to Java.

+

The main difference from the pvDataCPP-md version is that it does not implement +the extra methods and allows +the client access to the shared_vector. +The client is then able to perform C++ specific things to the data. +BUT it also means that if the client modifies the shared_vector +the client is also responsible for ensuring that the +immutable and capacity related features of PVField and PVArray are +respected and the postPut is properly handled. +

+

Note that two get methods exist. +One allows write access to the raw data and the other doesn't/

+

pvDataJava

+
interface PVArray extends PVField, SerializableArray {
+    int getLength();
+    void setLength(int length);
+    int getCapacity();
+    void setCapacity(int length);
+    boolean isCapacityMutable();
+    void setCapacityMutable(boolean isMutable);
+}
+
+interface PVScalarArray extends PVArray {
+    ScalarArray getScalarArray();
+}
+

For each scalar type an associated array data interface is defined. Each has +a get and put method. For example:

+
public class DoubleArrayData {
+    public double[] data;
+    public int offset;
+}
+
+interface PVDoubleArray extends PVArray {
+    int get(int offset, int len, DoubleArrayData data);
+    int put(int offset,int len, double[] from, int fromOffset);
+    void shareData(double[] from);
+}
+

pvDataCPP

+
class PVArray : public PVField, public SerializableArray {
+public:
+    POINTER_DEFINITIONS(PVArray);
+    virtual ~PVArray();
+    virtual void setImmutable();
+    std::size_t getLength() const;
+    virtual void setLength(std::size_t length);
+    std::size_t getCapacity() const;
+    bool isCapacityMutable() const;
+    void setCapacityMutable(bool isMutable);
+    virtual void setCapacity(std::size_t capacity) = 0;
+    virtual std::ostream& dumpValue(std::ostream& o, std::size_t index) const = 0;
+
+ ...
+};
+
+
+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)
+    {}
+};
+
+class PVScalarArray : public PVArray {
+public:
+    POINTER_DEFINITIONS(PVScalarArray);
+    virtual ~PVScalarArray();
+    typedef PVScalarArray &reference;
+    typedef const PVScalarArray& const_reference;
+    const ScalarArrayConstPtr getScalarArray() const ;
+ ...
+}
+
+template<typename T>
+class PVValueArray : public PVScalarArray {
+public:
+    POINTER_DEFINITIONS(PVValueArray);
+    typedef T  value_type;
+    typedef T* pointer;
+    typedef const T* const_pointer;
+
+    typedef PVArrayData<T> ArrayDataType;
+    typedef std::vector<T> vector;
+    typedef const std::vector<T> const_vector;
+    typedef std::tr1::shared_ptr<vector> shared_vector;
+    typedef PVValueArray & reference;
+    typedef const PVValueArray & const_reference;
+
+    virtual ~PVValueArray() {}
+    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;
+
+...
+};
+
+/**
+ * Definitions for the various scalarArray types.
+ */
+typedef PVArrayData<uint8> BooleanArrayData;
+typedef PVValueArray<uint8> PVBooleanArray;
+typedef std::tr1::shared_ptr<PVBooleanArray> PVBooleanArrayPtr;
+...
+typedef PVArrayData<String> StringArrayData;
+typedef PVValueArray<String> PVStringArray;
+typedef std::tr1::shared_ptr<PVStringArray> PVStringArrayPtr;i
+
+ +

pvDataCPP-md

+
class PVArray : public PVField, public SerializableArray {
+public:
+    POINTER_DEFINITIONS(PVArray);
+    virtual ~PVArray();
+    virtual void setImmutable();
+    std::size_t getLength() const;
+    virtual void setLength(std::size_t length);
+    std::size_t getCapacity() const;
+    bool isCapacityMutable() const;
+    void setCapacityMutable(bool isMutable);
+    virtual void setCapacity(std::size_t capacity) = 0;
+    virtual std::ostream& dumpValue(std::ostream& o, std::size_t index) const = 0;
+ ...
+};
+
+std::ostream& operator<<(format::array_at_internal const& manip, const PVArray& array);
+
+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)
+    {}
+};
+
+class PVScalarArray : public PVArray {
+public:
+    POINTER_DEFINITIONS(PVScalarArray);
+    virtual ~PVScalarArray();
+    typedef PVScalarArray &reference;
+    typedef const PVScalarArray& const_reference;
+    const ScalarArrayConstPtr getScalarArray() const ;
+
+    // in pvDataCPP but not in pvDataCPP=md
+    //virtual std::ostream& dumpValue(std::ostream& o, size_t index) const = 0;
+
+    // not in pvDataCPP
+    template<ScalarType ID>
+    virtual void
+    getAs(shared_vector<typename ScalarTypeTraits<ID>::type>& out) const;
+
+    virtual void
+    getAs(ScalarType, shared_vector<void>& out) const = 0;
+
+    template<ScalarType ID>
+    inline size_t copyOut(typename ScalarTypeTraits<ID>::type* inp, size_t len) const;
+
+    virtual size_t copyOut(ScalarType id, void* ptr, size_t olen) const = 0;
+
+    template<ScalarType ID>
+    inline void putFrom(const shared_vector<typename ScalarTypeTraits<ID>::type>& inp);
+
+    virtual void putFrom(ScalarType, const shared_vector<void>&) = 0;
+
+    template<ScalarType ID>
+    inline void copyIn(const typename ScalarTypeTraits<ID>::type* inp, size_t len);
+
+    virtual void copyIn(ScalarType, const void*, size_t) = 0;
+
+    virtual void assign(PVScalarArray& pv) = 0;
+    
+ ...
+}
+
+template<typename T>
+class PVValueArray : public detail::PVVectorStorage {
+    typedef detail::PVVectorStorage base_t;
+public:
+    POINTER_DEFINITIONS(PVValueArray);
+    typedef T  value_type;
+    typedef T* pointer;
+    typedef const T* const_pointer;
+    typedef PVArrayData<T> ArrayDataType;
+    typedef std::vector<T> vector;
+    typedef const std::vector<T> const_vector;
+    typedef std::tr1::shared_ptr<vector> shared_vector;
+    typedef PVValueArray & reference;
+    typedef const PVValueArray & const_reference;
+
+    virtual ~PVValueArray() {}
+    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;
+
+    /// not in pvDataCPP
+    static const ScalarType typeCode;
+    typedef ::epics::pvData::shared_vector<T> svector;
+    typedef ::epics::pvData::shared_vector<const T> const_svector;
+
+     virtual void
+    getAs(ScalarType id, ::epics::pvData::shared_vector<void>& out) const;
+    virtual size_t copyOut(ScalarType id, void* ptr, size_t olen) const;
+    virtual void
+    putFrom(ScalarType id, const ::epics::pvData::shared_vector<void>& inp);
+    virtual void copyIn(ScalarType id, const void* ptr, size_t len);
+    virtual void assign(PVScalarArray& pv);
+
+
+protected:
+    PVValueArray(ScalarArrayConstPtr const & scalar)
+    : PVScalarArray(scalar) {}
+    friend class PVDataCreate;
+};
+template<typename T>
+std::size_t PVValueArray<T>::put(
+    std::size_t offset,
+    std::size_t length,
+    const_vector &from,
+    std::size_t fromOffset)
+{ return put(offset,length, &from[0], fromOffset); }
+
+/**
+ * Definitions for the various scalarArray types.
+ */
+typedef PVArrayData<uint8> BooleanArrayData;
+typedef PVValueArray<uint8> PVBooleanArray;
+typedef std::tr1::shared_ptr<PVBooleanArray> PVBooleanArrayPtr;
+...
+typedef PVArrayData<String> StringArrayData;
+typedef PVValueArray<String> PVStringArray;
+typedef std::tr1::shared_ptr<PVStringArray> PVStringArrayPtr;i
+
+

proposed

+
class PVArray : public PVField, public SerializableArray {
+public:
+    POINTER_DEFINITIONS(PVArray);
+    virtual ~PVArray();
+    virtual std::size_t getLength() const = 0;
+    virtual void setLength(std::size_t length) = 0;
+    bool isCapacityMutable() const;
+    void setCapacityMutable(bool isMutable);
+    virtual std::size_t getCapacity() const = 0;
+    virtual void setCapacity(std::size_t capacity) = 0;
+ ...
+};
+
+
+class PVScalarArray : public PVArray {
+public:
+    POINTER_DEFINITIONS(PVScalarArray);
+    typedef PVScalarArray &reference;
+    typedef const PVScalarArray& const_reference;
+
+    virtual ~PVScalarArray();
+    const ScalarArrayConstPtr getScalarArray() const;
+ ...
+};
+
+template<typename T>
+class PVValueArray : public PVScalarArray
+{
+public:
+    POINTER_DEFINITIONS(PVValueArray);
+    typedef T  value_type;
+    typedef T* pointer;
+    typedef const T* const_pointer;
+    typedef PVValueArray & reference;
+    typedef const PVValueArray & const_reference;
+
+    typedef shared_vector<T> svector;
+    typedef shared_vector<const T> const_svector;
+
+    virtual ~PVValueArray() {}
+    const svector & get() ;
+    const const_svector &get() const;
+    size_t put(size_t offset,size_t length, const_pointer from, size_t fromOffset);
+
+    void shareData(const svector &from);
+
+...
+};
+
+typedef PVValueArray<uint8> PVBooleanArray;
+typedef std::tr1::shared_ptr<PVBooleanArray> PVBooleanArrayPtr;
+...
+typedef PVValueArray<String> PVStringArray;
+typedef std::tr1::shared_ptr<PVStringArray> PVStringArrayPtr;
+
+ + + +

pvDataApp/pv

+

pvData.h

+

This provides the interface for network accessible data. +Although templates are used to minimize the amount of code, +the interface is not meant to be extended. +Only the types defined by pvIntrospect are implemented.

+ +

PVField

+
+class PVField
+: virtual public Serializable,
+  public std::tr1::enable_shared_from_this
+{
+public:
+    POINTER_DEFINITIONS(PVField);
+    virtual ~PVField();
+    virtual void message(String message,MessageType messageType);
+    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;
+    PVAuxInfoPtr & getPVAuxInfo();
+    bool isImmutable() const;
+    void setImmutable();
+    const FieldConstPtr & getField() const;
+    PVStructure * getParent() const;
+    void replacePVField(const PVFieldPtr&  newPVField);
+    void renameField(String const & newName);
+    void postPut();
+    void setPostHandler(PostHandlerPtr const &postHandler);
+    virtual bool equals(PVField &pv);
+    void toString(StringBuilder buf) ;
+    void toString(StringBuilder buf,int indentLevel);
+    std::ostream& operator<<(std::ostream& o) const;
+...
+};
+
+std::ostream& operator<<(std::ostream& o, const PVFieldPtr & f);
+std::ostream& operator<<(std::ostream& o, const PVFieldPtr & f, size_t index);
+
+

The public methods for PVField are:

+
+
~PVField
+
Destructor. Since shared pointers are used it should never be called by + user code.
+
message
+
Code attached to this field can call this method to report + problems.
+
getFieldName
+
Get the field name. If the field is a top level structure the field + name will be an empty string.
+
setRequester
+
Sets a requester to be called when message or getRequesterName are + called. This is only legal for the top level PVField.
+
getFieldOffset
+
Get offset of the PVField field within top level structure. Every field + within the PVStructure has a unique offset. The top level structure has + an offset of 0. The first field within the structure has offset equal to + 1. The other offsets are determined by recursively traversing each + structure of the tree.
+
getNextFieldOffset
+
Get the next offset. If the field is a scalar or array field then this + is just offset + 1. If the field is a structure it is the offset of the + next field after this structure. Thus (nextOffset - offset) is always + equal to the total number of fields within the field.
+
getNumberFields
+
Get the total number of fields in this field. This is nextFieldOffset - + fieldOffset.
+
getPVAuxInfo
+
Get the PVAuxInfo for this field. PVAuxInfo is described below.
+
isImmutable
+
Is the field immutable?
+
setImmutable
+
Make the field immutable. Once a field is immutable it can never be + changed since there is no method to again make it mutable. This is an + important design decision since it allows immutable array fields to share + the internal primitive data array.
+
getField
+
Get the reflection interface for the data.
+
getParent
+
Get the interface for the parent or null if this is the top level + PVStructure.
+
replacePVField
+
Replace the data implementation for the field.
+
renameField
+
Rename the field name.
+
postPut
+
If a postHandler is registered it is called otherwise no action is + taken.
+
setPostHandler
+
Set the postHandler for the record. Only a single handler can be + registered.
+
operator<<
+
Stream output +
+

PVScalar

+
+class PVScalar : public PVField {
+public:
+    POINTER_DEFINITIONS(PVScalar);
+    virtual ~PVScalar();
+
+    typedef PVScalar &reference;
+    typedef const PVScalar& const_reference;
+
+    const ScalarConstPtr getScalar() const;
+...
+};
+
+

where

+
+
getScalar
+
Get the introspection interface for the PVScalar.
+
+ +

PVScalarValue

+
+template
+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;
+    void operator>>=(T& value) const;
+    void operator<<=(T value);
+...
+};
+typedef PVScalarValue<uint8> PVBoolean;
+typedef PVScalarValue<int8> PVByte;
+typedef PVScalarValue<int16> PVShort;
+typedef PVScalarValue<int32> PVInt;
+typedef PVScalarValue<int64> PVLong;
+typedef PVScalarValue<uint8> PVUByte;
+typedef PVScalarValue<uint16> PVUShort;
+typedef PVScalarValue<uint32> PVUInt;
+typedef PVScalarValue<uint64> PVULong;
+typedef PVScalarValue<float> PVFloat;
+typedef PVScalarValue<double> PVDouble;
+typedef std::tr1::shared_ptr<PVBoolean> PVBooleanPtr;
+typedef std::tr1::shared_ptr<PVByte> PVBytePtr;
+typedef std::tr1::shared_ptr<PVShort> PVShortPtr;
+typedef std::tr1::shared_ptr<PVInt> PVIntPtr;
+typedef std::tr1::shared_ptr<PVLong> PVLongPtr;
+typedef std::tr1::shared_ptr<PVUByte> PVUBytePtr;
+typedef std::tr1::shared_ptr<PVUShort> PVUShortPtr;
+typedef std::tr1::shared_ptr<PVUInt> PVUIntPtr;
+typedef std::tr1::shared_ptr<PVULong> PVULongPtr;
+typedef std::tr1::shared_ptr<PVFloat> PVFloatPtr;
+typedef std::tr1::shared_ptr<PVDouble> PVDoublePtr;
+
+// PVString is special case, since it implements SerializableArray
+class PVString : public PVScalarValue<String>, SerializableArray {
+public:
+    virtual ~PVString() {}
+ ...
+};
+
+ +

where

+
+
get
+
Get the value stored in the object.
+
put
+
Change the value stored in the object.
+
operator<<
+
operator>>
+
Methods for stream I/O.
+
+ + +

PVArray

+ +

PVArray is the base interface for all the other PV Array interfaces. It +extends PVField and provides the additional methods:

+
class PVArray : public PVField, public SerializableArray {
+public:
+    POINTER_DEFINITIONS(PVArray);
+    virtual ~PVArray();
+    virtual std::size_t getLength() const = 0;
+    virtual void setLength(std::size_t length) = 0;
+    bool isCapacityMutable() const;
+    void setCapacityMutable(bool isMutable);
+    virtual std::size_t getCapacity() const = 0;
+    virtual void setCapacity(std::size_t capacity) = 0;
+ ...
+};
+
+
getLength
+
Get the current length. This is less than or equal to the capacity.
+
setLength
+
Set the length. If the PVField is not mutable then an exception is + thrown. If this is greater than the capacity setCapacity is called.
+
isCapacityMutable
+
Is the capacity mutable
+
setCapacityMutable
+
Specify if the capacity can be changed.
+
getCapacity
+
Get the capacity, i.e. this is the size of the underlying data + array.
+
setCapacity
+
Set the capacity. The semantics are implementation dependent but + typical semantics are as follows: If the capacity is not mutable an + exception is thrown. A new data array is created and data is copied from + the old array to the new array.
+
+ + +

PVScalarArray

+ +

PVScalarArray is the base class for scalar array data. PVValueArray is a +templete for the various scalar array data classes. There is a class for each +possible scalar type, i. e. PVBooleanArray, ..., PVStringArray.

+
class PVScalarArray : public PVArray {
+public:
+    POINTER_DEFINITIONS(PVScalarArray);
+    typedef PVScalarArray &reference;
+    typedef const PVScalarArray& const_reference;
+
+    virtual ~PVScalarArray();
+    const ScalarArrayConstPtr getScalarArray() const;
+ ...
+};
+
+ +

where

+
+
getScalarArray
+
Get the introspection interface.
+
+ +

PVValueArray

+ +

This is a template class plus instances for PVBooleanArray, ..., +PVStringArray.

+
template<typename T>
+class PVValueArray : public PVScalarArray {
+public:
+    POINTER_DEFINITIONS(PVValueArray);
+    typedef T  value_type;
+    typedef T* pointer;
+    typedef const T* const_pointer;
+    typedef PVValueArray & reference;
+    typedef const PVValueArray & const_reference;
+
+    typedef shared_vector<T> svector;
+    typedef shared_vector<const T> const_svector;
+
+    virtual ~PVValueArray() {}
+    const svector & get() ;
+    const const_svector &get() const;
+    size_t put(size_t offset,size_t length, const_pointer from, size_t fromOffset);
+
+    void shareData(const svector &from);
+...
+};
+
+typedef PVValueArray<uint8> PVBooleanArray;
+typedef std::tr1::shared_ptr<PVBooleanArray> PVBooleanArrayPtr;
+
+typedef PVValueArray<int8> PVByteArray;
+typedef std::tr1::shared_ptr<PVByteArray> PVByteArrayPtr;
+
+typedef PVValueArray<int16> PVShortArray;
+typedef std::tr1::shared_ptr<PVShortArray> PVShortArrayPtr;
+
+typedef PVValueArray<int32> PVIntArray;
+typedef std::tr1::shared_ptr<PVIntArray> PVIntArrayPtr;
+
+typedef PVValueArray<int64> PVLongArray;
+typedef std::tr1::shared_ptr<PVLongArray> PVLongArrayPtr;
+
+typedef PVValueArray<uint8> PVUByteArray;
+typedef std::tr1::shared_ptr<PVUByteArray> PVUByteArrayPtr;
+
+typedef PVValueArray<uint16> PVUShortArray;
+typedef std::tr1::shared_ptr<PVUShortArray> PVUShortArrayPtr;
+
+typedef PVValueArray<uint32> PVUIntArray;
+typedef std::tr1::shared_ptr<PVUIntArray> PVUIntArrayPtr;
+
+typedef PVValueArray<uint64> PVULongArray;
+typedef std::tr1::shared_ptr<PVULongArray> PVULongArrayPtr;
+
+typedef PVValueArray<float> PVFloatArray;
+typedef std::tr1::shared_ptr<PVFloatArray> PVFloatArrayPtr;
+
+typedef PVValueArray<double> PVDoubleArray;
+typedef std::tr1::shared_ptr<PVDoubleArray> PVDoubleArrayPtr;
+
+typedef PVValueArray<String> PVStringArray;
+typedef std::tr1::shared_ptr<PVStringArray> PVStringArrayPtr;
+
+ +

where

+
+
get
+
Get the shared_vector that holds the data. + Code that calls this is able to modify the array elements + but should be very careful if it does. + For example it must call postPut after modifying the array elements. + It must also respect isImmutable(). +
+
size_t put(size_t offset,size_t length, const_pointer from, size_t fromOffset);
+
put
+
This is the recommended method for modifying the array elements. + It may change the capacity if len asks for more elements + than the cureent capacity allows. + It does not change the current length. +
+
shareData
+
Share data with an existing shared_vector. + Note that if capacity is ever changed then data will no + longer be shared. + This method can also be called to force the PVValueArray to have a new + raw array. This is usefull for implementing Copy On Write. +
+
+ +

shared_vector

+

Status

+

I think that all public components of sharedVector.h +are now documented, but not all have a description or example. +Thus the documentation needs more work. +

+

When NOTE EXISTING appears it means that there is a question about +the existing shared_vector implementation.

+

Introduction

+

A shared_vector is a container as defined by the C++ standard library. +It is like std::vector but provides two additional features +1) shared raw array and 2) a window into the raw array.

+

To support these two features a shared_vector keeps the following +private data: +

+
m_data
+
This is a std::tr1::shared_ptr for the actual data array. +
+
m_offset
+
This is the offset of the first element seen by the window.
+
m_count
+
This is the size, i. e. total number of elements, seen by the window.
+
m_total
+
This is the number of elements between offset and the end of the array referenced + by m_data.
+
+Note that only m_data is shared. Thus each shared_vector has it's own window.

+

The following subsections are organized as follows: +

+
shared_vector example
+
The example code is based on a shared_vector<int32> + This subsection show the C++ definitions that are assumed by + the example code. + The source that contains the example code will be part + of this project but not yet.
+
std::vector compatible subsections
+
The types and methods that have the same names as std::vector.
+
share_vector specific
+
The methods that are not part of std::vector.
+

+

The subsections that are compatible with std::vector are organized +and start with a brief summary modeled after Section 31.3(STL Containers) in:
+"The C++ Programming Language, C++11, Fourth Edition", Bjarne Stroustrup,2013
+The subsection names are the same names that Stroustrup uses. +Each subsection starts with a brief summary that is similar to +the summary Stroustrup has at the beginnining of each subsection.

+

The comparison is always with std::vector. +In addition it shows what is defined by by std::vector but not by +shared_vector.

+

Someone who already understand the C++ STL can understand shared_vector +by just looking at the brief summarys. +For others the brief summary is followed by tutorial information. +

+

shared_vector example

+

The examples all assume that the following has been defined:

+
+typedef shared_vector<int32> Int32Array;
+...
+static void dumpArray(String const &message,Int32Array const& int32Array);
+
+

The following: +

+Int32Array int32Array(5);
+dumpArray("example",int32Array);
+
+creates a shared vector that holds an array of five elements where each element is a +32 bit signed integer. +The call to dumpArray displays the message and the array elements on standard out: +
+example 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+

+

exampleSharedVector is a main program that has the code for the +examples shown below.

+

Member Types

+

Brief Summary +

+value_type              Type of element
+size_type               Unsigned type of subscripts, element counts, etc.
+difference_type         Signed type of difference between iterators
+iterator                Behaves like value_type*
+const_iterator          Behaves like const value_type*
+reverse_iterator        Behaves like value_type*
+const_reverse_iterator  Behaves like const value_type*
+reference               value_types&
+const_reference         const_value_type&
+pointer                 Behaves like value_type *
+const_pointer           Behaves like const value_type*
+//not part of std::vector
+element_type            same as value_type
+shared_pointer_type     std::tr1::shared_ptr<value_type>
+// defined by std::vector but not by shared_vector
+allocator_type
+
+

+

+The typedefs are compatible with the STL container member types. +These define types for various types of variables that belong to a container +or are used to access a container.

+

value_type, reference, and const_reference

+

These three typedefs define the same types as the equivalent types for +an element of the shared_vector. +

+Int32Array::value_type value;
+//is the same as
+int32 value;
+
+Int32Array::reference rvalue = value;
+//is the same as
+int32 & rvalue = value;
+
+Int32Array::const_reference rvalue = value;
+//is the same as
+const int32 & rvalue = value;
+
+

+

pointer and const_pointer

+

The following is an example of code that uses the +pointer typedef:

+
+Int32Array int32Array(5);
+Int32Array::pointer pint32Array = int32Array.data();
+size_t len = int32Array.size();
+for(size_t i=0; i<len; ++i) pint32Array[i] = i;
+
+

A const_pointer is like a pointer except that only read access to the array elements +is allowed.

+

NOTE: data The above code is better implemented as:

+
+Int32Array int32Array(5);
+size_t len = int32Array.size();
+for(size_t i=0; i<len; ++i) int32Array[i] = i;
+
+ +

difference_type

+

This is used to get the number of elements between two elements. +For example:

+
+Int32Array::difference_type pdiff = int32Array[3] - int32Array[1];
+// pdiff will have the value 2
+
+

element_type and shared_pointer_type

+

These are member types defined by std::tr1::shared_ptr. +These are not used by any of the client methods.

+ +

Constructors, Destructor, and Assignments

+

Brief Summary +

+C c();         Default constructor; c is empty.
+C c(n);        c is initialized with n elementis with the value value_type{};
+               offset is 0; size is n;
+C c(n,e);      Initialize c with n copies of e.
+               offset is 0; size is n;
+
+C c(c);        Copy an existing shared_vector of the same type.
+               offset and taken same as v.
+               shared_ptr is copied; not the raw array
+C operator=(c) Assignment constructor.
+               shared_ptr is copied; not the raw array
+C c(c,o,n);    Copy an existing std::tr1::shared_ptr<value_type>
+               offset is o; size is c;
+C c(r,o,n);    Use an existing raw pointer.
+               default deleter use "delete[]" to delete.
+               offset is o; size is c;
+C c(r,d,o,n);  Use an existing raw pointer and deleter d;
+               offset is o; size is c;
+
+not implemented
+~C()           The C++ default destructor is used.
+C++11 specific
+&& constructor move constructor
+{} constructor uniform initializer constructor
+
+where +
+
C
+
The class name, e. g. shared_vector<int32>
+
c
+
shared_vector instance
+
n
+
size, i. e. the number of elements
+
o
+
offset
+
e
+
element instance
+
r
+
raw pointer, e. g. int32 *
+
d
+
a deleter, i. e. object that destroys the raw array.
+
+

+

Construct by creating new raw array

+
+shared_vector();
+shared_vector(size_t n);
+shared_vector(size_t n, value_type e);
+
+

The first three constructors all create a new shared_vector +by also creating a new raw array, +The difference is the size of the array, i.e. how many elements it contains, +and how the elements are initalized. +

+
+
shared_vector()
+
The array is empty, i.e. it has no elements.
+
shared_vector(size_t n)
+
The array has n elements. Each element is initialized +by the default constructor for the element type. +For numeric elements, like int32, this means 0.
+
shared_vector(size_t n, value_type e)
+
The array has n elements. +Each element has the initial value e. +
+
+

The following: +

+    cout << "***exampleConstructors***" << endl;
+    Int32Array emptyArray();
+    Int32Array zeroArray(16);
+    int32 value = 1;
+    Int32Array oneArray(8, value);
+    dumpArray("emptyArray",emptyArray);
+    dumpArray("zeroArray",zeroArray);
+    dumpArray("oneArray",oneArray);
+
+produces +
+***exampleConstructors***
+emptyArray 1
+zeroArray {16}[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...]
+oneArray {8}[1, 1, 1, 1, 1, 1, 1, 1]
+
+

NOTE EXISTING: Why did emptyArray disply the above. +Should it be "emptyArray {0} []"? +

+

Construct by sharing raw array from a shared_vector

+
+shared_vector(const shared_vector& o);
+shared_vector_base& operator=(const shared_vector_base& o);
+
+

These create a vector by coping the contents of an existing shared_vector +of the same type into the newly created vector. +Note that the complete raw array is not copied but just the std::tr1:: shared_ptr +that holds the array.

+

The following: +

+    cout << "***exampleCopyConstructors***" << endl;
+    size_t max = 16;
+    Int32Array int32Array(max);
+    for(size_t i=0; i<max; ++i) int32Array[i] = i+1;
+    Int32Array xxx(int32Array);    //copy constructor
+    Int32Array yyy = int32Array;   //copy assignment
+    cout << "dataPtr int32Array " << int32Array.dataPtr();
+    cout << " xxx " << xxx.dataPtr();
+    cout << " yyy " << yyy.dataPtr() << endl;
+    dumpArray("int32Array",emptyArray);
+    dumpArray("xxx",emptyArray);
+    dumpArray("yyy",emptyArray);
+
+produces +
+***exampleConstructors***
+dataPtr int32Array 0x136ea90 xxx 0x136ea90 yyy 0x136ea90
+int32Array {16}[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ...]
+xxx {16}[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ...]
+yyy {16}[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ...]
+
+

Construct by wrapping an existing raw array

+
+shared_vector(A v, size_t o, size_t c)
+shared_vector(A d, B b, size_t o, size_t c)
+
+

NOTE EXISTING: Are these constructors necessary? +If code wants to wrap an existing raw array then +a std::tr1::shared_ptr can first be created +and the constructor in the next section can be called.

+

These "wrap" an existing raw pointer. +They allows access to a sub-array starting at offset o> +and has size c +The second provides a destructor and the first has a default deleter.

+

The default deleter does the following: +When the shared_vector is deleted, i. e. when no code references it, +the statement "delete[] a;" is executed.

+

An example of wrapping a raw array without using these constructors is:

+
+class Int32ArrayDeleter
+{
+//Note that this an example that does nothing.
+//But it could have private data
+public:
+     Int32ArrayDeleter() {}
+     virtual ~Int32ArrayDeleter() {}
+     void operator()(int32* a){
+         // MUST HANDLE DELETION
+         // default is "delete[] a;"
+     }
+};
+...
+int32 *pother; // something managed by other code
+size_t capacity; // size of array managed by other code
+
+Int32Array int32Array(pother,int32array_deleter,0,capacity);
+
+

This is used to wrap arrays that are managed by other +code. This should only be used if You understand the other code +and know what your deleter has to do. +An example, exampleShareRawArray, gives a more complete example. +

+ +

Create a shared_vector from an existing shared_ptr

+
+shared_vector(const std::tr1::shared_ptr<E1>& d, size_t o, size_t c)
+
+

This creates a vector from an existing smart pointer. +Thus the vector will share reference counting with the existing smart +pointer. This is useful for creating "windows" into the array +that the smart pointer references.

+ + + +

Create a shared_vector from an existing shared_vector

+
+ template<typename E1>
+    shared_vector(const shared_vector<E1>& o) :base_t(o) {}
+
+

NOTE EXISTING: I do not understand how this works or what it does.

+

This create a vector by coping the contents of an existing shared_vector +of the same or a different but related type +into the newly created vector. +This constructor creates a new raw array and copies the elements from +the existing array to the new array.

+ +

Size and Capacity

+

Brief Summary +

+size()      Return the number of elements in the window
+empty()     Is the window empty? this means shared_ptr is empty
+max_size()  The maximum possible number of elements.
+capacity()  The number of possible elements without re-allocating raw array.
+reserve(n)  Reserve at least n elements in raw array; May cause reallocation.
+resize(n)   Change size to n; May cause reallocation
+clear()     shared_ptr is reset, Window will be empty.
+
+not implemented
+resize(n,v)
+shrink_to_fit()
+

+

Details +

+size_t size() const;
+bool empty() const;
+size_t max_size() const;
+size_t capacity() const;
+void reserve(size_t n);
+void resize(size_t n);
+void clear();
+
+

+
+
size
+
The current number of elements in the window.
+
empty
+
(true,false) if size is (0,>0)
+
max_size
+
Maximum possible number of elements. +NOTE EXISTING; Should be ((size_t)-1)/sizeof(T) +
+
capacity
+
The maximum size the window can be without reallocating raw array
+
reserve
+
Set the maximum number of element that the window can see. + If the caller is the only user of the window and the number + of elements specified does not cause the number of elements to change + then this method just returns. + In all other cases a new raw array is allocated.

+
resize
+
Change the window size: may cause a reallocation of the raw array.
+
clear
+
If the shared_vector is not already empty the shared_ptr will + be reset. The new size will be 0.
+
+

The following: +

+static void exampleSizeEtc()
+{
+    cout << "***exampleSizeEtc***" << endl;
+    size_t max = 16;
+    Int32Array int32Array(max);
+    size_t capacity = int32Array.capacity();
+    size_t size = int32Array.size();
+    bool empty = int32Array.empty();
+    size_t max_size = int32Array.max_size();
+    cout<< "capacity" << capacity;
+    cout<< " size " << size;
+    cout<< " empty " << (empty ? true : false) ;
+    cout<< " max_size " << max_size << endl;
+}
+
+
+produces: +
+***exampleSizeEtc***
+capacity16 size 16 empty 0 max_size 18446744073709551615
+
+

+

Iterators

+

Brief Summary +

+begin()      First element
+end()        One past last element
+cbegin()     Constant first element
+cend()       Constant last element
+rbegin()     First element of reverse sequence
+rend()       One past last element of reverse sequence
+crbegin()    Constant first element of reverse sequence
+crend()      Constant last element of reverse sequence
+

+

+shared_vector supports both iterators and reverse iterators as defined by the STL. +For both constant iterators are also defined. +A constant iterator does not allow an array elemnent to be modified.

+

The following is an example of a constant iterator.

+
+int32 sum = 0;
+for(Int32Array::const_iterator iter=int32Array.begin(); iter<int32Array.end(); ++iter )
+{
+     sum += *iter;
+}
+
+

The following is an example of a non constant iterator.

+
+int32 value = 0;
+for(Int32Array::iterator iter=int32Array.begin(); iter<int32Array.end(); ++iter )
+{
+     *iter += ++value;
+}
+
+

Element Access

+

Brief Summary +

+operator[i]    random element access 
+data()         return the raw array
+
+implemented by std::vector but not implemented
+front()
+back()
+at()
+

+

Note that: +

+Int32Array::pointer pint32= int32Array.data();
+
+is guaranteed to be the same as +
+int32 * pint32 = int32Array.data();
+
+

+

NOTE EXISTING: data() should be defined to return a const_pointer. +It is currently defined to return a plain pointer.

+

Stack Operations

+

Brief Summary +

+push_back(x)     Add an element after the last element
+pop_back(x)      Remove the last element.
+

+

List operations

+

shared_vector does not support the standard list operations like: +

+implemented by std::vector but not by shared_vector
+
+insert(p,x)   Add x before p
+...
+
+

+

Other Operations

+

Brief Summary +

+operator==       Do all elements of both containers compare equal.
+operator!=       Does any element not compare equal.
+operator<<       ostream operator
+swap(c2)         Swap the contents of two shared_vectors of the same type.
+swap(c1,c2)      Swap the contents of two shared_vectors of the same type.
+
+not implemented
+operator<
+operator<=
+operator>
+operator>=
+

+

operators equals, not equals, and ostream

+
+template<typename A, typename B>
+bool operator==(const epics::pvData::shared_vector<A>& a,
+                const epics::pvData::shared_vector<B>& b);
+
+template<typename A, typename B>
+bool operator!=(const epics::pvData::shared_vector<A>& a,
+                const epics::pvData::shared_vector<B>& b);
+
+template<typename E>
+std::ostream& operator<<(
+    std::ostream& strm, const epics::pvData::shared_vector<E>& arr);
+
+
+

swap

+

Swap the contents of two shared_vectors. The following code: +

+    cout << "***exampleSwap***" << endl;
+    Int32Array first(8);
+    Int32Array second(16);
+    cout << " before swap  size ";
+    cout<< "first " << first.size() << " second " << second.size() << endl;
+    first.swap(second);
+    cout << " after swap   size ";
+    cout<< "first " << first.size() << " second " << second.size() << endl;
+    swap(first,second);
+    cout << " swap again   size ";
+    cout<< "first " << first.size() << " second " << second.size() << endl;
+
+produces: +
+***exampleSwap***
+ before swap  size first 8 second 16
+ after swap   size first 16 second 8
+ swap again   size first 8 second 16
+

+ +

shared_vector specific operations

+

Brief Summary +

+void make_unique()         Make caller the only user of std::tr1::shared_ptr
+bool unique()              Is the caller the only user of std::tr1::shared_ptr
+void slice(offset,length)  Change window offset andsize
+
+// following should only be used for debugging
+const std::tr1::shared_ptr<E>&
+       dataPtr()           Return const  shared_ptr
+size_t dataOffset()        Return offset.
+size_t dataCount()         Return count which is also the size
+size_t dataTotal()         Return total number of elements between
+                           offset and end of the raw array
+
+// following converts from type FROM to type TO
+shared_vector static_shared_vector_cast(const shared_vector<FROM>& src);
+
+// following casts from const Type to Type
+shared_vector
+const_shared_vector_cast(const shared_vector<const TYPE>& src)
+

+

NOTE EXISTING: The C++ standard library considers a slice to be every nth element +of some part of an array, i. e., slice has arguments (offset,length,stride). +shared_vector only has offset and length. +Perhaps it should have another name like rewindow. +

make_unique and unique

+
+void make_unique();
+bool unique() const;
+
+
+
make_unique
+
Makes sure that caller is the only user of this standard_vector. + If the caller is not already the only user a new raw array is allocated.
+
unique
+
+ Returns (true,false) if there is only one user of the shared_vector. +
+
+

slice

+
+void slice(size_t offset, size_t length=(size_t)-1);
+
+

This modifies the "window" into the raw array starting at offset and of +the specified length. The offset and length are forced to be +within the raw array. +Note that this method never reallocates the underlying raw array. +

+

The following code: +

+static void exampleSlice()
+{
+    cout << "***exampleSlice***" << endl;
+    size_t max = 16;
+    Int32Array int32Array(max);
+    int32 value = 0;
+    for(Int32Array::iterator iter = int32Array.begin(); iter!=int32Array.end(); ++iter)
+    {
+        *iter = ++value;
+    }
+    dumpArray("int32Array",int32Array);
+    size_t offset = 0;
+    size_t length = 8;
+    Int32Array window1(int32Array);
+    window1.slice(offset,length);
+    dumpArray("window1",window1);
+    offset = 8;
+    length = 8;
+    Int32Array window2(int32Array);
+    window2.slice(offset,length);
+    dumpArray("window2",window2);
+    offset = 2;
+    length = 4;
+    Int32Array window3(window2);
+    window3.slice(offset,length);
+    dumpArray("window3",window3);
+}
+
+produces the following output: +
+***exampleSlice***
+int32Array 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+window1 1 2 3 4 5 6 7 8
+window2 9 10 11 12 13 14 15 16
+window3 11 12 13 14
+
+

dataPtr, dataOffset, dataCount, and dataTotal

+
+
dataPtr
+
Returns the shared_ptr that holds the raw array. +
+
dataOffset
+
Offset in the data array of first element
+
dataCount
+
Number of visible elements. + Same as size. +
+
dataTotal
+
Total number of elements between m_offset and the end of data. + Same as capacity. +
+
+

The following: +

+static void exampleDataEtc()
+{
+    cout << "***exampleDataEtc***" << endl;
+    size_t max = 16;
+    Int32Array int32Array(max);
+    long use_count = int32Array.dataPtr().use_count();
+    long offset = int32Array.dataOffset();
+    long count = int32Array.dataCount();
+    long total = int32Array.dataTotal();
+    cout << "use_count " << use_count;
+    cout << " offset " << offset;
+    cout << " count " << count;
+    cout << " total " <<  total << endl;
+}
+
+produces: +
+***exampleDataEtc***
+use_count 1 offset 0 count 16 total 16
+
+

+ +

static_shared_vector_cast

+

Not yet documented

+ +

const_shared_vector_cast

+

Not yet documented

+ +

specialization for untyped pointers

+

Not yet documented

+ + +
+ + diff --git a/documentation/pvDataDiscussion.html b/documentation/pvDataDiscussion.html new file mode 100644 index 0000000..08a1e45 --- /dev/null +++ b/documentation/pvDataDiscussion.html @@ -0,0 +1,792 @@ + + + + + + EPICS pvDataDiscussion + + + + + + + + +
+

EPICS pvDataDiscussion

+ + +

EPICS v4 Working Group, Working Draft, 03-Jul-2013

+ +
+
Latest version:
+
pvDataDiscussion.html +
+
This version:
+
none
+
Previous version:
+
None
+
Editors:
+
Marty Kraimer, BNL
+
+ + +
+
+ + +
+

Table of Contents

+
+
+ + +

Introduction

+

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: +

pvData (Process Variable Data) defines and implements an efficent +way to store, access, and communicate memory resident data structures.
+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. +

+

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.

+

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.

+

There are methods regarding immutability: setImmutable, isImmutablei, setCapacityMutable, and isCapacityMutable. +Should they exists? For now lets assume no. +

+

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.

+

This document will first describe changes to the existing Java interfaces +and then the corresponding C++ API.

+

Java API

+

The following shows which methods will be removed from the existing interfaces +and what will be added. +The methods to be removed are in red +and methods to add are in blue +Also the removed methods are at the end with a comment above. +The new methods also have a comment. +

+

Introspection Interfaces

+ +
interface Field extends Serializable {
+    String getId();
+    Type getType();
+    // following will be removed
+    void toString(StringBuilder buf);
+    void toString(StringBuilder buf,int indentLevel);
+    String toString();
+}
+
+
+// new interface
+interface FieldToString {
+    String toString(Field field);
+}
+
+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
+    Structure appendField(Structure structure,String fieldName, Field field);
+    Structure appendFields(Structure structure,String[] fieldNames, Field[] fields);
+}
+
+

Data Interfaces

+
+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
+    PVAuxInfo getPVAuxInfo();
+    boolean isImmutable();
+    void setImmutable();
+    void renameField(String newName);
+    void toString(StringBuilder buf);
+    void toString(StringBuilder buf,int indentLevel);
+    String toString();
+}
+
+
+// The following is a new interface
+interface PVFieldToString {
+    String toString(PVField pvField);
+    void setMaxInitialArrayElements(int num);
+    void setMaxFinalArrayElements(int num);
+    int getMaxInitialArrayElements();
+    int getMaxFinalArrayElements();
+}
+    
+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
+    boolean isCapacityMutable();
+    void setCapacityMutable(boolean isMutable);
+}
+
+interface PVScalarArray extends PVArray {
+    ScalarArray getScalarArray();
+}
+
+
+//following will be removed
+public class DoubleArrayData {
+    public double[] data;
+    public int offset;
+}
+
+interface PVDoubleArray extends PVArray {
+    // following are new
+    double[] get();
+    void swap(double[] value);
+    //following will be removed
+    int get(int offset, int len, DoubleArrayData data);
+    int put(int offset,int len, double[] from, int fromOffset);
+    void shareData(double[] from);
+}
+
+// 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
+    void appendPVField(String fieldName,PVField pvField);
+    void appendPVFields(String[] fieldNames,PVField[] pvFields);
+    void removePVField(String fieldName);
+    void replacePVField(PVField oldPVField,PVField newPVField);
+    String getExtendsStructureName();
+    boolean putExtendsStructureName(String extendsStructureName);
+    public boolean checkValid();
+}
+ 
+
+//following will be removed
+public class StructureArrayData {
+    public PVStructure[] data;
+    public int offset;
+}
+
+
+interface PVStructureArray extends PVArray{
+    StructureArray getStructureArray();
+    // following are new
+    PVStructure[] get();
+    void swap(PVStructure[] value);
+    // following will be removed
+    int get(int offset, int length, StructureArrayData data);
+    int put(int offset,int length, PVStructure[] from, int fromOffset);
+    void shareData(PVStructure[] from);
+}
+
+
+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
+    PVField[] flattenPVStructure(PVStructure pvStructure);
+}
+
+

PVFieldToString

+

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.

+

For C++ this can be a replacement for dumpValue.

+

PVBooleanArray, ..., PVStructureArray

+

The old get and put are replaced by two new and simpler methods: +

+
get
+
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 +
swap
+
This exchanges the old raw data with the new raw data.
+
+

+

+The method setCapacity 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. +

+

C++ API

+

The C++ class definitions are similar to the Java definitions with two main exceptions: +

+
toString
+
In c++ this is replaced by std::ostream.
+
raw array data
+
Java supports array data like double[] + The C++ replacement is shared_vector<double>, which is implemented + in pvDataCPP-md.
+

Introspection Interfaces

+ +
+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;
+    
+    // following will be removed
+    virtual void toString(StringBuilder buf) const{toString(buf,0);}
+    virtual void toString(StringBuilder buf,int indentLevel) const;
+    
+ ...
+};
+
+// new function
+std::ostream &toString(Field::const_reference field, std::ostream& o);
+
+
+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);
+    
+    // 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;
+    
+ ...
+};
+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);
+    
+    // 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;
+    
+ ...
+};
+
+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);
+    
+    // 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;
+   
+ ...
+};
+
+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);
+    
+    // following will be removed
+    virtual void toString(StringBuilder buf,int indentLevel=0) const;
+    virtual String getID() const;
+    
+ ...
+};
+
+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;
+    
+    // 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;
+    
+ ...
+};
+
+extern FieldCreatePtr getFieldCreate();
+ 
+

Data Interfaces

+
+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
+    
+   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;
+   
+ ...
+};
+
+
+// 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();
+...
+}
+
+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;
+    
+    // following will be removed
+    std::ostream& dumpValue(std::ostream& o)
+    void operator>>=(T& value) const;
+    void operator<<=(T value);
+    
+ ...
+}
+
+// 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;
+    
+    // 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;
+    
+ ...
+};
+
+class PVScalarArray : public PVArray {
+public:
+    POINTER_DEFINITIONS(PVScalarArray);
+    virtual ~PVScalarArray();
+    typedef PVScalarArray &reference;
+    typedef const PVScalarArray& const_reference;
+
+    const ScalarArrayConstPtr getScalarArray() const ;
+    
+    // following will be removed
+    virtual std::ostream& dumpValue(std::ostream& o, size_t index) const = 0;
+    
+ ...
+}
+
+
+// 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)
+    {}
+};
+
+
+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
+    typedef shared_vector<T> svector;
+    typedef shared_vector<const T> const_svector; 
+
+    virtual ~PVValueArray() {}
+    // following are added
+    svector get();
+    void swap(svector& value);
+    
+    // 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;
+    
+...
+};
+
+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);
+    
+    // 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);
+    
+};
+
+
+// following will be removed
+typedef PVArrayData<PVStructurePtr> StructureArrayData;
+
+
+class PVStructureArray : public PVArray
+{
+public:
+    POINTER_DEFINITIONS(PVStructureArray);
+    typedef PVStructurePtr  value_type;
+    typedef PVStructurePtr* pointer;
+    typedef const PVStructurePtr* const_pointer;
+    
+    // following are new typeDefs
+    typedef shared_vector<PVStructurePtr> svector;
+    typedef shared_vector<const PVStructurePtr> const_svector;
+    
+
+    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
+    svector get();
+    void swap(svector & value);
+    
+    // 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;}
+    
+ ...
+};
+
+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();
+
+ + +
+ + diff --git a/pvDataApp/Makefile b/pvDataApp/Makefile index 0acf9b9..3e78645 100644 --- a/pvDataApp/Makefile +++ b/pvDataApp/Makefile @@ -24,6 +24,10 @@ INC += destroyable.h INC += status.h INC += sharedPtr.h INC += localStaticLock.h +INC += typeCast.h +INC += printer.h +INC += sharedVector.h +INC += templateMeta.h LIBSRCS += byteBuffer.cpp LIBSRCS += bitSet.cpp @@ -37,6 +41,8 @@ LIBSRCS += timer.cpp LIBSRCS += status.cpp LIBSRCS += messageQueue.cpp LIBSRCS += localStaticLock.cpp +LIBSRCS += typeCast.cpp +LIBSRCS += parseToPOD.cpp SRC_DIRS += $(PVDATA)/pv @@ -64,6 +70,7 @@ LIBSRCS += Convert.cpp LIBSRCS += Compare.cpp LIBSRCS += StandardField.cpp LIBSRCS += StandardPVField.cpp +LIBSRCS += printer.cpp SRC_DIRS += $(PVDATA)/property diff --git a/pvDataApp/factory/Compare.cpp b/pvDataApp/factory/Compare.cpp index 9830478..f6780dc 100644 --- a/pvDataApp/factory/Compare.cpp +++ b/pvDataApp/factory/Compare.cpp @@ -15,13 +15,6 @@ namespace epics { namespace pvData { -// PVXXX object comparison - -bool operator==(PVField& left, PVField& right) -{ - return getConvert()->equals(left,right); -} - // Introspection object comparision /** Field equality conditions: @@ -101,8 +94,142 @@ bool operator==(const StructureArray& a, const StructureArray& b) return *(a.getStructure().get())==*(b.getStructure().get()); } -namespace nconvert { +// PVXXX object comparison -} // namespace nconvert +namespace { + +// fully typed comparisons + +template +bool compareScalar(const PVScalarValue* left, const PVScalarValue* right) +{ + return left->get()==right->get(); +} + +template +bool compareArray(const PVValueArray* left, const PVValueArray* right) +{ + typename PVValueArray::const_svector lhs(left->view()), rhs(right->view()); + return std::equal(lhs.begin(), lhs.end(), rhs.begin()); +} + +// partially typed comparisons + +bool compareField(const PVScalar* left, const PVScalar* right) +{ + ScalarType lht = left->getScalar()->getScalarType(); + if(lht != right->getScalar()->getScalarType()) + return false; + switch(lht) { +#define OP(ENUM, TYPE) case ENUM: return compareScalar(static_cast*>(left), static_cast*>(right)) + OP(pvBoolean, uint8); + OP(pvUByte, uint8); + OP(pvByte, int8); + OP(pvUShort, uint16); + OP(pvShort, int16); + OP(pvUInt, uint32); + OP(pvInt, int32); + OP(pvULong, uint64); + OP(pvLong, int64); + OP(pvFloat, float); + OP(pvDouble, double); +#undef OP + case pvString: { + const PVString *a=static_cast(left), *b=static_cast(right); + return a->get()==b->get(); + } + } + throw std::logic_error("PVScalar with invalid scalar type!"); +} + +bool compareField(const PVScalarArray* left, const PVScalarArray* right) +{ + ScalarType lht = left->getScalarArray()->getElementType(); + if(lht != right->getScalarArray()->getElementType()) + return false; + + if(left->getLength()!=right->getLength()) + return false; + + switch(lht) { +#define OP(ENUM, TYPE) case ENUM: return compareArray(static_cast*>(left), static_cast*>(right)) + OP(pvBoolean, uint8); + OP(pvUByte, uint8); + OP(pvByte, int8); + OP(pvUShort, uint16); + OP(pvShort, int16); + OP(pvUInt, uint32); + OP(pvInt, int32); + OP(pvULong, uint64); + OP(pvLong, int64); + OP(pvFloat, float); + OP(pvDouble, double); + OP(pvString, String); +#undef OP + } + throw std::logic_error("PVScalarArray with invalid element type!"); +} + +bool compareField(const PVStructure* left, const PVStructure* right) +{ + StructureConstPtr ls = left->getStructure(); + + if(*ls!=*right->getStructure()) + return false; + + const PVFieldPtrArray& lf = left->getPVFields(); + const PVFieldPtrArray& rf = right->getPVFields(); + + for(size_t i=0, nfld=ls->getNumberFields(); igetStructureArray()->getStructure() + != *right->getStructureArray()->getStructure()) + return false; + + PVStructureArray::const_svector ld=left->view(), rd=right->view(); + + if(ld.size()!=rd.size()) + return false; + + PVStructureArray::const_svector::const_iterator lit, lend, rit; + + for(lit=ld.begin(), lend=ld.end(), rit=rd.begin(); + lit!=lend; + ++lit, ++rit) + { + if(**lit != **rit) + return false; + } + return true; +} + +} // end namespace + +// untyped comparison + +bool operator==(const PVField& left, const PVField& right) +{ + if(&left == &right) + return true; + + Type lht = left.getField()->getType(); + if(lht != right.getField()->getType()) + return false; + + switch(lht) { + case scalar: return compareField(static_cast(&left), static_cast(&right)); + case scalarArray: return compareField(static_cast(&left), static_cast(&right)); + case structure: return compareField(static_cast(&left), static_cast(&right)); + case structureArray: return compareField(static_cast(&left), static_cast(&right)); + } + throw std::logic_error("PVField with invalid type!"); +} }} // namespace epics::pvData diff --git a/pvDataApp/factory/Convert.cpp b/pvDataApp/factory/Convert.cpp index 40aa52a..627c062 100644 --- a/pvDataApp/factory/Convert.cpp +++ b/pvDataApp/factory/Convert.cpp @@ -16,6 +16,7 @@ #include #include #include +#include using std::tr1::static_pointer_cast; using std::size_t; @@ -23,373 +24,6 @@ using std::size_t; namespace epics { namespace pvData { -static void newLineImpl(StringBuilder buffer, int indentLevel) -{ - *buffer += "\n"; - for(int i=0; i -T toScalar(PVScalarPtr const &pv) -{ - ScalarConstPtr scalar = pv->getScalar(); - ScalarType scalarType = scalar->getScalarType(); - switch(scalarType) { - case pvBoolean: - throw std::logic_error(String("boolean can not be converted to scalar")); - case pvByte: { - PVBytePtr value = static_pointer_cast(pv); - return value->get(); - } - case pvShort: { - PVShortPtr value = static_pointer_cast(pv); - return value->get(); - } - case pvInt: { - PVIntPtr value = static_pointer_cast(pv); - return value->get(); - } - case pvLong: { - PVLongPtr value = static_pointer_cast(pv); - return value->get(); - } - case pvUByte: { - PVUBytePtr value = static_pointer_cast(pv); - return value->get(); - } - case pvUShort: { - PVUShortPtr value = static_pointer_cast(pv); - return value->get(); - } - case pvUInt: { - PVUIntPtr value = static_pointer_cast(pv); - return value->get(); - } - case pvULong: { - PVULongPtr value = static_pointer_cast(pv); - return value->get(); - } - case pvFloat: { - PVFloatPtr value = static_pointer_cast(pv); - return static_cast(value->get()); - } - case pvDouble: { - PVDoublePtr value = static_pointer_cast(pv); - return static_cast(value->get()); - } - case pvString: - throw std::logic_error(String("string can not be converted to byte")); - } - throw std::logic_error("Logic error. Should never get here."); -} - -int8 Convert::toByte(PVScalarPtr const & pv) -{ - return toScalar(pv); -} - -int16 Convert::toShort(PVScalarPtr const & pv) -{ - return toScalar(pv); -} - -int32 Convert::toInt(PVScalarPtr const & pv) -{ - return toScalar(pv); -} - -int64 Convert::toLong(PVScalarPtr const & pv) -{ - return toScalar(pv); -} - -uint8 Convert::toUByte(PVScalarPtr const & pv) -{ - return toScalar(pv); -} - -uint16 Convert::toUShort(PVScalarPtr const & pv) -{ - return toScalar(pv); -} - -uint32 Convert::toUInt(PVScalarPtr const & pv) -{ - return toScalar(pv); -} - -uint64 Convert::toULong(PVScalarPtr const &pv) -{ - return toScalar(pv); -} - -float Convert::toFloat(PVScalarPtr const &pv) -{ - return toScalar(pv); -} - -double Convert::toDouble(PVScalarPtr const & pv) -{ - return toScalar(pv); -} - -template -String scalarToString(T); - -template<> -String scalarToString(int8 value) -{ - char buffer[20]; - int ival = value; - sprintf(buffer,"%d",ival); - return String(buffer); -} - -template<> -String scalarToString(int16 value) -{ - char buffer[20]; - int ival = value; - sprintf(buffer,"%d",ival); - return String(buffer); -} - -template<> -String scalarToString(int32 value) -{ - char buffer[20]; - int ival = value; - sprintf(buffer,"%d",ival); - return String(buffer); -} - -template<> -String scalarToString(int64 value) -{ - char buffer[30]; - sprintf(buffer,"%lld",(long long)value); - return String(buffer); -} - -template<> -String scalarToString(uint8 value) -{ - char buffer[20]; - unsigned int ival = value; - sprintf(buffer,"%ud",ival); - return String(buffer); -} - -template<> -String scalarToString(uint16 value) -{ - char buffer[20]; - unsigned int ival = value; - sprintf(buffer,"%iud",ival); - return String(buffer); -} - -template<> -String scalarToString(uint32 value) -{ - char buffer[20]; - sprintf(buffer,"%ud",(unsigned int)value); - return String(buffer); -} - -template<> -String scalarToString(uint64 value) -{ - char buffer[30]; - sprintf(buffer,"%llu",(unsigned long long)value); - return String(buffer); -} - -template<> -String scalarToString(float value) -{ - char buffer[40]; - sprintf(buffer,"%g",value); - return String(buffer); -} - -template<> -String scalarToString(double value) -{ - char buffer[40]; - sprintf(buffer,"%g",value); - return String(buffer); -} - -template -void fromScalar(PVScalarPtr const &pv,T from) -{ - ScalarConstPtr scalar = pv->getScalar(); - ScalarType scalarType = scalar->getScalarType(); - switch(scalarType) { - case pvBoolean: - throw std::logic_error("byte can not be converted to boolean"); - case pvByte: { - PVBytePtr value = static_pointer_cast(pv); - value->put(static_cast(from)); return; - } - case pvShort: { - PVShortPtr value = static_pointer_cast(pv); - value->put(static_cast(from)); return; - } - case pvInt: { - PVIntPtr value = static_pointer_cast(pv); - value->put(static_cast(from)); return; - } - case pvLong: { - PVLongPtr value = static_pointer_cast(pv); - value->put(static_cast(from)); return; - } - case pvUByte: { - PVUBytePtr value = static_pointer_cast(pv); - value->put(static_cast(from)); return; - } - case pvUShort: { - PVUShortPtr value = static_pointer_cast(pv); - value->put(static_cast(from)); return; - } - case pvUInt: { - PVUIntPtr value = static_pointer_cast(pv); - value->put(static_cast(from)); return; - } - case pvULong: { - PVULongPtr value = static_pointer_cast(pv); - value->put(static_cast(from)); return; - } - case pvFloat: { - PVFloatPtr value = static_pointer_cast(pv); - value->put(static_cast(from)); return; - } - case pvDouble: { - PVDoublePtr value = static_pointer_cast(pv); - value->put(static_cast(from)); return; - } - case pvString: { - PVStringPtr pvvalue = static_pointer_cast(pv); - String value = scalarToString(from); - pvvalue->put(value); - return; - } - } - throw std::logic_error("Logic error. Should never get here."); -} - -void Convert::fromByte(PVScalarPtr const &pv,int8 from) -{ - fromScalar(pv,from); -} - -void Convert::fromShort(PVScalarPtr const &pv,int16 from) -{ - fromScalar(pv,from); -} - -void Convert::fromInt(PVScalarPtr const &pv, int32 from) -{ - fromScalar(pv,from); -} - -void Convert::fromLong(PVScalarPtr const &pv, int64 from) -{ - fromScalar(pv,from); -} - -void Convert::fromUByte(PVScalarPtr const &pv,uint8 from) -{ - fromScalar(pv,from); -} - -void Convert::fromUShort(PVScalarPtr const &pv,uint16 from) -{ - fromScalar(pv,from); -} - -void Convert::fromUInt(PVScalarPtr const &pv, uint32 from) -{ - fromScalar(pv,from); -} - -void Convert::fromULong(PVScalarPtr const &pv, uint64 from) -{ - fromScalar(pv,from); -} - -void Convert::fromFloat(PVScalarPtr const &pv, float from) -{ - fromScalar(pv,from); -} - -void Convert::fromDouble(PVScalarPtr const &pv, double from) -{ - fromScalar(pv,from); -} - - -static bool convertEquals(PVField *a,PVField *b); -static size_t convertFromByteArray(PVScalarArray * pv, size_t offset, - size_t len,const int8 from[], size_t fromOffset); -static size_t convertToByteArray(PVScalarArray *pv, size_t offset, - size_t len,int8 to[], size_t toOffset); -static size_t convertFromShortArray(PVScalarArray *pv, size_t offset, - size_t len,const int16 from[], size_t fromOffset); -static size_t convertToShortArray(PVScalarArray *pv, size_t offset, - size_t len,int16 to[], size_t toOffset); -static size_t convertFromIntArray(PVScalarArray *pv, size_t offset, - size_t len,const int32 from[], size_t fromOffset); -static size_t convertToIntArray(PVScalarArray *pv, size_t offset, - size_t len,int32 to[], size_t toOffset); -static size_t convertFromLongArray(PVScalarArray *pv, size_t offset, - size_t len,const int64 from[], size_t fromOffset); -static size_t convertToLongArray(PVScalarArray * pv, size_t offset, - size_t len,int64 to[], size_t toOffset); -static size_t convertFromUByteArray(PVScalarArray * pv, size_t offset, - size_t len,const uint8 from[], size_t fromOffset); -static size_t convertToUByteArray(PVScalarArray *pv, size_t offset, - size_t len,uint8 to[], size_t toOffset); -static size_t convertFromUShortArray(PVScalarArray *pv, size_t offset, - size_t len,const uint16 from[], size_t fromOffset); -static size_t convertToUShortArray(PVScalarArray *pv, size_t offset, - size_t len,uint16 to[], size_t toOffset); -static size_t convertFromUIntArray(PVScalarArray *pv, size_t offset, - size_t len,const uint32 from[], size_t fromOffset); -static size_t convertToUIntArray(PVScalarArray *pv, size_t offset, - size_t len,uint32 to[], size_t toOffset); -static size_t convertFromULongArray(PVScalarArray *pv, size_t offset, - size_t len,const uint64 from[], size_t fromOffset); -static size_t convertToULongArray(PVScalarArray * pv, size_t offset, - size_t len,uint64 to[], size_t toOffset); -static size_t convertFromFloatArray(PVScalarArray *pv, size_t offset, - size_t len,const float from[], size_t fromOffset); -static size_t convertToFloatArray(PVScalarArray * pv, size_t offset, - size_t len,float to[], size_t toOffset); -static size_t convertFromDoubleArray(PVScalarArray *pv, size_t offset, - size_t len,const double from[], size_t fromOffset); -static size_t convertToDoubleArray(PVScalarArray *pv, size_t offset, - size_t len,double to[], size_t toOffset); -static size_t convertFromStringArray(PVScalarArray *pv, size_t offset, - size_t len,const StringArray & from, size_t fromOffset); -static size_t convertToStringArray(PVScalarArray *pv, size_t offset, - size_t len,StringArray & to, size_t toOffset); - -static void convertToString(StringBuilder buffer, - PVField const *pv,int indentLevel); -static void convertStructure(StringBuilder buffer, - PVStructure const *data,int indentLevel); -static void convertArray(StringBuilder buffer, - PVScalarArray const* pv,int indentLevel); -static void convertStructureArray(StringBuilder buffer, - PVStructureArray const * pvdata,int indentLevel); -static size_t copyArrayDataReference(PVScalarArray *from,PVArray *to); -static size_t copyNumericArray(PVScalarArray *from, - size_t offset, PVScalarArray *to, size_t toOffset, size_t len); - -static std::vector split(String commaSeparatedList); - static std::vector split(String commaSeparatedList) { String::size_type numValues = 1; String::size_type index=0; @@ -409,62 +43,17 @@ static std::vector split(String commaSeparatedList) { } return valueList; } - -Convert::Convert() -: pvDataCreate(getPVDataCreate()), - trueString("true"), - falseString("false"), - illegalScalarType("Illegal ScalarType") -{} - - - -Convert::~Convert(){} - -void Convert::getFullName(StringBuilder buf,PVFieldPtr const & pvField) -{ - buf->empty(); - *buf += pvField->getFieldName(); - PVStructure *parent; - while((parent=pvField->getParent())!=0) { - parent = pvField->getParent(); - String name = parent->getFieldName(); - if(name.length()>0) { - buf->insert(0,"."); - buf->insert(0,name); - } - } -} - -bool Convert::equals(PVFieldPtr const &a,PVFieldPtr const &b) -{ - return convertEquals(a.get(),b.get()); -} - -bool Convert::equals(PVField &a,PVField &b) -{ - return convertEquals(&a,&b); -} - -void Convert::getString(StringBuilder buf,PVFieldPtr const & pvField,int indentLevel) -{ - convertToString(buf,pvField.get(),indentLevel); -} - -void Convert::getString(StringBuilder buf,PVFieldPtr const & pvField) -{ - convertToString(buf,pvField.get(),0); -} void Convert::getString(StringBuilder buf,PVField const *pvField,int indentLevel) { - convertToString(buf,pvField,indentLevel); + // TODO indextLevel ignored + std::ostringstream strm; + PrinterPlain p; + p.setStream(strm); + p.print(*pvField); + strm.str().swap(*buf); } -void Convert::getString(StringBuilder buf,PVField const *pvField) -{ - convertToString(buf,pvField,0); -} size_t Convert::fromString(PVStructurePtr const &pvStructure, StringArray const & from, size_t fromStartIndex) { @@ -506,137 +95,57 @@ size_t Convert::fromString(PVStructurePtr const &pvStructure, StringArray const return processed; } - -void Convert::fromString(PVScalarPtr const &pvScalar, String const & from) -{ - ScalarConstPtr scalar = pvScalar->getScalar(); - ScalarType scalarType = scalar->getScalarType(); - switch(scalarType) { - case pvBoolean: { - PVBooleanPtr pv = static_pointer_cast(pvScalar); - bool value = - ((from.compare("true")==0) ? true : false); - pv->put(value); - return; - } - case pvByte : { - PVBytePtr pv = static_pointer_cast(pvScalar); - int ival; - sscanf(from.c_str(),"%d",&ival); - int8 value = ival; - pv->put(value); - return; - } - case pvShort : { - PVShortPtr pv = static_pointer_cast(pvScalar); - int ival; - sscanf(from.c_str(),"%d",&ival); - int16 value = ival; - pv->put(value); - return; - } - case pvInt : { - PVIntPtr pv = static_pointer_cast(pvScalar); - int ival; - sscanf(from.c_str(),"%d",&ival); - int32 value = ival; - pv->put(value); - return; - } - case pvLong : { - PVLongPtr pv = static_pointer_cast(pvScalar); - int64 ival; - sscanf(from.c_str(),"%lld",(long long *)&ival); - int64 value = ival; - pv->put(value); - return; - } - case pvUByte : { - PVUBytePtr pv = static_pointer_cast(pvScalar); - unsigned int ival; - sscanf(from.c_str(),"%u",&ival); - uint8 value = ival; - pv->put(value); - return; - } - case pvUShort : { - PVUShortPtr pv = static_pointer_cast(pvScalar); - unsigned int ival; - sscanf(from.c_str(),"%u",&ival); - uint16 value = ival; - pv->put(value); - return; - } - case pvUInt : { - PVUIntPtr pv = static_pointer_cast(pvScalar); - unsigned int ival; - sscanf(from.c_str(),"%u",&ival); - uint32 value = ival; - pv->put(value); - return; - } - case pvULong : { - PVULongPtr pv = static_pointer_cast(pvScalar); - unsigned long long ival; - sscanf(from.c_str(),"%llu",(long long unsigned int *)&ival); - uint64 value = ival; - pv->put(value); - return; - } - case pvFloat : { - PVFloatPtr pv = static_pointer_cast(pvScalar); - float value; - sscanf(from.c_str(),"%f",&value); - pv->put(value); - return; - } - case pvDouble : { - PVDoublePtr pv = static_pointer_cast(pvScalar); - double value; - sscanf(from.c_str(),"%lf",&value); - pv->put(value); - return; - } - case pvString: { - PVStringPtr value = static_pointer_cast(pvScalar); - value->put(from); - return; - } - } - String message("Convert::fromString unknown scalarType "); - ScalarTypeFunc::toString(&message,scalarType); - throw std::logic_error(message); -} - 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 valueList = split(from); + std::vector valueList(split(from)); size_t length = valueList.size(); - StringArray valueArray = StringArray(length); - for(size_t i=0; isetLength(length); return length; } -size_t Convert::fromStringArray(PVScalarArrayPtr const &pv, size_t offset, size_t length, - StringArray const & from, size_t fromOffset) +size_t Convert::fromStringArray(PVScalarArrayPtr const &pv, + size_t offset, size_t length, + StringArray const & from, + size_t fromOffset) { - return convertFromStringArray(pv.get(),offset,length,from,fromOffset); + size_t alen = pv->getLength(); + + if(offset==0 && length>=alen) { + // replace all existing elements + assert(from.size()>=fromOffset+length); + + PVStringArray::svector data(length); + std::copy(from.begin()+fromOffset, + from.begin()+fromOffset+length, + data.begin()); + + PVStringArray::const_svector temp(freeze(data)); + pv->putFrom(temp); + return length; + + } else { + // partial update. + throw std::runtime_error("fromStringArray: partial update not implemented"); + } } -size_t Convert::toStringArray(PVScalarArrayPtr const & pv, size_t offset, size_t length, - StringArray &to, size_t toOffset) +size_t Convert::toStringArray(PVScalarArrayPtr const & pv, + size_t offset, size_t length, + StringArray &to, size_t toOffset) { - return convertToStringArray(pv.get(),offset,length,to,toOffset); + PVStringArray::const_svector data; + pv->getAs(data); + data.slice(offset, length); + if(toOffset+data.size() > to.size()) + to.resize(toOffset+data.size()); + std::copy(data.begin()+toOffset, data.end(), to.begin()); + return data.size(); } bool Convert::isCopyCompatible(FieldConstPtr const &from, FieldConstPtr const &to) @@ -686,8 +195,7 @@ void Convert::copy(PVFieldPtr const & from, PVFieldPtr const & to) { PVScalarArrayPtr fromArray = static_pointer_cast(from); PVScalarArrayPtr toArray = static_pointer_cast(to); - size_t length = copyScalarArray(fromArray,0,toArray,0,fromArray->getLength()); - if(toArray->getLength()!=length) toArray->setLength(length); + toArray->assign(*fromArray.get()); return; } case structure: @@ -726,98 +234,7 @@ void Convert::copyScalar(PVScalarPtr const & from, PVScalarPtr const & to) String message("Convert.copyScalar destination is immutable"); throw std::invalid_argument(message); } - ScalarType fromType = from->getScalar()->getScalarType(); - ScalarType toType = to->getScalar()->getScalarType(); - switch(fromType) { - case pvBoolean: { - if(toType!=pvBoolean) { - if(toType!=pvString) { - String message("Convert.copyScalar arguments are not compatible"); - throw std::invalid_argument(message); - } - } - PVBooleanPtr data = static_pointer_cast(from); - if(toType==pvString) { - PVStringPtr dataTo = static_pointer_cast(to); - String buf(""); - data->toString(&buf); - dataTo->put(buf); - } else { - bool value = data->get(); - PVBooleanPtr dataTo = static_pointer_cast(to); - dataTo->put(value); - } - return; - } - case pvByte : { - PVBytePtr data = static_pointer_cast(from); - int8 value = data->get(); - fromByte(to,value); - return; - } - case pvShort : { - PVShortPtr data = static_pointer_cast(from); - int16 value = data->get(); - fromShort(to,value); - return; - } - case pvInt :{ - PVIntPtr data = static_pointer_cast(from); - int32 value = data->get(); - fromInt(to,value); - return; - } - case pvLong : { - PVLongPtr data = static_pointer_cast(from); - int64 value = data->get(); - fromLong(to,value); - return; - } - case pvUByte : { - PVUBytePtr data = static_pointer_cast(from); - uint8 value = data->get(); - fromUByte(to,value); - return; - } - case pvUShort : { - PVUShortPtr data = static_pointer_cast(from); - uint16 value = data->get(); - fromUShort(to,value); - return; - } - case pvUInt :{ - PVUIntPtr data = static_pointer_cast(from); - uint32 value = data->get(); - fromUInt(to,value); - return; - } - case pvULong : { - PVULongPtr data = static_pointer_cast(from); - uint64 value = data->get(); - fromULong(to,value); - return; - } - case pvFloat : { - PVFloatPtr data = static_pointer_cast(from); - float value = data->get(); - fromFloat(to,value); - return; - } - case pvDouble : { - PVDoublePtr data = static_pointer_cast(from); - double value = data->get(); - fromDouble(to,value); - return; - } - case pvString: { - PVStringPtr data = static_pointer_cast(from); - String value = data->get(); - fromString(to,value); - return; - } - } - String message("Convert::copyScalar should never get here"); - throw std::logic_error(message); + to->assign(*from.get()); } bool Convert::isCopyScalarArrayCompatible(ScalarArrayConstPtr const &fromArray, @@ -833,99 +250,6 @@ bool Convert::isCopyScalarArrayCompatible(ScalarArrayConstPtr const &fromArray, return false; } -size_t Convert::copyScalarArray(PVScalarArrayPtr const & from, size_t offset, - PVScalarArrayPtr const & to, size_t toOffset, size_t length) -{ - - if(to->isImmutable()) { - if(from==to) return from->getLength(); - String message("Convert.copyArray destination is immutable"); - throw std::invalid_argument(message); - } - ScalarType fromElementType = from->getScalarArray()->getElementType(); - ScalarType toElementType = to->getScalarArray()->getElementType(); - - if(from->isImmutable() && (fromElementType==toElementType)) { - if(offset==0 && toOffset==0 && length==from->getLength()) { - return copyArrayDataReference(from.get(),to.get()); - } - } - - size_t ncopy = 0; - if(ScalarTypeFunc::isNumeric(fromElementType) - && ScalarTypeFunc::isNumeric(toElementType)) { - return copyNumericArray(from.get(),offset,to.get(),toOffset,length); - } else if(toElementType==pvBoolean && fromElementType==pvBoolean) { - PVBooleanArray *pvfrom = static_cast(from.get()); - PVBooleanArray *pvto = static_cast(to.get()); - while(length>0) { - size_t num = 0; - size_t fromOffset = 0; - BooleanArrayData booleanArrayData; - num = pvfrom->get(offset,length,booleanArrayData); - boolean * data = pvfrom->get(); - fromOffset = booleanArrayData.offset; - if(num<=0) return ncopy; - while(num>0) { - size_t n = pvto->put(toOffset,num,data,fromOffset); - if(n<=0) return ncopy; - length -= n; num -= n; ncopy+=n; offset += n; toOffset += n; - } - } - return ncopy; - } else if(toElementType==pvString && fromElementType==pvString) { - PVStringArray *pvfrom = static_cast(from.get()); - PVStringArray *pvto = static_cast(to.get()); - while(length>0) { - size_t num = 0; - String *data; - size_t fromOffset = 0; - StringArrayData stringArrayData; - num = pvfrom->get(offset,length,stringArrayData); - data = pvfrom->get(); - fromOffset = stringArrayData.offset; - if(num<=0) return ncopy; - while(num>0) { - size_t n = pvto->put(toOffset,num,data,fromOffset); - if(n<=0) return ncopy; - length -= n; num -= n; ncopy+=n; offset += n; toOffset += n; - } - } - return ncopy; - } else if(toElementType==pvString) { - PVStringArray *pvto = static_cast(to.get()); - ncopy = from->getLength(); - if(ncopy>length) ncopy = length; - size_t num = ncopy; - StringArray toData(1); - while(num>0) { - toStringArray(from,offset,1,toData,0); - if(pvto->put(toOffset,1,&toData[0],0)<=0) break; - num--; offset++; toOffset++; - } - return ncopy; - } else if(fromElementType==pvString) { - PVStringArray *pvfrom = static_cast(from.get()); - while(length>0) { - size_t num = 0; - size_t fromOffset = 0; - StringArrayData stringArrayData; - num = pvfrom->get(offset,length,stringArrayData); - StringArray const & data = stringArrayData.data; - fromOffset = stringArrayData.offset; - if(num<=0) return ncopy; - while(num>0) { - size_t n = fromStringArray(to,toOffset,num,data,fromOffset); - if(n<=0) return ncopy; - length -= n; num -= n; ncopy+=n; offset += n; toOffset += n; - } - } - return ncopy; - } - String message("Convert::copyScalarArray should not get here"); - throw std::logic_error(message); -} - bool Convert::isCopyStructureCompatible( StructureConstPtr const &fromStruct, StructureConstPtr const &toStruct) { @@ -977,8 +301,7 @@ void Convert::copyStructure(PVStructurePtr const & from, PVStructurePtr const & { if(to->isImmutable()) { if(from==to) return; - String message("Convert.copyStructure destination is immutable"); - throw std::invalid_argument(message); + throw std::invalid_argument("Convert.copyStructure destination is immutable"); } if(from==to) return; PVFieldPtrArray const & fromDatas = from->getPVFields(); @@ -1005,7 +328,7 @@ void Convert::copyStructure(PVStructurePtr const & from, PVStructurePtr const & && (pvArray->getScalarArray()->getElementType()==pvString)) { PVScalarArrayPtr toArray = static_pointer_cast(toDatas[1]); - copyScalarArray(pvArray,0,toArray,0,pvArray->getLength()); + toArray->assign(*pvArray.get()); PVScalarPtr toScalar = static_pointer_cast(toDatas[0]); copyScalar(pvScalar,toScalar); return; @@ -1022,6 +345,10 @@ void Convert::copyStructure(PVStructurePtr const & from, PVStructurePtr const & 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: { @@ -1034,9 +361,7 @@ void Convert::copyStructure(PVStructurePtr const & from, PVStructurePtr const & { PVScalarArrayPtr fromArray = static_pointer_cast(fromData); PVScalarArrayPtr toArray = static_pointer_cast(toData); - size_t length = copyScalarArray( - fromArray,0,toArray,0,fromArray->getLength()); - if(toArray->getLength()!=length) toArray->setLength(length); + toArray->assign(*fromArray.get()); break; } case structure: @@ -1070,2250 +395,18 @@ bool Convert::isCopyStructureArrayCompatible( void Convert::copyStructureArray( PVStructureArrayPtr const & from, PVStructureArrayPtr const & to) { - if(to->isImmutable()) { - if(from==to) return; - String message("Convert.copyStructureArray destination is immutable"); - throw std::invalid_argument(message); + if(from==to) { + return; + } else if(to->isImmutable()) { + throw std::invalid_argument("Convert.copyStructureArray destination is immutable"); } - to->put(0,from->getLength(),from->getVector(),0); -} - -String Convert::toString(PVScalarPtr const & pv) -{ - static String trueString("true"); - static String falseString("false"); - - ScalarConstPtr scalar = pv->getScalar(); - ScalarType scalarType = scalar->getScalarType(); - switch(scalarType) { - case pvBoolean: { - PVBooleanPtr pvalue = static_pointer_cast(pv); - boolean value = pvalue->get(); - return value ? trueString : falseString; - } - case pvByte: { - PVBytePtr value = static_pointer_cast(pv); - char buffer[30]; - sprintf(buffer,"%d",(int)value->get()); - return String(buffer); - } - case pvShort: { - PVShortPtr value = static_pointer_cast(pv); - char buffer[30]; - sprintf(buffer,"%d",(int)value->get()); - return String(buffer); - } - case pvInt: { - PVIntPtr value = static_pointer_cast(pv); - char buffer[30]; - sprintf(buffer,"%d",(int)value->get()); - return String(buffer); - } - case pvLong: { - PVLongPtr value = static_pointer_cast(pv); - char buffer[30]; - sprintf(buffer,"%lli",(long long int)value->get()); - return String(buffer); - } - case pvUByte: { - PVUBytePtr value = static_pointer_cast(pv); - char buffer[30]; - sprintf(buffer,"%u",(unsigned int)value->get()); - return String(buffer); - } - case pvUShort: { - PVUShortPtr value = static_pointer_cast(pv); - char buffer[30]; - sprintf(buffer,"%u",(unsigned int)value->get()); - return String(buffer); - } - case pvUInt: { - PVUIntPtr value = static_pointer_cast(pv); - char buffer[30]; - sprintf(buffer,"%u",(unsigned int)value->get()); - return String(buffer); - } - case pvULong: { - PVULongPtr value = static_pointer_cast(pv); - char buffer[30]; - sprintf(buffer,"%llu",(unsigned long long int)value->get()); - return String(buffer); - } - case pvFloat: { - PVFloatPtr value = static_pointer_cast(pv); - char buffer[30]; - sprintf(buffer,"%g",value->get()); - return String(buffer); - } - case pvDouble: { - PVDoublePtr value = static_pointer_cast(pv); - char buffer[30]; - sprintf(buffer,"%g",value->get()); - return String(buffer); - } - case pvString: { - PVStringPtr value = static_pointer_cast(pv); - return value->get(); - } - } - throw std::logic_error("Logic error. Should never get here."); -} - -size_t Convert::toByteArray(PVScalarArrayPtr const &pv, size_t offset, size_t length, - int8 to[], size_t toOffset) -{ - return convertToByteArray(pv.get(), offset, length, to, toOffset); -} - -size_t Convert::toShortArray(PVScalarArrayPtr const &pv, size_t offset, size_t length, - int16 to[], size_t toOffset) -{ - return convertToShortArray(pv.get(), offset, length, to, toOffset); -} - -size_t Convert::toIntArray(PVScalarArrayPtr const &pv, size_t offset, size_t length, - int32 to[], size_t toOffset) -{ - return convertToIntArray(pv.get(), offset, length, to, toOffset); -} - -size_t Convert::toLongArray(PVScalarArrayPtr const &pv, size_t offset, size_t length, - int64 to[], size_t toOffset) -{ - return convertToLongArray(pv.get(), offset, length, to, toOffset); -} - -size_t Convert::toUByteArray(PVScalarArrayPtr const &pv, size_t offset, size_t length, - uint8 to[], size_t toOffset) -{ - return convertToUByteArray(pv.get(), offset, length, to, toOffset); -} - -size_t Convert::toUShortArray(PVScalarArrayPtr const &pv, size_t offset, size_t length, - uint16 to[], size_t toOffset) -{ - return convertToUShortArray(pv.get(), offset, length, to, toOffset); -} - -size_t Convert::toUIntArray(PVScalarArrayPtr const &pv, size_t offset, size_t length, - uint32 to[], size_t toOffset) -{ - return convertToUIntArray(pv.get(), offset, length, to, toOffset); -} - -size_t Convert::toULongArray(PVScalarArrayPtr const &pv, size_t offset, size_t length, - uint64 to[], size_t toOffset) -{ - return convertToULongArray(pv.get(), offset, length, to, toOffset); -} - -size_t Convert::toFloatArray(PVScalarArrayPtr const &pv, size_t offset, size_t length, - float to[], size_t toOffset) -{ - return convertToFloatArray(pv.get(), offset, length, to, toOffset); -} - -size_t Convert::toDoubleArray(PVScalarArrayPtr const &pv, size_t offset, size_t length, - double to[], size_t toOffset) -{ - return convertToDoubleArray(pv.get(), offset, length, to, toOffset); -} - -size_t Convert::fromByteArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const int8 from[], size_t fromOffset) -{ - return convertFromByteArray(pv.get(), offset, length, from, fromOffset); -} - -size_t Convert::fromByteArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const ByteArray & from, size_t fromOffset) -{ - return convertFromByteArray(pv.get(), offset, length, get(from), fromOffset); -} - -size_t Convert::fromShortArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const int16 from[], size_t fromOffset) -{ - return convertFromShortArray(pv.get(), offset, length, from, fromOffset); -} - -size_t Convert::fromShortArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const ShortArray & from, size_t fromOffset) -{ - return convertFromShortArray(pv.get(), offset, length, get(from), fromOffset); -} - -size_t Convert::fromIntArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const int32 from[], size_t fromOffset) -{ - return convertFromIntArray(pv.get(), offset, length, from, fromOffset); -} - -size_t Convert::fromIntArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const IntArray & from, size_t fromOffset) -{ - return convertFromIntArray(pv.get(), offset, length, get(from), fromOffset); -} - -size_t Convert::fromLongArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const int64 from[], size_t fromOffset) -{ - return convertFromLongArray(pv.get(), offset, length, from, fromOffset); -} - -size_t Convert::fromLongArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const LongArray & from, size_t fromOffset) -{ - return convertFromLongArray(pv.get(), offset, length, get(from), fromOffset); -} - -size_t Convert::fromUByteArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const uint8 from[], size_t fromOffset) -{ - return convertFromUByteArray(pv.get(), offset, length, from, fromOffset); -} - -size_t Convert::fromUByteArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const UByteArray & from, size_t fromOffset) -{ - return convertFromUByteArray(pv.get(), offset, length, get(from), fromOffset); -} - -size_t Convert::fromUShortArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const uint16 from[], size_t fromOffset) -{ - return convertFromUShortArray(pv.get(), offset, length, from, fromOffset); -} - -size_t Convert::fromUShortArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const UShortArray &from, size_t fromOffset) -{ - return convertFromUShortArray(pv.get(), offset, length, get(from), fromOffset); -} - -size_t Convert::fromUIntArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const uint32 from[], size_t fromOffset) -{ - return convertFromUIntArray(pv.get(), offset, length, from, fromOffset); -} - -size_t Convert::fromUIntArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const UIntArray & from, size_t fromOffset) -{ - return convertFromUIntArray(pv.get(), offset, length, get(from), fromOffset); -} - -size_t Convert::fromULongArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const uint64 from[], size_t fromOffset) -{ - return convertFromULongArray(pv.get(), offset, length, from, fromOffset); -} - -size_t Convert::fromULongArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const ULongArray &from, size_t fromOffset) -{ - return convertFromULongArray(pv.get(), offset, length, get(from), fromOffset); -} - -size_t Convert::fromFloatArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const float from[], size_t fromOffset) -{ - return convertFromFloatArray(pv.get(), offset, length, from, fromOffset); -} - -size_t Convert::fromFloatArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const FloatArray & from, size_t fromOffset) -{ - return convertFromFloatArray(pv.get(), offset, length, get(from), fromOffset); -} - -size_t Convert::fromDoubleArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const double from[], size_t fromOffset) -{ - return convertFromDoubleArray(pv.get(), offset, length, from, fromOffset); -} - -size_t Convert::fromDoubleArray(PVScalarArrayPtr &pv, size_t offset, size_t length, - const DoubleArray & from, size_t fromOffset) -{ - return convertFromDoubleArray(pv.get(), offset, length, get(from), fromOffset); + to->replace(from->view()); } void Convert::newLine(StringBuilder buffer, int indentLevel) { - newLineImpl(buffer,indentLevel); -} - -static bool scalarEquals(PVScalar *a,PVScalar *b) -{ - ScalarType ascalarType = a->getScalar()->getScalarType(); - ScalarType bscalarType = b->getScalar()->getScalarType(); - if(ascalarType!=bscalarType) return false; - switch(ascalarType) { - case pvBoolean: { - PVBoolean *pa = static_cast(a); - PVBoolean *pb = static_cast(b); - bool avalue = pa->get(); - bool bvalue = pb->get(); - return ((avalue==bvalue) ? true : false); - } - case pvByte: { - PVByte *pa = static_cast(a); - PVByte *pb = static_cast(b); - int8 avalue = pa->get(); - int8 bvalue = pb->get(); - return ((avalue==bvalue) ? true : false); - } - case pvShort: { - PVShort *pa = static_cast(a); - PVShort *pb = static_cast(b); - int16 avalue = pa->get(); - int16 bvalue = pb->get(); - return ((avalue==bvalue) ? true : false); - } - case pvInt: { - PVInt *pa = static_cast(a); - PVInt *pb = static_cast(b); - int32 avalue = pa->get(); - int32 bvalue = pb->get(); - return ((avalue==bvalue) ? true : false); - } - case pvLong: { - PVLong *pa = static_cast(a); - PVLong *pb = static_cast(b); - int64 avalue = pa->get(); - int64 bvalue = pb->get(); - return ((avalue==bvalue) ? true : false); - } - case pvUByte: { - PVUByte *pa = static_cast(a); - PVUByte *pb = static_cast(b); - uint8 avalue = pa->get(); - uint8 bvalue = pb->get(); - return ((avalue==bvalue) ? true : false); - } - case pvUShort: { - PVUShort *pa = static_cast(a); - PVUShort *pb = static_cast(b); - uint16 avalue = pa->get(); - uint16 bvalue = pb->get(); - return ((avalue==bvalue) ? true : false); - } - case pvUInt: { - PVUInt *pa = static_cast(a); - PVUInt *pb = static_cast(b); - uint32 avalue = pa->get(); - uint32 bvalue = pb->get(); - return ((avalue==bvalue) ? true : false); - } - case pvULong: { - PVULong *pa = static_cast(a); - PVULong *pb = static_cast(b); - uint64 avalue = pa->get(); - uint64 bvalue = pb->get(); - return ((avalue==bvalue) ? true : false); - } - case pvFloat: { - PVFloat *pa = static_cast(a); - PVFloat *pb = static_cast(b); - float avalue = pa->get(); - float bvalue = pb->get(); - return ((avalue==bvalue) ? true : false); - } - case pvDouble: { - PVDouble *pa = static_cast(a); - PVDouble *pb = static_cast(b); - double avalue = pa->get(); - double bvalue = pb->get(); - return ((avalue==bvalue) ? true : false); - } - case pvString: { - PVString *pa = static_cast(a); - PVString *pb = static_cast(b); - String avalue = pa->get(); - String bvalue = pb->get(); - return ((avalue==bvalue) ? true : false); - } - } - String message("should not get here"); - throw std::logic_error(message); -} - -static bool arrayEquals(PVScalarArray *a,PVScalarArray *b) -{ - if(a==b) return true; - ScalarType aType = a->getScalarArray()->getElementType(); - ScalarType bType = b->getScalarArray()->getElementType(); - if(aType!=bType) return false; - if(a->getLength()!=b->getLength()) return false; - size_t length = a->getLength(); - switch(aType) { - case pvBoolean: { - PVBooleanArray *aarray = static_cast(a); - PVBooleanArray *barray = static_cast(b); - BooleanArrayData adata; - BooleanArrayData bdata; - aarray->get(0,length,adata); - barray->get(0,length,bdata); - BooleanArray & avalue = adata.data; - BooleanArray & bvalue = bdata.data; - for(size_t i=0; i(a); - PVByteArray *barray = static_cast(b); - ByteArrayData adata; - ByteArrayData bdata; - aarray->get(0,length,adata); - barray->get(0,length,bdata); - ByteArray & avalue = adata.data; - ByteArray & bvalue = bdata.data; - for(size_t i=0; i(a); - PVShortArray *barray = static_cast(b); - ShortArrayData adata; - ShortArrayData bdata; - aarray->get(0,length,adata); - barray->get(0,length,bdata); - ShortArray & avalue = adata.data; - ShortArray & bvalue = bdata.data; - for(size_t i=0; i(a); - PVIntArray *barray = static_cast(b); - IntArrayData adata; - IntArrayData bdata; - aarray->get(0,length,adata); - barray->get(0,length,bdata); - IntArray & avalue = adata.data; - IntArray & bvalue = bdata.data; - for(size_t i=0; i(a); - PVLongArray *barray = static_cast(b); - LongArrayData adata; - LongArrayData bdata; - aarray->get(0,length,adata); - barray->get(0,length,bdata); - LongArray & avalue = adata.data; - LongArray & bvalue = bdata.data; - for(size_t i=0; i(a); - PVUByteArray *barray = static_cast(b); - UByteArrayData adata; - UByteArrayData bdata; - aarray->get(0,length,adata); - barray->get(0,length,bdata); - UByteArray & avalue = adata.data; - UByteArray & bvalue = bdata.data; - for(size_t i=0; i(a); - PVUShortArray *barray = static_cast(b); - UShortArrayData adata; - UShortArrayData bdata; - aarray->get(0,length,adata); - barray->get(0,length,bdata); - UShortArray & avalue = adata.data; - UShortArray & bvalue = bdata.data; - for(size_t i=0; i(a); - PVUIntArray *barray = static_cast(b); - UIntArrayData adata; - UIntArrayData bdata; - aarray->get(0,length,adata); - barray->get(0,length,bdata); - UIntArray & avalue = adata.data; - UIntArray & bvalue = bdata.data; - for(size_t i=0; i(a); - PVULongArray *barray = static_cast(b); - ULongArrayData adata; - ULongArrayData bdata; - aarray->get(0,length,adata); - barray->get(0,length,bdata); - ULongArray & avalue = adata.data; - ULongArray & bvalue = bdata.data; - for(size_t i=0; i(a); - PVFloatArray *barray = static_cast(b); - FloatArrayData adata; - FloatArrayData bdata; - aarray->get(0,length,adata); - barray->get(0,length,bdata); - FloatArray & avalue = adata.data; - FloatArray & bvalue = bdata.data; - for(size_t i=0; i(a); - PVDoubleArray *barray = static_cast(b); - DoubleArrayData adata; - DoubleArrayData bdata; - aarray->get(0,length,adata); - barray->get(0,length,bdata); - DoubleArray & avalue = adata.data; - DoubleArray & bvalue = bdata.data; - for(size_t i=0; i(a); - PVStringArray *barray = static_cast(b); - StringArrayData adata; - StringArrayData bdata; - aarray->get(0,length,adata); - barray->get(0,length,bdata); - StringArray & avalue = adata.data; - StringArray & bvalue = bdata.data; - for(size_t i=0; igetStructureArray()->getStructure(); - StructureConstPtr bStructure = b->getStructureArray()->getStructure(); - if(aStructure!=bStructure) return false; - if(a->getLength()!=b->getLength()) return false; - StructureArrayData aData = StructureArrayData(); - StructureArrayData bData = StructureArrayData(); - size_t length = a->getLength(); - PVStructurePtrArray & aArray = aData.data; - PVStructurePtrArray & bArray = bData.data; - if(aArray==bArray) return true; - for(size_t i=0; igetStructure(); - StructureConstPtr bStructure = a->getStructure(); - size_t length = aStructure->getNumberFields(); - if(length!=bStructure->getNumberFields()) return false; - PVFieldPtrArray const & aFields = a->getPVFields(); - PVFieldPtrArray const & bFields = b->getPVFields(); - for(size_t i=0; i(a); - void * bvoid = static_cast(b); - if(avoid==bvoid) return true; - Type atype = a->getField()->getType(); - Type btype = b->getField()->getType(); - if(atype!=btype) return false; - if(atype==scalar) return scalarEquals( - static_cast(a),static_cast(b)); - if(atype==scalarArray) return arrayEquals( - static_cast(a),static_cast(b)); - if(atype==structureArray) return structureArrayEquals( - static_cast(a),static_cast(b)); - if(atype==structure) return structureEquals( - static_cast(a),static_cast(b)); - String message("should not get here"); - throw std::logic_error(message); -} - -template -size_t convertFromScalarArray(PVScalarArray *pv, - size_t offset, size_t len,const T from[], size_t fromOffset) -{ - ScalarType elemType = pv->getScalarArray()->getElementType(); - size_t ntransfered = 0; - String xx = typeid(PVT).name(); - String yy = typeid(T).name(); - if(xx.compare(yy)== 0) { - PVT *pvdata = static_cast(pv); - while (len > 0) { - size_t n = pvdata->put(offset, len, from, fromOffset); - if (n == 0) - break; - len -= n; - offset += n; - fromOffset += n; - ntransfered += n; - } - return ntransfered; - } - switch (elemType) { - case pvBoolean: { - String message("convert from numeric array to BooleanArray not legal"); - throw std::invalid_argument(message); - } - case pvByte: { - PVByteArray *pvdata = static_cast(pv); - int8 data[1]; - while (len > 0) { - data[0] = static_cast(from[fromOffset]); - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvShort: { - PVShortArray *pvdata = static_cast(pv); - int16 data[1]; - while (len > 0) { - data[0] = static_cast(from[fromOffset]); - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvInt: { - PVIntArray *pvdata = static_cast(pv); - int32 data[1]; - while (len > 0) { - data[0] = static_cast(from[fromOffset]); - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvLong: { - PVLongArray *pvdata = static_cast(pv); - int64 data[1]; - while (len > 0) { - data[0] = static_cast(from[fromOffset]); - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvUByte: { - PVUByteArray *pvdata = static_cast(pv); - uint8 data[1]; - while (len > 0) { - data[0] = static_cast(from[fromOffset]); - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvUShort: { - PVUShortArray *pvdata = static_cast(pv); - uint16 data[1]; - while (len > 0) { - data[0] = static_cast(from[fromOffset]); - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvUInt: { - PVUIntArray *pvdata = static_cast(pv); - uint32 data[1]; - while (len > 0) { - data[0] = static_cast(from[fromOffset]); - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvULong: { - PVULongArray *pvdata = static_cast(pv); - uint64 data[1]; - while (len > 0) { - data[0] = static_cast(from[fromOffset]); - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvFloat: { - PVFloatArray *pvdata = static_cast(pv); - float data[1]; - while (len > 0) { - data[0] = static_cast(from[fromOffset]); - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvDouble: { - PVDoubleArray *pvdata = static_cast(pv); - double data[1]; - while (len > 0) { - data[0] = static_cast(from[fromOffset]); - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvString: { - String message("convert from byte[] to StringArray not legal"); - throw std::invalid_argument(message); - } - } - String message("Convert::convertFromByteArray should never get here"); - throw std::logic_error(message); -} - -template -size_t convertToScalarArray(PVScalarArray *pv, - size_t offset, size_t len,T to[], size_t toOffset) -{ - ScalarType elemType = pv->getScalarArray()->getElementType(); - size_t ntransfered = 0; - switch (elemType) { - case pvBoolean: { - String message("convert BooleanArray to byte[]] not legal"); - throw std::invalid_argument(message); - } - case pvByte: { - PVByteArray *pvdata = static_cast(pv); - ByteArrayData data; - while (len > 0) { - size_t num = 0; - num = pvdata->get(offset,len,data); - if (num <= 0) break; - ByteArray & dataArray = data.data; - size_t dataOffset = data.offset; - for(size_t i=0;i(pv); - ShortArrayData data; - while (len > 0) { - size_t num = pvdata->get(offset, len, data); - if (num == 0) break; - ShortArray & dataArray = data.data; - size_t dataOffset = data.offset; - for (size_t i = 0; i < num; i++) - to[i + toOffset] = dataArray[i + dataOffset]; - len -= num; - offset += num; - toOffset += num; - ntransfered += num; - } - return ntransfered; - } - case pvInt: { - PVIntArray *pvdata = static_cast(pv); - IntArrayData data; - while (len > 0) { - size_t num = pvdata->get(offset, len, data); - if (num == 0) break; - IntArray & dataArray = data.data; - size_t dataOffset = data.offset; - for (size_t i = 0; i < num; i++) - to[i + toOffset] = dataArray[i + dataOffset]; - len -= num; - offset += num; - toOffset += num; - ntransfered += num; - } - return ntransfered; - } - case pvLong: { - PVLongArray *pvdata = static_cast(pv); - LongArrayData data; - while (len > 0) { - size_t num = pvdata->get(offset, len, data); - if (num == 0) - break; - LongArray & dataArray = data.data; - size_t dataOffset = data.offset; - for (size_t i = 0; i < num; i++) - to[i + toOffset] = dataArray[i + dataOffset]; - len -= num; - offset += num; - toOffset += num; - ntransfered += num; - } - return ntransfered; - } - case pvUByte: { - PVUByteArray *pvdata = static_cast(pv); - UByteArrayData data; - while (len > 0) { - size_t num = 0; - num = pvdata->get(offset,len,data); - if (num <= 0) break; - UByteArray & dataArray = data.data; - size_t dataOffset = data.offset; - for(size_t i=0;i(pv); - UShortArrayData data; - while (len > 0) { - size_t num = pvdata->get(offset, len, data); - if (num == 0) break; - UShortArray & dataArray = data.data; - size_t dataOffset = data.offset; - for (size_t i = 0; i < num; i++) - to[i + toOffset] = dataArray[i + dataOffset]; - len -= num; - offset += num; - toOffset += num; - ntransfered += num; - } - return ntransfered; - } - case pvUInt: { - PVUIntArray *pvdata = static_cast(pv); - UIntArrayData data; - while (len > 0) { - size_t num = pvdata->get(offset, len, data); - if (num == 0) break; - UIntArray & dataArray = data.data; - size_t dataOffset = data.offset; - for (size_t i = 0; i < num; i++) - to[i + toOffset] = dataArray[i + dataOffset]; - len -= num; - offset += num; - toOffset += num; - ntransfered += num; - } - return ntransfered; - } - case pvULong: { - PVULongArray *pvdata = static_cast(pv); - ULongArrayData data; - while (len > 0) { - size_t num = pvdata->get(offset, len, data); - if (num == 0) - break; - ULongArray & dataArray = data.data; - size_t dataOffset = data.offset; - for (size_t i = 0; i < num; i++) - to[i + toOffset] = dataArray[i + dataOffset]; - len -= num; - offset += num; - toOffset += num; - ntransfered += num; - } - return ntransfered; - } - case pvFloat: { - PVFloatArray *pvdata = static_cast(pv); - FloatArrayData data; - while (len > 0) { - size_t num = pvdata->get(offset, len, data); - if (num == 0) break; - FloatArray & dataArray = data.data; - size_t dataOffset = data.offset; - for (size_t i = 0; i < num; i++) - to[i + toOffset] = static_cast(dataArray[i + dataOffset]); - len -= num; - offset += num; - toOffset += num; - ntransfered += num; - } - return ntransfered; - } - case pvDouble: { - PVDoubleArray *pvdata = static_cast(pv); - DoubleArrayData data; - while (len > 0) { - size_t num = pvdata->get(offset, len, data); - if (num == 0) - break; - DoubleArray & dataArray = data.data; - size_t dataOffset = data.offset; - for (size_t i = 0; i < num; i++) - to[i + toOffset] = static_cast(dataArray[i + dataOffset]); - len -= num; - offset += num; - toOffset += num; - ntransfered += num; - } - return ntransfered; - } - case pvString: { - String message("convert StringArray to numeric not legal"); - throw std::invalid_argument(message); - } - } - String message("Convert::convertToScalarArray should never get here"); - throw std::logic_error(message); -} - -size_t convertFromByteArray(PVScalarArray *pv, - size_t offset, size_t len,const int8 from[], size_t fromOffset) -{ - return convertFromScalarArray(pv,offset,len,from,fromOffset); -} - -size_t convertToByteArray(PVScalarArray * pv, - size_t offset, size_t len,int8 to[], size_t toOffset) -{ - return convertToScalarArray(pv,offset,len,to,toOffset); -} - -size_t convertFromShortArray(PVScalarArray *pv, - size_t offset, size_t len,const int16 from[], size_t fromOffset) -{ - return convertFromScalarArray(pv,offset,len,from,fromOffset); -} - -size_t convertToShortArray(PVScalarArray * pv, - size_t offset, size_t len,int16 to[], size_t toOffset) -{ - return convertToScalarArray(pv,offset,len,to,toOffset); -} - -size_t convertFromIntArray(PVScalarArray *pv, - size_t offset, size_t len,const int32 from[], size_t fromOffset) -{ - return convertFromScalarArray(pv,offset,len,from,fromOffset); -} - -size_t convertToIntArray(PVScalarArray * pv, - size_t offset, size_t len,int32 to[], size_t toOffset) -{ - return convertToScalarArray(pv,offset,len,to,toOffset); -} - -size_t convertFromLongArray(PVScalarArray *pv, - size_t offset, size_t len,const int64 from[], size_t fromOffset) -{ - return convertFromScalarArray(pv,offset,len,from,fromOffset); -} - -size_t convertToLongArray(PVScalarArray * pv, - size_t offset, size_t len,int64 to[], size_t toOffset) -{ - return convertToScalarArray(pv,offset,len,to,toOffset); -} - -size_t convertFromUByteArray(PVScalarArray *pv, - size_t offset, size_t len,const uint8 from[], size_t fromOffset) -{ - return convertFromScalarArray(pv,offset,len,from,fromOffset); -} - -size_t convertToUByteArray(PVScalarArray * pv, - size_t offset, size_t len,uint8 to[], size_t toOffset) -{ - return convertToScalarArray(pv,offset,len,to,toOffset); -} - -size_t convertFromUShortArray(PVScalarArray *pv, - size_t offset, size_t len,const uint16 from[], size_t fromOffset) -{ - return convertFromScalarArray(pv,offset,len,from,fromOffset); -} - -size_t convertToUShortArray(PVScalarArray * pv, - size_t offset, size_t len,uint16 to[], size_t toOffset) -{ - return convertToScalarArray(pv,offset,len,to,toOffset); -} - -size_t convertFromUIntArray(PVScalarArray *pv, - size_t offset, size_t len,const uint32 from[], size_t fromOffset) -{ - return convertFromScalarArray(pv,offset,len,from,fromOffset); -} - -size_t convertToUIntArray(PVScalarArray * pv, - size_t offset, size_t len,uint32 to[], size_t toOffset) -{ - return convertToScalarArray(pv,offset,len,to,toOffset); -} - -size_t convertFromULongArray(PVScalarArray *pv, - size_t offset, size_t len,const uint64 from[], size_t fromOffset) -{ - return convertFromScalarArray(pv,offset,len,from,fromOffset); -} - -size_t convertToULongArray(PVScalarArray * pv, - size_t offset, size_t len,uint64 to[], size_t toOffset) -{ - return convertToScalarArray(pv,offset,len,to,toOffset); -} - -size_t convertFromFloatArray(PVScalarArray *pv, - size_t offset, size_t len,const float from[], size_t fromOffset) -{ - return convertFromScalarArray(pv,offset,len,from,fromOffset); -} - -size_t convertToFloatArray(PVScalarArray * pv, - size_t offset, size_t len,float to[], size_t toOffset) -{ - return convertToScalarArray(pv,offset,len,to,toOffset); -} - -size_t convertFromDoubleArray(PVScalarArray *pv, - size_t offset, size_t len,const double from[], size_t fromOffset) -{ - return convertFromScalarArray(pv,offset,len,from,fromOffset); -} - -size_t convertToDoubleArray(PVScalarArray * pv, - size_t offset, size_t len,double to[], size_t toOffset) -{ - return convertToScalarArray(pv,offset,len,to,toOffset); -} - -size_t convertFromStringArray(PVScalarArray *pv, - size_t offset, size_t len,const StringArray & from, size_t fromOffset) -{ - ScalarType elemType = pv->getScalarArray()->getElementType(); - size_t ntransfered = 0; - switch (elemType) { - case pvBoolean: { - PVBooleanArray *pvdata = static_cast(pv); - boolean data[1]; - while (len > 0) { - String fromString = from[fromOffset]; - data[0] = (fromString.compare("true")==0) ? true : false; - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvByte: { - PVByteArray *pvdata = static_cast(pv); - int8 data[1]; - while (len > 0) { - String fromString = from[fromOffset]; - int ival; - sscanf(fromString.c_str(),"%d",&ival); - data[0] = ival; - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvShort: { - PVShortArray *pvdata = static_cast(pv); - int16 data[1]; - while (len > 0) { - String fromString = from[fromOffset]; - int ival; - sscanf(fromString.c_str(),"%d",&ival); - data[0] = ival; - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvInt: { - PVIntArray *pvdata = static_cast(pv); - int32 data[1]; - while (len > 0) { - String fromString = from[fromOffset]; - int ival; - sscanf(fromString.c_str(),"%d",&ival); - data[0] = ival; - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvLong: { - PVLongArray *pvdata = static_cast(pv); - int64 data[1]; - while (len > 0) { - String fromString = from[fromOffset]; - int64 ival; - sscanf(fromString.c_str(),"%lld",(long long int *)&ival); - data[0] = ival; - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvUByte: { - PVUByteArray *pvdata = static_cast(pv); - uint8 data[1]; - while (len > 0) { - String fromString = from[fromOffset]; - unsigned int ival; - sscanf(fromString.c_str(),"%u",&ival); - data[0] = ival; - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvUShort: { - PVUShortArray *pvdata = static_cast(pv); - uint16 data[1]; - while (len > 0) { - String fromString = from[fromOffset]; - unsigned int ival; - sscanf(fromString.c_str(),"%u",&ival); - data[0] = ival; - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvUInt: { - PVUIntArray *pvdata = static_cast(pv); - uint32 data[1]; - while (len > 0) { - String fromString = from[fromOffset]; - unsigned int ival; - sscanf(fromString.c_str(),"%u",&ival); - data[0] = ival; - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvULong: { - PVULongArray *pvdata = static_cast(pv); - uint64 data[1]; - while (len > 0) { - String fromString = from[fromOffset]; - uint64 ival; - sscanf(fromString.c_str(),"%lld",(unsigned long long int *)&ival); - data[0] = ival; - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvFloat: { - PVFloatArray *pvdata = static_cast(pv); - float data[1]; - while (len > 0) { - String fromString = from[fromOffset]; - float fval; - sscanf(fromString.c_str(),"%f",&fval); - data[0] = fval; - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvDouble: { - PVDoubleArray *pvdata = static_cast(pv); - double data[1]; - while (len > 0) { - String fromString = from[fromOffset]; - double fval; - sscanf(fromString.c_str(),"%lf",&fval); - data[0] = fval; - if (pvdata->put(offset, 1, data, 0) == 0) - return ntransfered; - --len; - ++ntransfered; - ++offset; - ++fromOffset; - } - return ntransfered; - } - case pvString: - PVStringArray *pvdata = static_cast(pv); - while (len > 0) { - String * xxx = const_cast(get(from)); - size_t n = pvdata->put(offset, len, xxx, fromOffset); - if (n == 0) - break; - len -= n; - offset += n; - fromOffset += n; - ntransfered += n; - } - return ntransfered; - } - String message("Convert::convertFromStringArray should never get here"); - throw std::logic_error(message); -} - -size_t convertToStringArray(PVScalarArray *pv, - size_t offset, size_t len,StringArray & xxx, size_t toOffset) -{ - String *to = &xxx[0]; - ScalarType elementType = pv->getScalarArray()->getElementType(); - size_t ncopy = pv->getLength(); - if (ncopy > len) ncopy = len; - size_t num = ncopy; - switch (elementType) { - case pvBoolean: { - PVBooleanArray *pvdata = static_cast(pv); - BooleanArrayData data; - for (size_t i = 0; i < num; i++) { - if (pvdata->get(offset + i, 1, data) == 1) { - BooleanArray & dataArray = data.data; - bool value = dataArray[data.offset]; - to[toOffset + i] = value ? "true" : "false"; - } else { - to[toOffset + i] = "bad pv"; - } - } - } - break; - case pvByte: { - PVByteArray *pvdata = static_cast(pv); - ByteArrayData data; - char cr[30]; - for (size_t i = 0; i < num; i++) { - if (pvdata->get(offset + i, 1, data) == 1) { - ByteArray & dataArray = data.data; - int ival = dataArray[data.offset]; - sprintf(cr,"%d",ival); - to[toOffset + i] = String(cr); - } else { - to[toOffset + i] = "bad pv"; - } - } - } - break; - case pvShort: { - PVShortArray *pvdata = static_cast(pv); - ShortArrayData data; - char cr[30]; - for (size_t i = 0; i < num; i++) { - if (pvdata->get(offset + i, 1, data) == 1) { - ShortArray & dataArray = data.data; - int ival = dataArray[data.offset]; - sprintf(cr,"%d",ival); - to[toOffset + i] = String(cr); - } else { - to[toOffset + i] = "bad pv"; - } - } - } - break; - case pvInt: { - PVIntArray *pvdata = static_cast(pv); - IntArrayData data; - char cr[30]; - for (size_t i = 0; i < num; i++) { - if (pvdata->get(offset + i, 1, data) == 1) { - IntArray & dataArray = data.data; - int ival = dataArray[data.offset]; - sprintf(cr,"%d",ival); - to[toOffset + i] = String(cr); - } else { - to[toOffset + i] = "bad pv"; - } - } - } - break; - case pvLong: { - PVLongArray *pvdata = static_cast(pv); - LongArrayData data = LongArrayData(); - char cr[30]; - for (size_t i = 0; i < num; i++) { - if (pvdata->get(offset + i, 1, data) == 1) { - LongArray & dataArray = data.data; - int64 ival = dataArray[data.offset]; - sprintf(cr,"%lld",(long long)ival); - to[toOffset + i] = String(cr); - } else { - to[toOffset + i] = "bad pv"; - } - } - } - break; - case pvUByte: { - PVUByteArray *pvdata = static_cast(pv); - UByteArrayData data; - char cr[30]; - for (size_t i = 0; i < num; i++) { - if (pvdata->get(offset + i, 1, data) == 1) { - UByteArray & dataArray = data.data; - unsigned int ival = dataArray[data.offset]; - sprintf(cr,"%u",ival); - to[toOffset + i] = String(cr); - } else { - to[toOffset + i] = "bad pv"; - } - } - } - break; - case pvUShort: { - PVUShortArray *pvdata = static_cast(pv); - UShortArrayData data; - char cr[30]; - for (size_t i = 0; i < num; i++) { - if (pvdata->get(offset + i, 1, data) == 1) { - UShortArray & dataArray = data.data; - unsigned int ival = dataArray[data.offset]; - sprintf(cr,"%u",ival); - to[toOffset + i] = String(cr); - } else { - to[toOffset + i] = "bad pv"; - } - } - } - break; - case pvUInt: { - PVUIntArray *pvdata = static_cast(pv); - UIntArrayData data; - char cr[30]; - for (size_t i = 0; i < num; i++) { - if (pvdata->get(offset + i, 1, data) == 1) { - UIntArray & dataArray = data.data; - unsigned int ival = dataArray[data.offset]; - sprintf(cr,"%u",ival); - to[toOffset + i] = String(cr); - } else { - to[toOffset + i] = "bad pv"; - } - } - } - break; - case pvULong: { - PVULongArray *pvdata = static_cast(pv); - ULongArrayData data; - char cr[30]; - for (size_t i = 0; i < num; i++) { - if (pvdata->get(offset + i, 1, data) == 1) { - ULongArray & dataArray = data.data; - uint64 ival = dataArray[data.offset]; - sprintf(cr,"%llu",(unsigned long long)ival); - to[toOffset + i] = String(cr); - } else { - to[toOffset + i] = "bad pv"; - } - } - } - break; - case pvFloat: { - PVFloatArray *pvdata = static_cast(pv); - FloatArrayData data; - char cr[30]; - for (size_t i = 0; i < num; i++) { - if (pvdata->get(offset + i, 1, data) == 1) { - FloatArray & dataArray = data.data; - float fval = dataArray[data.offset]; - sprintf(cr,"%g",fval); - to[toOffset + i] = String(cr); - } else { - to[toOffset + i] = "bad pv"; - } - } - } - break; - case pvDouble: { - PVDoubleArray *pvdata = static_cast(pv); - DoubleArrayData data; - char cr[30]; - for (size_t i = 0; i < num; i++) { - if (pvdata->get(offset + i, 1, data) == 1) { - DoubleArray & dataArray = data.data; - double fval = dataArray[data.offset]; - sprintf(cr,"%g",fval); - to[toOffset + i] = String(cr); - } else { - to[toOffset + i] = "bad pv"; - } - } - } - break; - case pvString: { - PVStringArray *pvdata = static_cast(pv); - while (num > 0) { - size_t numnow = 0; - size_t dataOffset = 0; - String *dataArray; - StringArrayData stringArrayData; - numnow = pvdata->get(offset, num, stringArrayData); - dataArray = pvdata->get(); - dataOffset = stringArrayData.offset; - if (numnow <= 0) { - for (size_t i = 0; i < num; i++) - to[toOffset + i] = "bad pv"; - break; - } - for(size_t i=0; igetField()->getType(); - if(type==scalarArray) { - convertArray(buffer,static_cast(pv),indentLevel); - return; - } - if(type==structure) { - convertStructure(buffer,static_cast(pv),indentLevel); - return; - } - if(type==structureArray) { - convertStructureArray( - buffer,static_cast(pv),indentLevel); - return; - } - PVScalar const *pvScalar = static_cast(pv); - const ScalarConstPtr & pscalar = pvScalar->getScalar(); - ScalarType scalarType = pscalar->getScalarType(); - *buffer += pscalar->getID(); - *buffer += " "; - *buffer += pv->getFieldName(); - *buffer += " "; - switch(scalarType) { - case pvBoolean: { - PVBoolean const *data = static_cast(pv); - bool value = data->get(); - if(value) { - *buffer += "true"; - } else { - *buffer += "false"; - } - } - return; - case pvByte: { - PVByte const *data = static_cast(pv); - char xxx[30]; - sprintf(xxx,"%d",(int)data->get()); - *buffer += xxx; - } - return; - case pvShort: { - PVShort const *data = static_cast(pv); - char xxx[30]; - sprintf(xxx,"%d",(int)data->get()); - *buffer += xxx; - } - return; - case pvInt: { - PVInt const *data = static_cast(pv); - char xxx[30]; - sprintf(xxx,"%d",(int)data->get()); - *buffer += xxx; - } - return; - case pvLong: { - PVLong const *data = static_cast(pv); - char xxx[30]; - sprintf(xxx,"%lld",(long long)data->get()); - *buffer += xxx; - } - return; - case pvUByte: { - PVUByte const *data = static_cast(pv); - char xxx[30]; - sprintf(xxx,"%u",(unsigned int)data->get()); - *buffer += xxx; - } - return; - case pvUShort: { - PVUShort const *data = static_cast(pv); - char xxx[30]; - sprintf(xxx,"%u",(unsigned int)data->get()); - *buffer += xxx; - } - return; - case pvUInt: { - PVUInt const *data = static_cast(pv); - char xxx[30]; - sprintf(xxx,"%u",(unsigned int)data->get()); - *buffer += xxx; - } - return; - case pvULong: { - PVULong const *data = static_cast(pv); - char xxx[30]; - sprintf(xxx,"%llu",(unsigned long long)data->get()); - *buffer += xxx; - } - return; - case pvFloat: { - PVFloat const *data = static_cast(pv); - char xxx[30]; - sprintf(xxx,"%g",data->get()); - *buffer += xxx; - } - return; - case pvDouble: { - PVDouble const *data = static_cast(pv); - char xxx[30]; - sprintf(xxx,"%g",data->get()); - *buffer += xxx; - } - return; - case pvString: { - PVString const *data = static_cast(pv); - *buffer += data->get(); - } - return; - default: - *buffer += "unknown ScalarType"; - } -} - -void convertStructure(StringBuilder buffer,PVStructure const *data,int indentLevel) -{ - *buffer += data->getStructure()->getID() + " " + data->getFieldName(); - String extendsName = data->getExtendsStructureName(); - if(extendsName.length()>0) { - *buffer += " extends " + extendsName; - } - PVFieldPtrArray const & fieldsData = data->getPVFields(); - if (fieldsData.size() != 0) { - int length = data->getStructure()->getNumberFields(); - for(int i=0; itoString(buffer,indentLevel + 1); - } - } -} - -void convertArray(StringBuilder buffer,PVScalarArray const * xxx,int /*indentLevel*/) -{ - PVScalarArray *pv = const_cast(xxx); - ScalarArrayConstPtr array = pv->getScalarArray(); - ScalarType type = array->getElementType(); - *buffer += array->getID() + " " + pv->getFieldName() + " "; - switch(type) { - case pvBoolean: { - PVBooleanArray *pvdata = static_cast(pv); - BooleanArrayData data; - *buffer += "["; - for(size_t i=0; i < pvdata->getLength(); i++) { - if(i!=0) *buffer += ","; - size_t num = pvdata->get(i,1,data); - if(num==1) { - BooleanArray & value = data.data; - if(value[data.offset]) { - *buffer += "true"; - } else { - *buffer += "false"; - } - } else { - *buffer += "???? "; - } - } - *buffer += "]"; - break; - } - case pvByte: { - PVByteArray *pvdata = static_cast(pv); - ByteArrayData data; - *buffer += "["; - for(size_t i=0; i < pvdata->getLength(); i++) { - if(i!=0) *buffer += ","; - size_t num = pvdata->get(i,1,data); - if(num==1) { - int val = data.data[data.offset]; - char buf[16]; - sprintf(buf,"%d",val); - *buffer += buf; - } else { - *buffer += "???? "; - } - } - *buffer += "]"; - break; - } - case pvShort: { - PVShortArray *pvdata = static_cast(pv); - ShortArrayData data; - *buffer += "["; - for(size_t i=0; i < pvdata->getLength(); i++) { - if(i!=0) *buffer += ','; - size_t num = pvdata->get(i,1,data); - if(num==1) { - int val = data.data[data.offset]; - char buf[16]; - sprintf(buf,"%d",val); - *buffer += buf; - } else { - *buffer += "???? "; - } - } - *buffer += "]"; - break; - } - case pvInt: { - PVIntArray *pvdata = static_cast(pv); - IntArrayData data; - *buffer += "["; - for(size_t i=0; i < pvdata->getLength(); i++) { - if(i!=0) *buffer += ','; - size_t num = pvdata->get(i,1,data); - if(num==1) { - int val = data.data[data.offset]; - char buf[16]; - sprintf(buf,"%d",val); - *buffer += buf; - } else { - *buffer += "???? "; - } - } - *buffer += "]"; - break; - } - case pvLong: { - PVLongArray *pvdata = static_cast(pv); - LongArrayData data; - *buffer += "["; - for(size_t i=0; i < pvdata->getLength(); i++) { - if(i!=0) *buffer += ','; - size_t num = pvdata->get(i,1,data); - if(num==1) { - int64 val = data.data[data.offset]; - char buf[32]; - sprintf(buf,"%lld",(long long)val); - *buffer += buf; - } else { - *buffer += "???? "; - } - } - *buffer += "]"; - break; - } - case pvUByte: { - PVUByteArray *pvdata = static_cast(pv); - UByteArrayData data; - *buffer += "["; - for(size_t i=0; i < pvdata->getLength(); i++) { - if(i!=0) *buffer += ","; - size_t num = pvdata->get(i,1,data); - if(num==1) { - unsigned int val = data.data[data.offset]; - char buf[16]; - sprintf(buf,"%u",val); - *buffer += buf; - } else { - *buffer += "???? "; - } - } - *buffer += "]"; - break; - } - case pvUShort: { - PVUShortArray *pvdata = static_cast(pv); - UShortArrayData data; - *buffer += "["; - for(size_t i=0; i < pvdata->getLength(); i++) { - if(i!=0) *buffer += ','; - size_t num = pvdata->get(i,1,data); - if(num==1) { - unsigned int val = data.data[data.offset]; - char buf[16]; - sprintf(buf,"%u",val); - *buffer += buf; - } else { - *buffer += "???? "; - } - } - *buffer += "]"; - break; - } - case pvUInt: { - PVUIntArray *pvdata = static_cast(pv); - UIntArrayData data; - *buffer += "["; - for(size_t i=0; i < pvdata->getLength(); i++) { - if(i!=0) *buffer += ','; - size_t num = pvdata->get(i,1,data); - if(num==1) { - unsigned int val = data.data[data.offset]; - char buf[16]; - sprintf(buf,"%u",val); - *buffer += buf; - } else { - *buffer += "???? "; - } - } - *buffer += "]"; - break; - } - case pvULong: { - PVULongArray *pvdata = static_cast(pv); - ULongArrayData data; - *buffer += "["; - for(size_t i=0; i < pvdata->getLength(); i++) { - if(i!=0) *buffer += ','; - size_t num = pvdata->get(i,1,data); - if(num==1) { - uint64 val = data.data[data.offset]; - char buf[32]; - sprintf(buf,"%llu",(unsigned long long)val); - *buffer += buf; - } else { - *buffer += "???? "; - } - } - *buffer += "]"; - break; - } - case pvFloat: { - PVFloatArray *pvdata = static_cast(pv); - FloatArrayData data; - *buffer += "["; - for(size_t i=0; i < pvdata->getLength(); i++) { - if(i!=0) *buffer += ','; - size_t num = pvdata->get(i,1,data); - if(num==1) { - float val = data.data[data.offset]; - char buf[16]; - sprintf(buf,"%g",val); - *buffer += buf; - } else { - *buffer += "???? "; - } - } - *buffer += "]"; - break; - } - case pvDouble: { - PVDoubleArray *pvdata = static_cast(pv); - DoubleArrayData data; - *buffer += "["; - for(size_t i=0; i < pvdata->getLength(); i++) { - if(i!=0) *buffer += ','; - size_t num = pvdata->get(i,1,data); - if(num==1) { - double val = data.data[data.offset]; - char buf[16]; - sprintf(buf,"%g",val); - *buffer += buf; - } else { - *buffer += "???? "; - } - } - *buffer += ("]"); - break; - } - case pvString: { - PVStringArray *pvdata = static_cast(pv); - StringArrayData data; - *buffer += "["; - for(size_t i=0; i < pvdata->getLength(); i++) { - if(i!=0) *buffer += ","; - size_t num = pvdata->get(i,1,data); - StringArray & value = data.data; - if(num==1) { - if(value[data.offset].length()>0) { - *buffer += value[data.offset].c_str(); - } else { - *buffer += "null"; - } - } else { - *buffer += "null"; - } - } - *buffer += "]"; - break; - } - default: - *buffer += " array element is unknown ScalarType"; - } - if(pv->isImmutable()) { - *buffer += " immutable "; - } -} - -void convertStructureArray(StringBuilder buffer, - PVStructureArray const * xxx,int indentLevel) -{ - PVStructureArray *pvdata = const_cast(xxx); - *buffer += pvdata->getStructureArray()->getID() + " " + pvdata->getFieldName() + " "; - size_t length = pvdata->getLength(); - if(length<=0) { - return; - } - StructureArrayData data = StructureArrayData(); - pvdata->get(0, length, data); - for (size_t i = 0; i < length; i++) { - newLineImpl(buffer, indentLevel + 1); - PVStructurePtr & pvStructure = data.data[i]; - if (pvStructure.get() == 0) { - *buffer += "null"; - } else { - pvStructure->toString(buffer,indentLevel+1); - } - } -} - -size_t copyArrayDataReference(PVScalarArray *from,PVArray *to) -{ - ScalarType scalarType = from->getScalarArray()->getElementType(); - switch (scalarType) { - case pvBoolean: { - PVBooleanArray *pvfrom = (PVBooleanArray*) from; - PVBooleanArray *pvto = (PVBooleanArray*) to; - pvto->shareData( - pvfrom->getSharedVector(),pvfrom->getCapacity(),pvfrom->getLength()); - break; - } - case pvByte: { - PVByteArray *pvfrom = (PVByteArray*) from; - PVByteArray *pvto = (PVByteArray*) to; - pvto->shareData( - pvfrom->getSharedVector(),pvfrom->getCapacity(),pvfrom->getLength()); - break; - } - case pvShort: { - PVShortArray *pvfrom = (PVShortArray*) from; - PVShortArray *pvto = (PVShortArray*) to; - pvto->shareData( - pvfrom->getSharedVector(),pvfrom->getCapacity(),pvfrom->getLength()); - break; - } - case pvInt: { - PVIntArray *pvfrom = (PVIntArray*) from; - PVIntArray *pvto = (PVIntArray*) to; - pvto->shareData( - pvfrom->getSharedVector(),pvfrom->getCapacity(),pvfrom->getLength()); - break; - } - case pvLong: { - PVLongArray *pvfrom = (PVLongArray*) from; - PVLongArray *pvto = (PVLongArray*) to; - pvto->shareData( - pvfrom->getSharedVector(),pvfrom->getCapacity(),pvfrom->getLength()); - break; - } - case pvUByte: { - PVUByteArray *pvfrom = (PVUByteArray*) from; - PVUByteArray *pvto = (PVUByteArray*) to; - pvto->shareData( - pvfrom->getSharedVector(),pvfrom->getCapacity(),pvfrom->getLength()); - break; - } - case pvUShort: { - PVUShortArray *pvfrom = (PVUShortArray*) from; - PVUShortArray *pvto = (PVUShortArray*) to; - pvto->shareData( - pvfrom->getSharedVector(),pvfrom->getCapacity(),pvfrom->getLength()); - break; - } - case pvUInt: { - PVUIntArray *pvfrom = (PVUIntArray*) from; - PVUIntArray *pvto = (PVUIntArray*) to; - pvto->shareData( - pvfrom->getSharedVector(),pvfrom->getCapacity(),pvfrom->getLength()); - break; - } - case pvULong: { - PVULongArray *pvfrom = (PVULongArray*) from; - PVULongArray *pvto = (PVULongArray*) to; - pvto->shareData( - pvfrom->getSharedVector(),pvfrom->getCapacity(),pvfrom->getLength()); - break; - } - case pvFloat: { - PVFloatArray *pvfrom = (PVFloatArray*) from; - PVFloatArray *pvto = (PVFloatArray*) to; - pvto->shareData( - pvfrom->getSharedVector(),pvfrom->getCapacity(),pvfrom->getLength()); - break; - } - case pvDouble: { - PVDoubleArray *pvfrom = (PVDoubleArray*) from; - PVDoubleArray *pvto = (PVDoubleArray*) to; - pvto->shareData( - pvfrom->getSharedVector(),pvfrom->getCapacity(),pvfrom->getLength()); - break; - } - case pvString: { - PVStringArray *pvfrom = (PVStringArray*) from; - PVStringArray *pvto = (PVStringArray*) to; - pvto->shareData( - pvfrom->getSharedVector(),pvfrom->getCapacity(),pvfrom->getLength()); - break; - } - } - to->setImmutable(); - return from->getLength(); -} - -size_t copyNumericArray(PVScalarArray *from, size_t offset, PVScalarArray *to, size_t toOffset, size_t len) -{ - ScalarType fromElementType = from->getScalarArray()->getElementType(); - size_t ncopy = 0; - switch (fromElementType) { - case pvBoolean: - throw std::logic_error(String("PVBooleanArray is not a numeric array")); - case pvByte: { - PVByteArray *pvfrom = (PVByteArray*) from; - while (len > 0) { - size_t num = 0; - ByteArrayData arrayData = ByteArrayData(); - num = pvfrom->get(offset, len, arrayData); - int8 * data = get(arrayData.data); - size_t dataOffset = arrayData.offset; - if (num <= 0) break; - while (num > 0) { - size_t n = convertFromByteArray( - to, toOffset, num, data, dataOffset); - if (n <= 0) break; - len -= n; - num -= n; - ncopy += n; - offset += n; - toOffset += n; - } - } - break; - } - case pvShort: { - PVShortArray *pvfrom = (PVShortArray*) from; - while (len > 0) { - size_t num = 0; - ShortArrayData arrayData = ShortArrayData(); - num = pvfrom->get(offset, len, arrayData); - int16 * data = get(arrayData.data); - size_t dataOffset = arrayData.offset; - if (num <= 0) break; - while (num > 0) { - size_t n = convertFromShortArray( - to, toOffset, num, data, dataOffset); - if (n <= 0) break; - len -= n; - num -= n; - ncopy += n; - offset += n; - toOffset += n; - } - } - break; - } - case pvInt: { - PVIntArray *pvfrom = (PVIntArray*) from; - while (len > 0) { - size_t num = 0; - IntArrayData arrayData = IntArrayData(); - num = pvfrom->get(offset, len, arrayData); - int32 * data = get(arrayData.data); - size_t dataOffset = arrayData.offset; - if (num <= 0) break; - while (num > 0) { - size_t n = convertFromIntArray( - to, toOffset, num, data, dataOffset); - if (n <= 0) break; - len -= n; - num -= n; - ncopy += n; - offset += n; - toOffset += n; - } - } - break; - } - case pvLong: { - PVLongArray *pvfrom = (PVLongArray*) from; - while (len > 0) { - size_t num = 0; - LongArrayData arrayData = LongArrayData(); - num = pvfrom->get(offset, len, arrayData); - int64 * data = get(arrayData.data); - size_t dataOffset = arrayData.offset; - if (num <= 0) break; - while (num > 0) { - size_t n = convertFromLongArray( - to, toOffset, num, data, dataOffset); - if (n <= 0) break; - len -= n; - num -= n; - ncopy += n; - offset += n; - toOffset += n; - } - } - break; - } - case pvUByte: { - PVUByteArray *pvfrom = (PVUByteArray*) from; - while (len > 0) { - size_t num = 0; - UByteArrayData arrayData = UByteArrayData(); - num = pvfrom->get(offset, len, arrayData); - uint8 * data = get(arrayData.data); - size_t dataOffset = arrayData.offset; - if (num <= 0) break; - while (num > 0) { - size_t n = convertFromUByteArray( - to, toOffset, num, data, dataOffset); - if (n <= 0) break; - len -= n; - num -= n; - ncopy += n; - offset += n; - toOffset += n; - } - } - break; - } - case pvUShort: { - PVUShortArray *pvfrom = (PVUShortArray*) from; - while (len > 0) { - size_t num = 0; - UShortArrayData arrayData = UShortArrayData(); - num = pvfrom->get(offset, len, arrayData); - uint16 * data = get(arrayData.data); - size_t dataOffset = arrayData.offset; - if (num <= 0) break; - while (num > 0) { - size_t n = convertFromUShortArray( - to, toOffset, num, data, dataOffset); - if (n <= 0) break; - len -= n; - num -= n; - ncopy += n; - offset += n; - toOffset += n; - } - } - break; - } - case pvUInt: { - PVUIntArray *pvfrom = (PVUIntArray*) from; - while (len > 0) { - size_t num = 0; - UIntArrayData arrayData = UIntArrayData(); - num = pvfrom->get(offset, len, arrayData); - uint32 * data = get(arrayData.data); - size_t dataOffset = arrayData.offset; - if (num <= 0) break; - while (num > 0) { - size_t n = convertFromUIntArray( - to, toOffset, num, data, dataOffset); - if (n <= 0) break; - len -= n; - num -= n; - ncopy += n; - offset += n; - toOffset += n; - } - } - break; - } - case pvULong: { - PVULongArray *pvfrom = (PVULongArray*) from; - while (len > 0) { - size_t num = 0; - ULongArrayData arrayData = ULongArrayData(); - num = pvfrom->get(offset, len, arrayData); - uint64 * data = get(arrayData.data); - size_t dataOffset = arrayData.offset; - if (num <= 0) break; - while (num > 0) { - size_t n = convertFromULongArray( - to, toOffset, num, data, dataOffset); - if (n <= 0) break; - len -= n; - num -= n; - ncopy += n; - offset += n; - toOffset += n; - } - } - break; - } - case pvFloat: { - PVFloatArray *pvfrom = (PVFloatArray*) from; - while (len > 0) { - size_t num = 0; - FloatArrayData floatArrayData = FloatArrayData(); - num = pvfrom->get(offset, len, floatArrayData); - float * data = get(floatArrayData.data); - size_t dataOffset = floatArrayData.offset; - if (num <= 0) break; - while (num > 0) { - size_t n = convertFromFloatArray( - to, toOffset, num, data, dataOffset); - if (n <= 0) break; - len -= n; - num -= n; - ncopy += n; - offset += n; - toOffset += n; - } - } - break; - } - case pvDouble: { - PVDoubleArray *pvfrom = (PVDoubleArray*) from; - while (len > 0) { - size_t num = 0; - DoubleArrayData doubleArrayData = DoubleArrayData(); - num = pvfrom->get(offset, len, doubleArrayData); - double * data = get(doubleArrayData.data); - size_t dataOffset = doubleArrayData.offset; - if (num <= 0) break; - while (num > 0) { - size_t n = convertFromDoubleArray( - to, toOffset, num, data, dataOffset); - if (n <= 0) break; - len -= n; - num -= n; - ncopy += n; - offset += n; - toOffset += n; - } - } - break; - } - case pvString: - throw std::logic_error(String("PVStringArray is not a numeric array")); - } - return ncopy; + *buffer += "\n"; + *buffer += String(indentLevel*4, ' '); } ConvertPtr Convert::getConvert() @@ -3328,8 +421,4 @@ ConvertPtr Convert::getConvert() return convert; } -ConvertPtr getConvert() { - return Convert::getConvert(); -} - }} diff --git a/pvDataApp/factory/FieldCreateFactory.cpp b/pvDataApp/factory/FieldCreateFactory.cpp index 7024cd7..e8444ba 100644 --- a/pvDataApp/factory/FieldCreateFactory.cpp +++ b/pvDataApp/factory/FieldCreateFactory.cpp @@ -66,7 +66,11 @@ struct StructureArrayHashFunction { Scalar::Scalar(ScalarType scalarType) - : Field(scalar),scalarType(scalarType){} + : Field(scalar),scalarType(scalarType) +{ + if(scalarTypepvString) + throw std::invalid_argument("Can't construct Scalar from invalid ScalarType"); +} Scalar::~Scalar(){} @@ -166,7 +170,11 @@ static StructureConstPtr deserializeStructureField(const FieldCreate* fieldCreat } ScalarArray::ScalarArray(ScalarType elementType) -: Field(scalarArray),elementType(elementType){} +: Field(scalarArray),elementType(elementType) +{ + if(elementTypepvString) + throw std::invalid_argument("Can't construct ScalarArray from invalid ScalarType"); +} ScalarArray::~ScalarArray() {} @@ -275,10 +283,12 @@ Structure::Structure ( } size_t number = fields.size(); for(size_t i=0; icapacityMutable = false; + capacityMutable = false; PVField::setImmutable(); } - size_t PVArray::getLength() const {return pImpl->length;} - - size_t PVArray::getCapacity() const {return pImpl->capacity;} - - static String fieldImmutable("field is immutable"); - - void PVArray::setLength(size_t length) { - if(length==pImpl->length) return; - if(PVField::isImmutable()) { - PVField::message(fieldImmutable,errorMessage); - return; - } - if(length>pImpl->capacity) this->setCapacity(length); - if(length>pImpl->capacity) length = pImpl->capacity; - pImpl->length = length; - } - - void PVArray::setCapacityLength(size_t capacity,size_t length) { - pImpl->capacity = capacity; - pImpl->length = length; - } - - bool PVArray::isCapacityMutable() const { if(PVField::isImmutable()) { return false; } - return pImpl->capacityMutable; + return capacityMutable; } void PVArray::setCapacityMutable(bool isMutable) { if(isMutable && PVField::isImmutable()) { - PVField::message(fieldImmutable,errorMessage); - return; + throw std::runtime_error("field is immutable"); } - pImpl->capacityMutable = isMutable; + capacityMutable = isMutable; } - static String capacityImmutable("capacity is immutable"); - - void PVArray::setCapacity(size_t capacity) { - if(PVField::isImmutable()) { - PVField::message(fieldImmutable,errorMessage); - return; - } - if(pImpl->capacityMutable==false) { - PVField::message(capacityImmutable,errorMessage); - return; - } - pImpl->capacity = capacity; - } std::ostream& operator<<(format::array_at_internal const& manip, const PVArray& array) { diff --git a/pvDataApp/factory/PVDataCreateFactory.cpp b/pvDataApp/factory/PVDataCreateFactory.cpp index baf1047..adf813f 100644 --- a/pvDataApp/factory/PVDataCreateFactory.cpp +++ b/pvDataApp/factory/PVDataCreateFactory.cpp @@ -28,6 +28,32 @@ using std::min; namespace epics { namespace pvData { +template<> const ScalarType PVBoolean::typeCode = pvBoolean; +template<> const ScalarType PVByte::typeCode = pvByte; +template<> const ScalarType PVShort::typeCode = pvShort; +template<> const ScalarType PVInt::typeCode = pvInt; +template<> const ScalarType PVLong::typeCode = pvLong; +template<> const ScalarType PVUByte::typeCode = pvUByte; +template<> const ScalarType PVUShort::typeCode = pvUShort; +template<> const ScalarType PVUInt::typeCode = pvUInt; +template<> const ScalarType PVULong::typeCode = pvULong; +template<> const ScalarType PVFloat::typeCode = pvFloat; +template<> const ScalarType PVDouble::typeCode = pvDouble; +template<> const ScalarType PVScalarValue::typeCode = pvString; + +template<> const ScalarType PVBooleanArray::typeCode = pvBoolean; +template<> const ScalarType PVByteArray::typeCode = pvByte; +template<> const ScalarType PVShortArray::typeCode = pvShort; +template<> const ScalarType PVIntArray::typeCode = pvInt; +template<> const ScalarType PVLongArray::typeCode = pvLong; +template<> const ScalarType PVUByteArray::typeCode = pvUByte; +template<> const ScalarType PVUShortArray::typeCode = pvUShort; +template<> const ScalarType PVUIntArray::typeCode = pvUInt; +template<> const ScalarType PVULongArray::typeCode = pvULong; +template<> const ScalarType PVFloatArray::typeCode = pvFloat; +template<> const ScalarType PVDoubleArray::typeCode = pvDouble; +template<> const ScalarType PVStringArray::typeCode = pvString; + /** Default storage for scalar values */ template @@ -170,157 +196,79 @@ public: typedef const std::vector const_vector; typedef std::tr1::shared_ptr shared_vector; + typedef ::epics::pvData::shared_vector svector; + typedef ::epics::pvData::shared_vector const_svector; + DefaultPVArray(ScalarArrayConstPtr const & scalarArray); virtual ~DefaultPVArray(); + + virtual size_t getLength() const {return value.size();} + virtual size_t getCapacity() const {return value.capacity();} + virtual void setCapacity(size_t capacity); virtual void setLength(size_t length); - virtual size_t get(size_t offset, size_t length, PVArrayData &data) ; - virtual size_t put(size_t offset,size_t length, const_pointer from, - size_t fromOffset); - virtual void shareData( - std::tr1::shared_ptr > const & value, - std::size_t capacity, - std::size_t length); - virtual pointer get() ; - virtual pointer get() const ; - virtual vector const & getVector() { return *value.get(); } - virtual shared_vector const & getSharedVector(){return value;}; + + virtual const_svector view() const {return value;} + virtual void swap(const_svector &other); + virtual void replace(const const_svector& next); + // from Serializable virtual void serialize(ByteBuffer *pbuffer,SerializableControl *pflusher) const; virtual void deserialize(ByteBuffer *pbuffer,DeserializableControl *pflusher); virtual void serialize(ByteBuffer *pbuffer, SerializableControl *pflusher, size_t offset, size_t count) const; private: - shared_vector value; + const_svector value; }; -template -T *DefaultPVArray::get() -{ - std::vector *vec = value.get(); - T *praw = &((*vec)[0]); - return praw; -} - -template -T *DefaultPVArray::get() const -{ - std::vector *vec = value.get(); - T *praw = &((*vec)[0]); - return praw; -} - - template DefaultPVArray::DefaultPVArray(ScalarArrayConstPtr const & scalarArray) : PVValueArray(scalarArray), - value(std::tr1::shared_ptr >(new std::vector())) + value() { } template DefaultPVArray::~DefaultPVArray() { } - template void DefaultPVArray::setCapacity(size_t capacity) { - if(PVArray::getCapacity()==capacity) return; - if(!PVArray::isCapacityMutable()) { - std::string message("not capacityMutable"); - PVField::message(message, errorMessage); - return; + if(this->isCapacityMutable()) { + value.reserve(capacity); } - size_t length = PVArray::getLength(); - if(length>capacity) length = capacity; - size_t oldCapacity = PVArray::getCapacity(); - if(oldCapacity>capacity) { - std::vector array; - array.reserve(capacity); - array.resize(length); - T * from = get(); - for (size_t i=0; iswap(array); - } else { - value->reserve(capacity); - } - PVArray::setCapacityLength(capacity,length); } template void DefaultPVArray::setLength(size_t length) { - if(PVArray::getLength()==length) return; - size_t capacity = PVArray::getCapacity(); - if(length>capacity) { - if(!PVArray::isCapacityMutable()) { - std::string message("not capacityMutable"); - PVField::message(message, errorMessage); - return; - } - setCapacity(length); - } - value->resize(length); - PVArray::setCapacityLength(capacity,length); + if(this->isImmutable()) + THROW_EXCEPTION2(std::logic_error,"Immutable"); + if(length == value.size()) + return; + else if(length < value.size()) + value.slice(0, length); + else + value.resize(length); } template -size_t DefaultPVArray::get(size_t offset, size_t len, PVArrayData &data) +void DefaultPVArray::replace(const const_svector& next) { - size_t n = len; - size_t length = this->getLength(); - if(offset+len > length) { - n = length-offset; - //if(n<0) n = 0; - } - data.data = *value.get(); - data.offset = offset; - return n; -} - -template -size_t DefaultPVArray::put(size_t offset,size_t len, - const_pointer from,size_t fromOffset) -{ - if(PVField::isImmutable()) { - PVField::message("field is immutable",errorMessage); - return 0; - } - T * pvalue = get(); - if(from==pvalue) return len; - if(len<1) return 0; - size_t length = this->getLength(); - size_t capacity = this->getCapacity(); - if(offset+len > length) { - size_t newlength = offset + len; - if(newlength>capacity) { - setCapacity(newlength); - newlength = this->getCapacity(); - len = newlength - offset; - if(len<=0) return 0; - } - length = newlength; - setLength(length); - } - pvalue = get(); - for(size_t i=0;isetLength(length); + value = next; this->postPut(); - return len; } template -void DefaultPVArray::shareData( - std::tr1::shared_ptr > const & sharedValue, - std::size_t capacity, - std::size_t length) +void DefaultPVArray::swap(const_svector &other) { - value = sharedValue; - PVArray::setCapacityLength(capacity,length); + if(this->isImmutable()) + THROW_EXCEPTION2(std::logic_error,"Immutable"); + + value.swap(other); } + template void DefaultPVArray::serialize(ByteBuffer *pbuffer, SerializableControl *pflusher) const { @@ -331,93 +279,92 @@ template void DefaultPVArray::deserialize(ByteBuffer *pbuffer, DeserializableControl *pcontrol) { size_t size = SerializeHelper::readSize(pbuffer, pcontrol); - // alignment if (size>0) { pcontrol->ensureData(sizeof(T)-1); pbuffer->align(sizeof(T)); } - //if(size>=0) { - // prepare array, if necessary - if(size>this->getCapacity()) this->setCapacity(size); - // set new length - this->setLength(size); - // try to avoid deserializing from the buffer - // this is only possible if we do not need to do endian-swapping - if (!pbuffer->reverse()) - if (pcontrol->directDeserialize(pbuffer, (char*)(get()), size, sizeof(T))) - { - // inform about the change? - PVField::postPut(); - return; - } + svector nextvalue(thaw(value)); + nextvalue.resize(size); // TODO: avoid copy of stuff we will then overwrite - // retrieve value from the buffer - size_t i = 0; - T * pvalue = get(); - while(true) { - /* - size_t maxIndex = min(size-i, (int)(pbuffer->getRemaining()/sizeof(T)))+i; - for(; iget(); - */ - size_t maxCount = min(size-i, (pbuffer->getRemaining()/sizeof(T))); - pbuffer->getArray(pvalue+i, maxCount); - i += maxCount; - - if(iensureData(sizeof(T)); // this is not OK since can exceen max local buffer (size-i)*sizeof(T)); - else - break; - } + T* cur = nextvalue.data(); + + // try to avoid deserializing from the buffer + // this is only possible if we do not need to do endian-swapping + if (!pbuffer->reverse()) + if (pcontrol->directDeserialize(pbuffer, (char*)cur, size, sizeof(T))) + { // inform about the change? PVField::postPut(); - //} - // TODO null arrays (size == -1) not supported + return; + } + + // retrieve value from the buffer + size_t remaining = size; + while(remaining) { + const size_t have_bytes = pbuffer->getRemaining(); + + // correctly rounds down in an element is partially received + const size_t available = have_bytes/sizeof(T); + + if(available == 0) { + size_t want = sizeof(T); + if(remaining==1 && sizeof(T)>1) { + // Need to wait for the last few bytes + // of the final element. + // available==0 implies have_bytesensureData(want); + continue; + } + + const size_t n2read = std::min(remaining, available); + + pbuffer->getArray(cur, n2read); + cur += n2read; + remaining -= n2read; + } + value = freeze(nextvalue); + // inform about the change? + PVField::postPut(); } template void DefaultPVArray::serialize(ByteBuffer *pbuffer, - SerializableControl *pflusher, size_t offset, size_t count) const { - // cache - size_t length = this->getLength(); + SerializableControl *pflusher, size_t offset, size_t count) const +{ + //TODO: avoid incrementing the ref counter... + const_svector temp(value); + temp.slice(offset, count); + count = temp.size(); - // check bounds - /*if(offset<0) - offset = 0; - else*/ if(offset>length) offset = length; - //if(count<0) count = length; - - size_t maxCount = length-offset; - if(count>maxCount) count = maxCount; - - // write - SerializeHelper::writeSize(count, pbuffer, pflusher); - //if (count == 0) return; pcontrol->ensureData(sizeof(T)-1); pbuffer->align(sizeof(T)); + SerializeHelper::writeSize(temp.size(), pbuffer, pflusher); + const T* cur = temp.data(); // try to avoid copying into the buffer // this is only possible if we do not need to do endian-swapping if (!pbuffer->reverse()) - if (pflusher->directSerialize(pbuffer, (const char*)(get()+offset), count, sizeof(T))) + if (pflusher->directSerialize(pbuffer, (const char*)cur, count, sizeof(T))) return; - size_t end = offset+count; - size_t i = offset; - T * pvalue = const_cast(get()); - while(true) { - - /* - size_t maxIndex = min(end-i, (int)(pbuffer->getRemaining()/sizeof(T)))+i; - for(; iput(value[i]); - */ - - size_t maxCount = min(end-i, (int)(pbuffer->getRemaining()/sizeof(T))); - pbuffer->putArray(pvalue+i, maxCount); - i += maxCount; - - if(igetRemaining(); + const size_t space_for = empty/sizeof(T); + + if(space_for==0) { pflusher->flushSerializeBuffer(); - else - break; + // Can we be certain that more space is now free??? + // If not then we spinnnnnnnnn + continue; + } + + const size_t n2send = std::min(count, space_for); + + pbuffer->putArray(cur, n2send); + cur += n2send; + count -= n2send; } + + pflusher->flushSerializeBuffer(); } // specializations for String @@ -426,42 +373,37 @@ template<> void DefaultPVArray::deserialize(ByteBuffer *pbuffer, DeserializableControl *pcontrol) { size_t size = SerializeHelper::readSize(pbuffer, pcontrol); - //if(size>=0) { - // prepare array, if necessary - if(size>getCapacity()) setCapacity(size); - // set new length - setLength(size); - // retrieve value from the buffer - String * pvalue = get(); - for(size_t i = 0; i nextvalue.size() || !nextvalue.unique()) + nextvalue.resize(size); + else if(size < nextvalue.size()) + nextvalue.slice(0, size); + + + String * pvalue = nextvalue.data(); + for(size_t i = 0; i void DefaultPVArray::serialize(ByteBuffer *pbuffer, SerializableControl *pflusher, size_t offset, size_t count) const { - size_t length = getLength(); - // check bounds - /*if(offset<0) - offset = 0; - else*/ if(offset>length) offset = length; - //if(count<0) count = length; + const_svector temp(value); + temp.slice(offset, count); - size_t maxCount = length-offset; - if(count>maxCount) count = maxCount; + SerializeHelper::writeSize(temp.size(), pbuffer, pflusher); - // write - SerializeHelper::writeSize(count, pbuffer, pflusher); - size_t end = offset+count; - String * pvalue = get(); - for(size_t i = offset; igetScalarArray()->getElementType()); - getConvert()->copyScalarArray(arrayToClone,0, pvArray,0,arrayToClone->getLength()); + pvArray->assign(*arrayToClone.get()); PVAuxInfoPtr from = arrayToClone->getPVAuxInfo(); PVAuxInfoPtr to = pvArray->getPVAuxInfo(); PVAuxInfo::PVInfoMap & map = from->getInfoMap(); diff --git a/pvDataApp/factory/PVField.cpp b/pvDataApp/factory/PVField.cpp index e4574d9..e9cd3b7 100644 --- a/pvDataApp/factory/PVField.cpp +++ b/pvDataApp/factory/PVField.cpp @@ -26,8 +26,7 @@ PVField::PVField(FieldConstPtr field) : notImplemented("not implemented"), parent(NULL),field(field), fieldOffset(0), nextFieldOffset(0), - immutable(false), - convert(getConvert()) + immutable(false) { } @@ -64,11 +63,6 @@ void PVField::message(String message,MessageType messageType) PVField::message(message,messageType,""); } -String PVField::getFieldName() const -{ - return fieldName; -} - void PVField::setRequester(RequesterPtr const &req) { if(parent!=NULL) { @@ -180,7 +174,7 @@ void PVField::setParentAndName(PVStructure * xxx,String const & name) bool PVField::equals(PVField &pv) { - return convert->equals(*this,pv); + return pv==*this; } void PVField::toString(StringBuilder buf) @@ -190,7 +184,7 @@ void PVField::toString(StringBuilder buf) void PVField::toString(StringBuilder buf,int indentLevel) { - convert->getString(buf,this,indentLevel); + Convert().getString(buf,this,indentLevel); if(pvAuxInfo.get()!=NULL) pvAuxInfo->toString(buf,indentLevel); } @@ -223,6 +217,31 @@ namespace format } }; +String PVField::getFullName() const +{ + size_t size=fieldName.size(); + + for(PVField *fld=getParent(); fld; fld=fld->getParent()) + { + size+=fld->fieldName.size()+1; + } + + 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; +} + void PVField::computeOffset(const PVField * pvField) { const PVStructure * pvTop = pvField->getParent(); if(pvTop==NULL) { diff --git a/pvDataApp/factory/PVScalarArray.cpp b/pvDataApp/factory/PVScalarArray.cpp index 86f1821..19d0339 100644 --- a/pvDataApp/factory/PVScalarArray.cpp +++ b/pvDataApp/factory/PVScalarArray.cpp @@ -28,16 +28,4 @@ namespace epics { namespace pvData { return static_pointer_cast(PVField::getField()); } - template<> - std::ostream& PVValueArray::dumpValue(std::ostream& o, size_t index) const - { - return o << static_cast(*(get() + index)); - } - - template<> - std::ostream& PVValueArray::dumpValue(std::ostream& o, size_t index) const - { - return o << static_cast(*(get() + index)); - } - }} diff --git a/pvDataApp/factory/PVStructureArray.cpp b/pvDataApp/factory/PVStructureArray.cpp index d08b6a4..c22ca1c 100644 --- a/pvDataApp/factory/PVStructureArray.cpp +++ b/pvDataApp/factory/PVStructureArray.cpp @@ -21,44 +21,52 @@ using std::size_t; namespace epics { namespace pvData { -PVStructureArray::PVStructureArray(StructureArrayConstPtr const & structureArray) -: PVArray(structureArray), - structureArray(structureArray), - value(std::tr1::shared_ptr(new PVStructurePtrArray())) -{ -} - size_t PVStructureArray::append(size_t number) { - size_t currentLength = getLength(); - size_t newLength = currentLength + number; - setCapacity(newLength); - setLength(newLength); + svector data(reuse()); + data.resize(data.size()+number); + StructureConstPtr structure = structureArray->getStructure(); - PVStructurePtrArray *to = value.get(); - for(size_t i=currentLength; icreatePVStructure(structure); - } + + for(svector::reverse_iterator it = data.rbegin(); number; ++it, --number) + *it = getPVDataCreate()->createPVStructure(structure); + + size_t newLength = data.size(); + + const_svector cdata(freeze(data)); + swap(cdata); + return newLength; } bool PVStructureArray::remove(size_t offset,size_t number) { - size_t length = getLength(); - if(offset+number>length) return false; - PVStructurePtrArray vec = *value.get(); + if(number==0) + return true; + else if(offset+number>getLength()) + return false; + + svector vec(reuse()); + + size_t length = vec.size(); + for(size_t i = offset; i+number < length; i++) { - vec[i] = vec[i + number]; + vec[i].swap(vec[i + number]); } - size_t newLength = length - number; - setCapacityLength(newLength,newLength); + + vec.resize(length - number); + const_svector cdata(freeze(vec)); + swap(cdata); + return true; } void PVStructureArray::compress() { - size_t length = getCapacity(); + svector vec(reuse()); // TODO: check for first NULL before realloc + + size_t length = vec.size(); size_t newLength = 0; - PVStructurePtrArray vec = *value.get(); + for(size_t i=0; iisCapacityMutable()) { + const_svector value; + swap(value); + if(value.capacity()capacity) length = capacity; - size_t oldCapacity = getCapacity(); - if(oldCapacity>capacity) { - PVStructurePtrArray array; - array.reserve(capacity); - array.resize(length); - PVStructurePtr * from = get(); - for (size_t i=0; iswap(array); +} + +void PVStructureArray::setLength(size_t length) +{ + if(this->isImmutable()) + THROW_EXCEPTION2(std::logic_error,"Immutable"); + const_svector value; + swap(value); + if(length == value.size()) { + // nothing + } else if(length < value.size()) { + value.slice(0, length); } else { - value->reserve(capacity); + svector mvalue(thaw(value)); + mvalue.resize(length); + value = freeze(mvalue); } - setCapacityLength(capacity,length); + swap(value); } -void PVStructureArray::setLength(size_t length) { - if(PVArray::getLength()==length) return; - size_t capacity = PVArray::getCapacity(); - if(length>capacity) { - if(!PVArray::isCapacityMutable()) { - std::string message("not capacityMutable"); - PVField::message(message, errorMessage); - return; - } - setCapacity(length); - } - value->resize(length); - PVArray::setCapacityLength(capacity,length); -} - -StructureArrayConstPtr PVStructureArray::getStructureArray() const +void PVStructureArray::swap(const_svector &other) { - return structureArray; -} + if(this->isImmutable()) + THROW_EXCEPTION2(std::logic_error,"Immutable"); -size_t PVStructureArray::get( - size_t offset, size_t len, StructureArrayData &data) -{ - size_t n = len; - size_t length = getLength(); - if(offset+len > length) { - n = length - offset; - //if(n<0) n = 0; - } - data.data = *value.get(); - data.offset = offset; - return n; -} - -size_t PVStructureArray::put(size_t offset,size_t len, - const_vector const & from, size_t fromOffset) -{ - if(isImmutable()) { - message(String("field is immutable"), errorMessage); - return 0; - } - if(&from==value.get()) return 0; - if(len<1) return 0; - size_t length = getLength(); - size_t capacity = getCapacity(); - if(offset+len > length) { - size_t newlength = offset + len; - if(newlength>capacity) { - setCapacity(newlength); - capacity = getCapacity(); - newlength = capacity; - len = newlength - offset; - if(len<=0) return 0; - } - length = newlength; - setLength(length); - } - PVStructurePtrArray *to = value.get(); - StructureConstPtr structure = structureArray->getStructure(); - for(size_t i=0; igetStructure()!=structure) { - throw std::invalid_argument(String( - "Element is not a compatible structure")); - } - } - (*to)[i+offset] = frompv; - } - postPut(); - setLength(length); - return len; -} - -void PVStructureArray::shareData( - std::tr1::shared_ptr > const & sharedValue, - std::size_t capacity, - std::size_t length) -{ - value = sharedValue; - setCapacityLength(capacity,length); + value.swap(other); } void PVStructureArray::serialize(ByteBuffer *pbuffer, @@ -196,56 +141,47 @@ void PVStructureArray::serialize(ByteBuffer *pbuffer, void PVStructureArray::deserialize(ByteBuffer *pbuffer, DeserializableControl *pcontrol) { + svector data(reuse()); + size_t size = SerializeHelper::readSize(pbuffer, pcontrol); - //if(size>=0) { - // prepare array, if necessary - if(size>getCapacity()) setCapacity(size); - setLength(size); - PVStructurePtrArray *pvArray = value.get(); - for(size_t i = 0; iensureData(1); - size_t temp = pbuffer->getByte(); - if(temp==0) { - (*pvArray)[i].reset(); - } - else { - if((*pvArray)[i].get()==NULL) { - StructureConstPtr structure = structureArray->getStructure(); - (*pvArray)[i] = getPVDataCreate()->createPVStructure(structure); - } - (*pvArray)[i]->deserialize(pbuffer, pcontrol); - } + data.resize(size); + + StructureConstPtr structure = structureArray->getStructure(); + + for(size_t i = 0; iensureData(1); + size_t temp = pbuffer->getByte(); + if(temp==0) { + data[i].reset(); } - postPut(); - //} + else { + if(data[i].get()==NULL) { + data[i] = getPVDataCreate()->createPVStructure(structure); + } + data[i]->deserialize(pbuffer, pcontrol); + } + } + replace(freeze(data)); // calls postPut() } void PVStructureArray::serialize(ByteBuffer *pbuffer, SerializableControl *pflusher, size_t offset, size_t count) const { - // cache - size_t length = getLength(); - // check bounds - /*if(offset<0) - offset = 0; - else*/ if(offset>length) offset = length; - //if(count<0) count = length; + const_svector temp(view()); + temp.slice(offset, count); - size_t maxCount = length-offset; - if(count>maxCount) count = maxCount; + SerializeHelper::writeSize(temp.size(), pbuffer, pflusher); - PVStructurePtrArray pvArray = *value.get(); - // write - SerializeHelper::writeSize(count, pbuffer, pflusher); for(size_t i = 0; igetRemaining()<1) pflusher->flushSerializeBuffer(); - PVStructurePtr pvStructure = pvArray[i+offset]; - if(pvStructure.get()==NULL) { + if(pbuffer->getRemaining()<1) + pflusher->flushSerializeBuffer(); + + if(temp[i].get()==NULL) { pbuffer->putByte(0); } else { pbuffer->putByte(1); - pvStructure->serialize(pbuffer, pflusher); + temp[i]->serialize(pbuffer, pflusher); } } } @@ -267,9 +203,9 @@ std::ostream& PVStructureArray::dumpValue(std::ostream& o) const std::ostream& PVStructureArray::dumpValue(std::ostream& o, std::size_t index) const { - PVStructurePtrArray pvArray = *value.get(); - PVStructurePtr pvStructure = pvArray[index]; - return o << *(pvStructure.get()); + const_svector temp(view()); + if(indexcreatePVStructure(field); PVScalarArrayPtr pvScalarArray = pvStructure->getScalarArrayField( "choices",pvString); - if(pvScalarArray.get()==NULL) { - throw std::logic_error(String("StandardPVField::enumerated")); - } - PVStringArray * pvChoices = static_cast(pvScalarArray.get()); - pvChoices->put(0,choices.size(),get(choices),0); + PVStringArray::svector cdata(choices.size()); + std::copy(choices.begin(), choices.end(), cdata.begin()); + static_cast(*pvScalarArray).replace(freeze(cdata)); return pvStructure; } @@ -74,11 +72,9 @@ PVStructurePtr StandardPVField::enumerated( PVStructurePtr pvStructure = pvDataCreate->createPVStructure(field); PVScalarArrayPtr pvScalarArray = pvStructure->getScalarArrayField( "value.choices",pvString); - if(pvScalarArray.get()==NULL) { - throw std::logic_error(String("StandardPVField::enumerated")); - } - PVStringArray * pvChoices = static_cast(pvScalarArray.get()); - pvChoices->put(0,choices.size(),get(choices),0); + PVStringArray::svector cdata(choices.size()); + std::copy(choices.begin(), choices.end(), cdata.begin()); + static_cast(*pvScalarArray).replace(freeze(cdata)); return pvStructure; } diff --git a/pvDataApp/factory/TypeFunc.cpp b/pvDataApp/factory/TypeFunc.cpp index 68075b3..3d1a51a 100644 --- a/pvDataApp/factory/TypeFunc.cpp +++ b/pvDataApp/factory/TypeFunc.cpp @@ -14,6 +14,7 @@ #include #include +#include #include "dbDefs.h" // for NELEMENTS @@ -61,7 +62,7 @@ namespace ScalarTypeFunc { "ubyte", "ushort", "uint", "ulong", "float", "double", "string", }; - ScalarType getScalarType(String pvalue) { + ScalarType getScalarType(const String& pvalue) { for(size_t i=0; i allocArray(ScalarType id, size_t len) + { + switch(id) { +#define OP(ENUM, TYPE) case ENUM: return static_shared_vector_cast(shared_vector(len)) + OP(pvBoolean, boolean); + OP(pvUByte, uint8); + OP(pvByte, int8); + OP(pvUShort, uint16); + OP(pvShort, int16); + OP(pvUInt, uint32); + OP(pvInt, int32); + OP(pvULong, uint64); + OP(pvLong, int64); + OP(pvFloat, float); + OP(pvDouble, double); + OP(pvString, String); +#undef OP + default: + throw std::bad_alloc(); + } + } + } // namespace ScalarTypeFunc }} diff --git a/pvDataApp/factory/printer.cpp b/pvDataApp/factory/printer.cpp new file mode 100644 index 0000000..f6e3a96 --- /dev/null +++ b/pvDataApp/factory/printer.cpp @@ -0,0 +1,201 @@ + +#include + +#include "pv/printer.h" + +namespace { + +void indentN(std::ostream& strm, size_t N) +{ + while(N--) + strm.put(' '); +} + +} + +namespace epics { namespace pvData { + +PrinterBase::PrinterBase() + :strm(NULL) +{} + +PrinterBase::~PrinterBase() {} + +void PrinterBase::setStream(std::ostream& s) +{ + strm = &s; +} + +void PrinterBase::clearStream() +{ + strm = NULL; +} + +void PrinterBase::print(const PVField& pv) +{ + if(!strm) + throw std::runtime_error("No stream set for PV Printer"); + impl_print(pv); +} + +void PrinterBase::beginStructure(const PVStructure&) {} +void PrinterBase::endStructure(const PVStructure&) {} + +void PrinterBase::beginStructureArray(const PVStructureArray&) {} +void PrinterBase::endStructureArray(const PVStructureArray&) {} + +void PrinterBase::encodeScalar(const PVScalar& pv) {} + +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 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(inprog.back())); + break; + + case structureArray: + endStructureArray(*static_cast(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(next)); + break; + case scalarArray: + encodeArray(*static_cast(next)); + break; + case structure: { + const PVStructure &fld = *static_cast(next); + const PVFieldPtrArray& vals = fld.getPVFields(); + + inprog.push_back(next); + + beginStructure(fld); + for(size_t i=0, nfld=fld.getStructure()->getNumberFields(); i(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; + } + } + } + } +} + + +PrinterPlain::PrinterPlain() + :PrinterBase() + ,ilvl(0) +{} + +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::encodeScalar(const PVScalar& pv) +{ + indentN(S(), ilvl); + S() << pv.getScalar()->getID() << " " + << pv.getFieldName() << " " + << pv.getAs() << std::endl; +} + +void PrinterPlain::encodeArray(const PVScalarArray& pv) +{ + indentN(S(), ilvl); + shared_vector temp; + pv.getAs(temp); + + S() << pv.getScalarArray()->getID() << " " + << pv.getFieldName() << " ["; + for(size_t i=0, len=pv.getLength(); i - inline void putArray(T* values, std::size_t count); + inline void putArray(const T* values, std::size_t count); /** * Get an array of type {@code T} from the byte buffer. * The position is adjusted. @@ -842,7 +842,7 @@ private: } template - inline void ByteBuffer::putArray(T* values, std::size_t count) + inline void ByteBuffer::putArray(const T* values, std::size_t count) { // this avoids int8 specialization, compiler will take care if optimization, -O2 or more if (sizeof(T) == 1) diff --git a/pvDataApp/misc/epicsException.h b/pvDataApp/misc/epicsException.h index 24025cd..b7bfad6 100644 --- a/pvDataApp/misc/epicsException.h +++ b/pvDataApp/misc/epicsException.h @@ -103,7 +103,7 @@ namespace detail { * * Takes advantage of the requirement that all exception classes * must be copy constructable. Of course this also requires - * the and extra copy be constructed... + * that an extra copy be constructed... */ template class ExceptionMixed : public E, public ExceptionMixin { diff --git a/pvDataApp/misc/parseToPOD.cpp b/pvDataApp/misc/parseToPOD.cpp new file mode 100644 index 0000000..e947c69 --- /dev/null +++ b/pvDataApp/misc/parseToPOD.cpp @@ -0,0 +1,467 @@ +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "typeCast.h" + +// need to use "long long" when sizeof(int)==sizeof(long) +#if ULONG_MAX == 0xfffffffful +#define NEED_LONGLONG +#endif + +#ifndef EPICS_VERSION_INT +#define VERSION_INT(V,R,M,P) ( ((V)<<24) | ((R)<<16) | ((M)<<8) | (P)) +#define EPICS_VERSION_INT VERSION_INT(EPICS_VERSION, EPICS_REVISION, EPICS_MODIFICATION, EPICS_PATCH_LEVEL) +#endif + +#if EPICS_VERSION_INT < VERSION_INT(3,15,0,1) +/* integer conversion primatives added to epicsStdlib.c in 3.15.0.1 */ + +#define S_stdlib_noConversion 1 /* No digits to convert */ +#define S_stdlib_extraneous 2 /* Extraneous characters */ +#define S_stdlib_underflow 3 /* Too small to represent */ +#define S_stdlib_overflow 4 /* Too large to represent */ +#define S_stdlib_badBase 5 /* Number base not supported */ + +static int +epicsParseLong(const char *str, long *to, int base, char **units) +{ + int c; + char *endp; + long value; + + while ((c = *str) && isspace(c)) + ++str; + + errno = 0; + value = strtol(str, &endp, base); + + if (endp == str) + return S_stdlib_noConversion; + if (errno == EINVAL) /* Not universally supported */ + return S_stdlib_badBase; + if (errno == ERANGE) + return S_stdlib_overflow; + + while ((c = *endp) && isspace(c)) + ++endp; + if (c && !units) + return S_stdlib_extraneous; + + *to = value; + if (units) + *units = endp; + return 0; +} + +static int +epicsParseULong(const char *str, unsigned long *to, int base, char **units) +{ + int c; + char *endp; + unsigned long value; + + while ((c = *str) && isspace(c)) + ++str; + + errno = 0; + value = strtoul(str, &endp, base); + + if (endp == str) + return S_stdlib_noConversion; + if (errno == EINVAL) /* Not universally supported */ + return S_stdlib_badBase; + if (errno == ERANGE) + return S_stdlib_overflow; + + while ((c = *endp) && isspace(c)) + ++endp; + if (c && !units) + return S_stdlib_extraneous; + + *to = value; + if (units) + *units = endp; + return 0; +} + +static int +epicsParseDouble(const char *str, double *to, char **units) +{ + int c; + char *endp; + double value; + + while ((c = *str) && isspace(c)) + ++str; + + errno = 0; + value = epicsStrtod(str, &endp); + + if (endp == str) + return S_stdlib_noConversion; + if (errno == ERANGE) + return (value == 0) ? S_stdlib_underflow : S_stdlib_overflow; + + while ((c = *endp) && isspace(c)) + ++endp; + if (c && !units) + return S_stdlib_extraneous; + + *to = value; + if (units) + *units = endp; + return 0; +} + + +/* These call the primitives */ + +static int +epicsParseInt8(const char *str, epicsInt8 *to, int base, char **units) +{ + long value; + int status = epicsParseLong(str, &value, base, units); + + if (status) + return status; + + if (value < -0x80 || value > 0x7f) + return S_stdlib_overflow; + + *to = value; + return 0; +} + +static int +epicsParseUInt8(const char *str, epicsUInt8 *to, int base, char **units) +{ + unsigned long value; + int status = epicsParseULong(str, &value, base, units); + + if (status) + return status; + + if (value > 0xff && value <= ~0xffUL) + return S_stdlib_overflow; + + *to = value; + return 0; +} + +static int +epicsParseInt16(const char *str, epicsInt16 *to, int base, char **units) +{ + long value; + int status = epicsParseLong(str, &value, base, units); + + if (status) + return status; + + if (value < -0x8000 || value > 0x7fff) + return S_stdlib_overflow; + + *to = value; + return 0; +} + +static int +epicsParseUInt16(const char *str, epicsUInt16 *to, int base, char **units) +{ + unsigned long value; + int status = epicsParseULong(str, &value, base, units); + + if (status) + return status; + + if (value > 0xffff && value <= ~0xffffUL) + return S_stdlib_overflow; + + *to = value; + return 0; +} + +static int +epicsParseInt32(const char *str, epicsInt32 *to, int base, char **units) +{ + long value; + int status = epicsParseLong(str, &value, base, units); + + if (status) + return status; + +#if (LONG_MAX > 0x7fffffff) + if (value < -0x80000000L || value > 0x7fffffffL) + return S_stdlib_overflow; +#endif + + *to = value; + return 0; +} + +static int +epicsParseUInt32(const char *str, epicsUInt32 *to, int base, char **units) +{ + unsigned long value; + int status = epicsParseULong(str, &value, base, units); + + if (status) + return status; + +#if (ULONG_MAX > 0xffffffff) + if (value > 0xffffffffUL && value <= ~0xffffffffUL) + return S_stdlib_overflow; +#endif + + *to = value; + return 0; +} + +static int +epicsParseFloat(const char *str, float *to, char **units) +{ + double value, abs; + int status = epicsParseDouble(str, &value, units); + + if (status) + return status; + + abs = fabs(value); + if (value > 0 && abs <= FLT_MIN) + return S_stdlib_underflow; + if (finite(value) && abs >= FLT_MAX) + return S_stdlib_overflow; + + *to = value; + return 0; +} +#endif + +#if defined(NEED_LONGLONG) && defined(__vxworks) +static +long long strtoll(const char *ptr, char ** endp, int base) +{ + size_t inlen = strlen(ptr); + long long result; + unsigned char offset=0; + + assert(base==0); + + if(ptr[0]=='-') + offset=1; + + try { + std::istringstream strm(ptr); + + assert(strm.rdbuf()->in_avail()>=0 + && inlen==(size_t)strm.rdbuf()->in_avail()); + + if(ptr[offset]=='0') { + if(ptr[offset+1]=='x') + strm >> std::hex; + else + strm >> std::oct; + } + + strm >> result; + if(strm.fail()) + goto noconvert; + + assert(strm.rdbuf()->in_avail()>=0 + && inlen>=(size_t)strm.rdbuf()->in_avail()); + + size_t consumed = inlen - strm.rdbuf()->in_avail(); + *endp = (char*)ptr + consumed; + + return result; + + } catch(...) { + goto noconvert; + } + + return result; +noconvert: + *endp = (char*)ptr; + return 0; +} + +static +unsigned long long strtoull(const char *ptr, char ** endp, int base) +{ + size_t inlen = strlen(ptr); + unsigned long long result; + + assert(base==0); + + try { + std::istringstream strm(ptr); + + assert(strm.rdbuf()->in_avail()>=0 + && inlen==(size_t)strm.rdbuf()->in_avail()); + + if(ptr[0]=='0') { + if(ptr[1]=='x') + strm >> std::hex; + else + strm >> std::oct; + } + + strm >> result; + if(strm.fail()) + goto noconvert; + + assert(strm.rdbuf()->in_avail()>=0 + && inlen>=(size_t)strm.rdbuf()->in_avail()); + + size_t consumed = inlen - strm.rdbuf()->in_avail(); + *endp = (char*)ptr + consumed; + + return result; + + } catch(...) { + goto noconvert; + } + + return result; +noconvert: + *endp = (char*)ptr; + return 0; +} + +#endif + +/* do we need long long? */ +#ifdef NEED_LONGLONG +static int +epicsParseLongLong(const char *str, long long *to, int base, char **units) +{ + int c; + char *endp; + long long value; + + while ((c = *str) && isspace(c)) + ++str; + + errno = 0; + value = strtoll(str, &endp, base); + + if (endp == str) + return S_stdlib_noConversion; + if (errno == EINVAL) /* Not universally supported */ + return S_stdlib_badBase; + if (errno == ERANGE) + return S_stdlib_overflow; + + while ((c = *endp) && isspace(c)) + ++endp; + if (c && !units) + return S_stdlib_extraneous; + + *to = value; + if (units) + *units = endp; + return 0; +} + +static int +epicsParseULongLong(const char *str, unsigned long long *to, int base, char **units) +{ + int c; + char *endp; + unsigned long long value; + + while ((c = *str) && isspace(c)) + ++str; + + errno = 0; + value = strtoull(str, &endp, base); + + if (endp == str) + return S_stdlib_noConversion; + if (errno == EINVAL) /* Not universally supported */ + return S_stdlib_badBase; + if (errno == ERANGE) + return S_stdlib_overflow; + + while ((c = *endp) && isspace(c)) + ++endp; + if (c && !units) + return S_stdlib_extraneous; + + *to = value; + if (units) + *units = endp; + return 0; +} +#endif + +static +void handleParseError(int err) +{ + switch(err) { + case 0: break; + case S_stdlib_noConversion: throw std::runtime_error("parseToPOD: No digits to convert"); + case S_stdlib_extraneous: throw std::runtime_error("parseToPOD: Extraneous characters"); + case S_stdlib_underflow: throw std::runtime_error("parseToPOD: Too small to represent"); + case S_stdlib_overflow: throw std::runtime_error("parseToPOD: Too large to represent"); + case S_stdlib_badBase: throw std::runtime_error("parseToPOD: Number base not supported"); + default: + throw std::runtime_error("parseToPOD: unknown error"); + } +} + +namespace epics { namespace pvData { namespace detail { + +#define INTFN(T, S) \ +void parseToPOD(const std::string& in, T *out) { \ + epics ## S temp; \ + int err = epicsParse ## S (in.c_str(), &temp, 0, NULL); \ + if(err) handleParseError(err); \ + else *out = temp; \ +} + +INTFN(char, Int8); +INTFN(int8_t, Int8); +INTFN(uint8_t, UInt8); +INTFN(int16_t, Int16); +INTFN(uint16_t, UInt16); +INTFN(int32_t, Int32); +INTFN(uint32_t, UInt32); + +void parseToPOD(const std::string& in, int64_t *out) { +#ifdef NEED_LONGLONG + int err = epicsParseLongLong(in.c_str(), out, 0, NULL); +#else + int err = epicsParseLong(in.c_str(), out, 0, NULL); +#endif + if(err) handleParseError(err); +} + +void parseToPOD(const std::string& in, uint64_t *out) { +#ifdef NEED_LONGLONG + int err = epicsParseULongLong(in.c_str(), out, 0, NULL); +#else + int err = epicsParseULong(in.c_str(), out, 0, NULL); +#endif + if(err) handleParseError(err); +} + +void parseToPOD(const std::string& in, float *out) { + int err = epicsParseFloat(in.c_str(), out, NULL); + if(err) handleParseError(err); +} + +void parseToPOD(const std::string& in, double *out) { + int err = epicsParseDouble(in.c_str(), out, NULL); + if(err) handleParseError(err); +} + +}}} diff --git a/pvDataApp/misc/sharedPtr.h b/pvDataApp/misc/sharedPtr.h index f896eaf..0a1ed76 100644 --- a/pvDataApp/misc/sharedPtr.h +++ b/pvDataApp/misc/sharedPtr.h @@ -4,7 +4,7 @@ * in file LICENSE that is included with this distribution. */ /** - * @author Michael DavidSaver + * @author Michael Davidsaver */ #ifndef SHAREDPTR_H diff --git a/pvDataApp/misc/sharedVector.h b/pvDataApp/misc/sharedVector.h new file mode 100644 index 0000000..cd8ee39 --- /dev/null +++ b/pvDataApp/misc/sharedVector.h @@ -0,0 +1,1006 @@ +#ifndef SHAREDVECTOR_H +#define SHAREDVECTOR_H + +#include +#include +#include +#include + +#include + +#include "pv/sharedPtr.h" +#include "pv/pvIntrospect.h" +#include "pv/typeCast.h" +#include "pv/templateMeta.h" + +namespace epics { namespace pvData { + +template class shared_vector; + +template +static FORCE_INLINE +shared_vector +const_shared_vector_cast(shared_vector& src); + +namespace detail { + template + struct default_array_deleter {void operator()(E a){delete[] a;}}; + + // How values should be passed as arguments to shared_vector methods + // really should use boost::call_traits + template struct call_with { typedef T type; }; + template struct call_with > + { typedef const std::tr1::shared_ptr& type; }; + template<> struct call_with { typedef const std::string& type; }; + + struct _shared_vector_freeze_tag {}; + struct _shared_vector_thaw_tag {}; + struct _shared_vector_cast_tag {}; + + /* All the parts of shared_vector which + * don't need special handling for E=void + */ + template + class shared_vector_base + { + // allow specialization for all E to be friends + template friend class shared_vector_base; + protected: + std::tr1::shared_ptr m_data; + //! Offset in the data array of first visible element + size_t m_offset; + //! Number of visible elements between m_offset and end of data + size_t m_count; + //! Total number of elements between m_offset and the end of data + size_t m_total; + + /* invariants + * m_count <= m_total (enforced) + * m_offset + m_total <= (size_t)-1 (checked w/ assert()) + */ + + public: + + //! @brief Empty vector (not very interesting) + shared_vector_base() + :m_data(), m_offset(0), m_count(0), m_total(0) + {} + + protected: + // helper for constructors + // Ensure that offset and size are zero when we are constructed with NULL + void _null_input() + { + if(!m_data.get()) { + m_offset = m_total = m_count = 0; + } else { + // ensure we won't have integer overflows later + assert( m_offset <= ((size_t)-1) - m_total); + } + } + public: + + template + shared_vector_base(A v, size_t o, size_t c) + :m_data(v, detail::default_array_deleter()) + ,m_offset(o), m_count(c), m_total(c) + {_null_input();} + + shared_vector_base(const std::tr1::shared_ptr& d, size_t o, size_t c) + :m_data(d), m_offset(o), m_count(c), m_total(c) + {_null_input();} + + + template + shared_vector_base(A d, B b, size_t o, size_t c) + :m_data(d,b), m_offset(o), m_count(c), m_total(c) + {_null_input();} + + shared_vector_base(const shared_vector_base& O) + :m_data(O.m_data), m_offset(O.m_offset) + ,m_count(O.m_count), m_total(O.m_total) + {} + + protected: + typedef typename meta::strip_const::type _E_non_const; + public: + //! Constructor used to implement freeze(). + //! Should not be called directly. + shared_vector_base(shared_vector_base<_E_non_const>& O, + _shared_vector_freeze_tag) + :m_data() + ,m_offset(O.m_offset) + ,m_count(O.m_count) + ,m_total(O.m_total) + { + if(!O.unique()) + throw std::runtime_error("Can't freeze non-unique vector"); + m_data = O.m_data; + O.clear(); + } + + //! Constructor used to implement thaw(). + //! Should not be called directly. + shared_vector_base(shared_vector& O, + _shared_vector_thaw_tag) + :m_data() + ,m_offset(O.m_offset) + ,m_count(O.m_count) + ,m_total(O.m_total) + { + O.make_unique(); + m_data = std::tr1::const_pointer_cast(O.m_data); + O.clear(); + } + + //! @brief Copy an existing vector + shared_vector_base& operator=(const shared_vector_base& o) + { + if(&o!=this) { + m_data=o.m_data; + m_offset=o.m_offset; + m_count=o.m_count; + m_total=o.m_total; + } + return *this; + } + + //! @brief Swap the contents of this vector with another + void swap(shared_vector_base& o) { + if(&o!=this) { + m_data.swap(o.m_data); + std::swap(m_count, o.m_count); + std::swap(m_offset, o.m_offset); + std::swap(m_total, o.m_total); + } + } + + //! @brief Clear contents. + //! size() becomes 0 + void clear() { + m_data.reset(); + m_offset = m_total = m_count = 0; + } + + //! @brief Data is not shared? + bool unique() const {return !m_data || m_data.unique();} + + + //! @brief Number of elements visible through this vector + size_t size() const{return m_count;} + bool empty() const{return !m_count;} + + + /** @brief Reduce the view of this shared_vector. + * + * Reduce the portion of the underlying buffer which + * is accessible through this shared_vector. + * + * When the requested new offset and length are not possible + * then the following holds. + * + * When offset is >= size() then after slice() size()==0. + * When length >= size()-offset then after slice() + * size() = old_size-offset. + * + @param offset The request new offset relative to the + * current offset. + @param length The requested new length. + * + @note offset and length are in units of sizeof(E). + * or bytes (1) when E=void. + */ + void slice(size_t offset, size_t length=(size_t)-1) + { + if(offset>m_count) + offset = m_count; // will slice down to zero length + + const size_t max_count = m_count - offset; + + m_offset += offset; + + m_total -= offset; + + m_count = std::min(length, max_count); + } + + // Access to members. + const std::tr1::shared_ptr& dataPtr() const { return m_data; } + size_t dataOffset() const { return m_offset; } + size_t dataCount() const { return m_count; } + size_t dataTotal() const { return m_total; } + }; +} + +/** @brief A holder for a contigious piece of memory. + * + * Data is shared, but offset and length are not. + * This allows one vector to have access to only a + * subset of a piece of memory. + * + * The ways in which shared_vector is intended to differ from + * std::vector are outlined in @ref vectordiff . + * + * Also see @ref vectormem and @ref vectorconst + * + * @warning Due to the implementation of std::tr1::shared_ptr, use of + * shared_vector should not be combined with use of weak_ptr. + * shared_ptr::unique() and shared_ptr::use_count() do @b not + * include weak_ptr instances. This breaks the assumption made + * by make_unique() that unique()==true implies exclusive + * ownership. + */ +template +class shared_vector : public detail::shared_vector_base +{ + typedef detail::shared_vector_base base_t; + typedef typename detail::call_with::type param_type; + typedef typename meta::strip_const::type _E_non_const; +public: + typedef E value_type; + typedef E& reference; + typedef typename meta::decorate_const::type& const_reference; + typedef E* pointer; + typedef typename meta::decorate_const::type* const_pointer; + typedef E* iterator; + typedef std::reverse_iterator reverse_iterator; + typedef typename meta::decorate_const::type* const_iterator; + typedef std::reverse_iterator const_reverse_iterator; + typedef ptrdiff_t difference_type; + typedef size_t size_type; + + typedef E element_type; + typedef std::tr1::shared_ptr shared_pointer_type; + + // allow specialization for all E to be friends + template friend class shared_vector; + + + //! @brief Empty vector (not very interesting) + shared_vector() :base_t() {} + + //! @brief Allocate (with new[]) a new vector of size c + explicit shared_vector(size_t c) + :base_t(new _E_non_const[c], 0, c) + {} + + //! @brief Allocate (with new[]) a new vector of size c and fill with value e + shared_vector(size_t c, param_type e) + :base_t(new _E_non_const[c], 0, c) + { + std::fill_n((_E_non_const*)this->m_data.get(), this->m_count, e); + } + + /** @brief Build vector from a raw pointer + * + @param v A raw pointer allocated with new[]. + @param o The offset in v or the first element visible to the vector + @param c The number of elements pointed to by v+o + */ + template + shared_vector(A v, size_t o, size_t c) :base_t(v,o,c) {} + + /** @brief Build vector from an existing smart pointer + * + @param d An existing smart pointer + @param o The offset in v or the first element visible to the vector + @param c The number of elements pointed to by v+o + */ + template + shared_vector(const std::tr1::shared_ptr& d, size_t o, size_t c) + :base_t(d,o,c) {} + + /** @brief Build vector from raw pointer and cleanup function + * + @param d An existing raw pointer + @param b An function/functor used to free d. Invoked as b(d). + @param o The offset in v or the first element visible to the vector + @param c The number of elements pointed to by v+o + */ + template + shared_vector(A d, B b, size_t o, size_t c) + :base_t(d,b,o,c) {} + + //! @brief Copy an existing vector of same type + shared_vector(const shared_vector& o) :base_t(o) {} + + //! @internal + //! Internal for static_shared_vector_cast + template + shared_vector(const shared_vector &src, + typename meta::is_void::type) + :base_t(std::tr1::static_pointer_cast(src.dataPtr()), + src.dataOffset()/sizeof(E), + src.dataCount()/sizeof(E)) + {} + + + shared_vector(shared_vector& O, + detail::_shared_vector_freeze_tag t) + :base_t(O,t) + {} + + shared_vector(shared_vector& O, + detail::_shared_vector_thaw_tag t) + :base_t(O,t) + {} + + size_t max_size() const{return ((size_t)-1)/sizeof(E);} + + size_t capacity() const { return this->m_total; } + + /** @brief Set array capacity + * + * A side effect is that array data will be uniquely owned by this instance + * as if make_unique() was called. This holds even if the capacity + * does not increase. + * + * For notes on copying see docs for make_unique(). + */ + void reserve(size_t i) { + if(this->unique() && i<=this->m_total) + return; + _E_non_const* temp=new _E_non_const[i]; + try{ + std::copy(begin(), end(), temp); + this->m_data.reset(temp, detail::default_array_deleter()); + }catch(...){ + delete[] temp; + throw; + } + this->m_offset = 0; + this->m_total = i; + // m_count is unchanged + } + + /** @brief Grow or shrink array + * + * A side effect is that array data will be uniquely owned by this instance + * as if make_unique() were called. This holds even if the size does not change. + * + * For notes on copying see docs for make_unique(). + */ + void resize(size_t i) { + if(i==this->m_count) { + make_unique(); + return; + } + if(this->m_data && this->m_data.unique()) { + // we have data and exclusive ownership of it + if(i<=this->m_total) { + // We have room to grow (or shrink)! + this->m_count = i; + return; + } + } + // must re-allocate :( + size_t new_total = std::max(this->m_total, i); + _E_non_const* temp=new _E_non_const[new_total]; + try{ + // Copy as much as possible from old, + // remaining elements are uninitialized. + std::copy(begin(), + begin()+std::min(i,this->size()), + temp); + this->m_data.reset(temp, detail::default_array_deleter()); + }catch(...){ + delete[] temp; + throw; + } + this->m_offset= 0; + this->m_count = i; + this->m_total = new_total; + } + + /** @brief Grow (and fill) or shrink array. + * + * see @ref resize(size_t) + */ + void resize(size_t i, param_type v) { + size_t oldsize=this->size(); + resize(i); + if(this->size()>oldsize) { + std::fill(begin()+oldsize, end(), v); + } + } + + /** @brief Ensure (by copying) that this shared_vector is the sole + * 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. + @code + shared_vector original(...); + + if(!original.unique()){ + shared_vector temp(myallocator(original.size()), + 0, original.size()); + std::copy(original.begin(), original.end(), temp.begin()); + original.swap(temp); + } + assert(original.unique()); + @endcode + */ + void make_unique() { + if(this->unique()) + return; + _E_non_const *d = new _E_non_const[this->m_total]; + try { + std::copy(this->m_data.get()+this->m_offset, + this->m_data.get()+this->m_offset+this->m_count, + d); + }catch(...){ + delete[] d; + throw; + } + this->m_data.reset(d, detail::default_array_deleter()); + this->m_offset=0; + } + + + // STL iterators + + iterator begin() const{return this->m_data.get()+this->m_offset;} + const_iterator cbegin() const{return begin();} + + iterator end() const{return this->m_data.get()+this->m_offset+this->m_count;} + const_iterator cend() const{return end();} + + reverse_iterator rbegin() const{return reverse_iterator(end());} + const_reverse_iterator crbegin() const{return rbegin();} + + reverse_iterator rend() const{return reverse_iterator(begin());} + const_reverse_iterator crend() const{return rend();} + + reference front() const{return (*this)[0];} + reference back() const{return (*this)[this->m_count-1];} + + // Modifications + +private: + void _push_resize() { + if(this->m_count==this->m_total || !this->unique()) { + size_t next; + if(this->m_total<1024) { + // round m_total+1 up to the next power of 2 + next = this->m_total; + next |= next >> 1; + next |= next >> 2; + next |= next >> 4; + next |= next >> 8; + next++; + } else { + // pad m_total up to the next multiple of 1024 + next = this->m_total+1024; + next &= ~0x3ff; + } + assert(next > this->m_total); + reserve(next); + } + resize(this->size()+1); + } + +public: + + void push_back(param_type v) + { + _push_resize(); + back() = v; + } + + void pop_back() + { + this->slice(0, this->size()-1); + } + + // data access + + pointer data() const{return this->m_data.get()+this->m_offset;} + + reference operator[](size_t i) const {return this->m_data.get()[this->m_offset+i];} + + reference at(size_t i) const + { + if(i>this->m_count) + throw std::out_of_range("Index out of bounds"); + return (*this)[i]; + } + +}; + +//! Specialization for storing untyped pointers +//! Does not allow access or iteration of contents +//! other than as void* or const void* +template +class shared_vector::type > + : public detail::shared_vector_base +{ + typedef detail::shared_vector_base base_t; + ScalarType m_vtype; +public: + typedef E* pointer; + typedef ptrdiff_t difference_type; + typedef size_t size_type; + + typedef std::tr1::shared_ptr shared_pointer_type; + + shared_vector() :base_t(), m_vtype((ScalarType)-1) {} + + shared_vector(pointer v, size_t o, size_t c) + :base_t(v,o,c), m_vtype((ScalarType)-1) {} + + template + shared_vector(pointer d, B b, size_t o, size_t c) + :base_t(d,b,o,c), m_vtype((ScalarType)-1) {} + + template + shared_vector(const std::tr1::shared_ptr& d, size_t o, size_t c) + :base_t(d,o,c), m_vtype((ScalarType)-1) {} + + shared_vector(const shared_vector& o) + :base_t(o), m_vtype(o.m_vtype) {} + + //! @internal + //! Internal for static_shared_vector_cast + template + shared_vector(const shared_vector &src, + typename meta::is_not_void::type) + :base_t(std::tr1::static_pointer_cast(src.dataPtr()), + src.dataOffset()*sizeof(FROM), + src.dataCount()*sizeof(FROM)) + ,m_vtype((ScalarType)ScalarTypeID::value) + {} + + shared_vector(shared_vector& O, + detail::_shared_vector_freeze_tag t) + :base_t(O,t) + {} + + shared_vector(shared_vector& O, + detail::_shared_vector_thaw_tag t) + :base_t(O,t) + {} + + shared_vector& operator=(const shared_vector& o) + { + if(&o!=this) { + this->base_t::operator=(o); + m_vtype = o.m_vtype; + } + return *this; + } + + template + shared_vector& operator=(const shared_vector& o) + { + if(&o!=this) { + this->base_t::operator=(o); + m_vtype = o.m_vtype; + } + return *this; + } + + size_t max_size() const{return (size_t)-1;} + + pointer data() const{ + return (pointer)(((char*)this->m_data.get())+this->m_offset); + } + + shared_vector& set_original_type(ScalarType t) { m_vtype=t; return *this; } + ScalarType original_type() const {return m_vtype;} +}; + +namespace detail { + + // Default to type conversion using castUnsafe (C++ type casting) on each element + template + struct shared_vector_converter { + static inline shared_vector op(const shared_vector& src) + { + shared_vector ret(src.size()); + std::transform(src.begin(), src.end(), ret.begin(), castUnsafe); + return ret; + } + }; + + // copy reference when types are the same (excluding const qualifiers) + template + struct shared_vector_converter::type > { + static FORCE_INLINE shared_vector op(const shared_vector& src) { + return src; + } + }; + + // "convert" to 'void' or 'const void from non-void + // is an alias for shared_vector_cast() + template + struct shared_vector_converter, meta::is_not_void >::type + > + { + static FORCE_INLINE shared_vector op(const shared_vector& src) { + return shared_vector(src, detail::_shared_vector_cast_tag()); + } + }; + + // convert from void uses original type or throws an exception. + template + struct shared_vector_converter, meta::is_void >::type + > + { + static shared_vector op(const shared_vector& src) { + typedef typename meta::strip_const::type to_t; + ScalarType stype = src.original_type(), + dtype = (ScalarType)ScalarTypeID::value; + if(stype==dtype) { + // no convert needed + return shared_vector(src, detail::_shared_vector_cast_tag()); + } else { + // alloc and convert + shared_vector ret(src.size()/ScalarTypeFunc::elementSize(stype)); + castUnsafeV(ret.size(), + dtype, + static_cast(ret.data()), + stype, + static_cast(src.data())); + return const_shared_vector_cast(ret); + } + } + }; +} + +/** @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 +static FORCE_INLINE +shared_vector +static_shared_vector_cast(const shared_vector& src, + typename meta::same_const::type = 0) +{ + return shared_vector(src, detail::_shared_vector_cast_tag()); +} + +/** @brief Allow converting of shared_vector between types + * + * Conversion utilizes castUnsafe(). + * + * Converting to/from void is supported. Convert to void + * is an alias for static_shared_vector_cast(). + * Convert from void utilizes shared_vector::original_type() + * and throws std::runtime_error if this is not valid. + */ +template +static FORCE_INLINE +shared_vector +shared_vector_convert(const shared_vector& src) +{ + return detail::shared_vector_converter::op(src); +} + +/** @brief transform a shared_vector to shared_vector + * + * Transform a reference to mutable data into a reference to read-only data. + * Throws an exception unless the reference to mutable data is unique. + * On success the reference to mutable data is cleared. + */ +template +static FORCE_INLINE +shared_vector::type> +freeze(SRC& src) +{ + typedef typename meta::decorate_const::type const_value; + return shared_vector(src, detail::_shared_vector_freeze_tag()); +} + +/** @brief transform a shared_vector to shared_vector + * + * Transform a reference to read-only data into a unique reference to mutable data. + * + * The reference to read-only data is cleared. + */ +template +static FORCE_INLINE +shared_vector::type> +thaw(SRC& src) +{ + typedef typename meta::strip_const::type value; + return shared_vector(src, detail::_shared_vector_thaw_tag()); +} + +namespace detail { + template + struct const_caster {}; + + template + struct const_caster { + static FORCE_INLINE shared_vector op(shared_vector& src) + { + return thaw(src); + } + }; + + template + struct const_caster { + static FORCE_INLINE shared_vector op(shared_vector& src) + { + return freeze(src); + } + }; + + template + struct const_caster { + static FORCE_INLINE shared_vector op(shared_vector& src) + { + shared_vector ret(src); + src.clear(); + return ret; + } + }; +} + +//! Allows casting from const TYPE -> TYPE. +template +static FORCE_INLINE +shared_vector +const_shared_vector_cast(shared_vector& src) +{ + return detail::const_caster::op(src); +} + + +namespace ScalarTypeFunc { + //! Allocate an untyped array based on ScalarType + shared_vector allocArray(ScalarType id, size_t len); + + //! Allocate an untyped array based on ScalarType + template + inline + shared_vector::type> + allocArray(size_t len) + { + shared_vector raw(allocArray(ID, len)); + return static_shared_vector_cast::type>(raw); + } +} + +}} // namespace epics::pvData + +// Global operators for shared_vector + +template +bool operator==(const epics::pvData::shared_vector& a, + const epics::pvData::shared_vector& b) +{ + if(a.size() != b.size()) + return false; + if(a.dataOffset()==b.dataOffset() && a.dataPtr().get()==b.dataPtr().get()) + return true; + return std::equal(a.begin(), a.end(), b.begin()); +} + +template +bool operator!=(const epics::pvData::shared_vector& a, + const epics::pvData::shared_vector& b) +{ + return !(a==b); +} + +template +std::ostream& operator<<(std::ostream& strm, const epics::pvData::shared_vector& arr) +{ + strm<<'{'<10) { + strm<<"..."; + break; + } + strm<' is 'const shared_vector'. However, + * it is also possible to have 'const shared_vector' analogous to + * 'E* const' and 'shared_vector' which is analogous to + * 'const E*'. + * + * Copying a shared_vector, by construction or assignment, does + * not copy its contents. Modifications to one such "copy" effect + * all associated shared_vector instances. + * + * std::vector::reserve(N) has no effect if N<=std::vector::capacity(). + * However, like resize(), shared_vector::reserve() has the side + * effect of always calling make_unique(). + * + * @section notimpl Parts of std::vector interface not implemented + * + * Mutating methods insert(), erase(), shrink_to_fit(), + * emplace(), and emplace_back() are not implemented. + * + * shared_vector does not model an allocator which is bound to the object. + * Therefore the get_allocator() method and the allocator_type typedef are + * not provided. + * + * The assign() method and the related constructor are not implemented + * at this time. + * + * The comparison operators '>', '>=', '<=', and '<' are not implemented + * at this time. + * + * @section newstuff Parts not found in std::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' to 'shared_vector'. + * + * To faciliate safe modification the methods unique() and + * make_unique() are provided. + * + * The slice() method selects a sub-set of the shared_vector. + * + * The low level accessors dataPtr(), dataOffset(), dataCount(), + * and dataTotal(). + * + */ + +/** @page vectormem Memory Management with shared_vector + * + * The @link epics::pvData::shared_vector shared_vector class @endlink + * is a std::vector like class which implements sharing data by reference counting. + * + * Internally memory is tracked with the shared_ptr reference counting smart pointer. + * This allows a custom destructor to be specified. This allows a vector to borrow + * memory allocated by 3rd party libraries which require special cleanup. + * + * In place element modification is allowed. It is left to user code to ensure + * that such modification is safe, either from application specific knowledge, or by + * calling + * @link paramTable::string_data::make_unique make_unique @endlink + * explicitly, or implicitly by calling + * @link paramTable::shared_vector::resize resize @endlink + * prior to making modifications. + * + @code + extern "C" { + // array embedded in C structure + struct composite { + int other, stuff; + char buf[42]; + } + + // Unknown relation between array and handle + typedef void* handle_type; + handle_type mylib_alloc(void); + char *mylib_mem(handle_type); + void mylib_free(handle_type); + } + + // Note that mylibcleaner must be copy constructable + struct mylibcleaner { + handle_type handle; + mylibcleaner(handle_type h) :handle(h) {} + void operator()(char*){ mylib_free(handle);} + }; + + struct compcleaner { + void operator()(char* c){ free(c-offsetof(composite,buf)); } + }; + + void main() { + + unsigned char* buf=calloc(42,1); + + shared_vector a(buf, &free); + + a.clear(); // calls free(ptr) + + + composite *c=malloc(sizeof(*c)); + assert(c!=NULL); + + shared_vector d(c->buf, compcleaner()); + + d.clear(); // calls free(ptr-offsetof(composite,buf)) + + + void *handle=mylib_alloc(); + char *hmem=mylib_mem(handle); + assert(hmem!=NULL); + + shared_vector b(hmem, mylibcleaner(handle)); + + b.clear(); // calls mylib_free(handleptr) + } + @endcode + */ + +/** @page vectorconst Value const-ness and shared_vector + +The type 'shared_vector' can be thought of as 'T*'. +Like the T pointer there are three related constant types: + +@code + shared_vector v_mutable; // 1 + const shared_vector v_const_ref; // 2 + shared_vector v_const_data; // 3 + const shared_vector v_const_ref_data; // 4 +@endcode + +The distinction between these types is what "part" of the type is constant, +the "reference" (pointer) or the "value" (location being pointed to). + +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. + +For casting between shared_vector and shared_vector +explicit casting operations are required. These operations are +@b freeze() (non-const to const) and @b thaw() (const to non-const). + +A shared_vector is "frozen" as its value can not be modified. + +These functions are defined like: + +@code +namespace epics{namespace pvData{ + template + shared_vector freeze(shared_vector&); + + template + shared_vector thaw(shared_vector&); +}} +@endcode + +So each consumes a shared_vector with a certain value +const-ness, and returns one with the other. + +The following guarantees are provided by both functions: + +# The returned reference points to a value which is equal to the value referenced + by the argument. +# 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 +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. + +This possibility can be avoided by calling the make_unique() on a +shared_vector before passing it to freeze(). + +@section vthaw Thawing + +The act of thawing a shared_vector may make a copy of the value +referenced by its argument if this reference is not unique(). + +*/ diff --git a/pvDataApp/misc/templateMeta.h b/pvDataApp/misc/templateMeta.h new file mode 100644 index 0000000..cd82f48 --- /dev/null +++ b/pvDataApp/misc/templateMeta.h @@ -0,0 +1,120 @@ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** C++ Template meta programming helpers + */ +#ifndef TEMPLATEMETA_H +#define TEMPLATEMETA_H + +// gently nudge the compiler to inline our wrappers +// Warning: Only use this when the template body is *small*. +// You have been warned! +#if defined(__GNUC__) && __GNUC__>=3 +# define FORCE_INLINE __attribute__((always_inline)) inline +#elif defined(_MSC_VER) +# define FORCE_INLINE __forceinline +#else +# define FORCE_INLINE inline +#endif + +namespace epics { namespace pvData { +namespace meta { + +/** If needed, add the 'const' qualifier to the provided type. + * + * Avoids adding the const qualifier twice (aka 'const const int') + @code + assert(typeid(decorate_const::type)==typeid(const int)); + assert(typeid(decorate_const::type)==typeid(const int)); + @endcode + */ +template struct decorate_const { typedef const T type; }; +template struct decorate_const { typedef const T type; }; + +/** Remove the 'const' qualifier if present + @code + assert(typeid(strip_const::type)==typeid(int)); + assert(typeid(strip_const::type)==typeid(int)); + @endcode + */ +template struct strip_const { typedef T type; }; +template struct strip_const { typedef T type; }; + +/** test to allow specialization only when A!=B + * + @code + template + struct myTemp {...}; + + // specialization when A==B + template + struct myTemp {...}; + + // specialization for A is 'int', + // enabler needed to remove ambiguity when B is 'int'. + template + struct myTemp::type> + {...}; + @endcode + */ +template +struct not_same_type {typedef R type;}; +template +struct not_same_type {}; + +//! Select if both A and B have the same root type (excluding const qualifier) +template struct same_root {}; +template struct same_root { typedef R type; }; +template struct same_root { typedef R type; }; +template struct same_root { typedef R type; }; + +namespace detail { + struct _const_yes {}; + struct _const_no {}; + template struct _has_const { typedef _const_no type; }; + template struct _has_const { typedef _const_yes type; }; + + template struct _same_type {}; + template struct _same_type { typedef R type; }; +} // namespace detail + +//! Check if both A and B are either const or non-const. +template +struct same_const : + public detail::_same_type::type, + typename detail::_has_const::type, + R> +{}; + +/** test if provided type is 'void' or 'const void' + * + * Avoid having to explicitly specialize for both + @code + template + struct myTemp {...}; + + // specialization when A is 'void' or 'const void' + template + struct myTemp::type> {...}; + @endcode + */ +template struct is_void {}; +template struct is_void { typedef R type; }; +template struct is_void { typedef R type; }; + +//! Inverse of is_void +template struct is_not_void { typedef R type; }; +template<> struct is_not_void {}; +template<> struct is_not_void {}; + +//! Enabler to ensure that both conditions A and B are true +template +struct _and {}; +template +struct _and { typedef R type; }; + +}}} + +#endif // TEMPLATEMETA_H diff --git a/pvDataApp/misc/typeCast.cpp b/pvDataApp/misc/typeCast.cpp new file mode 100644 index 0000000..6b5ba2a --- /dev/null +++ b/pvDataApp/misc/typeCast.cpp @@ -0,0 +1,230 @@ +/** + * 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: Michael Davidsaver */ +#include + +#include "typeCast.h" + +using epics::pvData::castUnsafe; +using epics::pvData::String; +using epics::pvData::ScalarType; +using epics::pvData::pvString; + +namespace { + +static void noconvert(size_t, void*, const void*) +{ + throw std::runtime_error("castUnsafeV: Conversion not supported"); +} + +template +static void castVTyped(size_t count, void *draw, const void *sraw) +{ + TO *dest=(TO*)draw; + const FROM *src=(FROM*)sraw; + std::transform(src, src+count, dest, castUnsafe); +} + +template +static void copyV(size_t count, void *draw, const void *sraw) +{ + T *dest=(T*)draw; + const T *src=(T*)sraw; + std::copy(src, src+count, dest); +} + +typedef void (*convertfn)(size_t, void*, const void*); + +/* lookup table of converter functions. + * first dimension is TO, second is FROM + */ +static convertfn converters[pvString+1][pvString+1] = +{ + // to pvBoolean + { &noconvert, + &noconvert, + &noconvert, + &noconvert, + &noconvert, + &noconvert, + &noconvert, + &noconvert, + &noconvert, + &noconvert, + &noconvert, + &noconvert + }, + // to pvByte + {&noconvert, + ©V, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + }, + // to pvShort + {&noconvert, + &castVTyped, + ©V, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + }, + // to pvInt + {&noconvert, + &castVTyped, + &castVTyped, + ©V, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + }, + // to pvLong + {&noconvert, + &castVTyped, + &castVTyped, + &castVTyped, + ©V, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + }, + // to pvUByte + {&noconvert, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + ©V, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + }, + // to pvUShort + {&noconvert, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + ©V, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + }, + // to pvUInt + {&noconvert, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + ©V, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + }, + // to pvULong + {&noconvert, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + ©V, + &castVTyped, + &castVTyped, + &castVTyped, + }, + // to pvFloat + {&noconvert, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + ©V, + &castVTyped, + &castVTyped, + }, + // to pvDouble + {&noconvert, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + ©V, + &castVTyped, + }, + // to pvString + {&noconvert, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + &castVTyped, + ©V, + }, +}; + +} // end namespace + +namespace epics { namespace pvData { + +void castUnsafeV(size_t count, ScalarType to, void *dest, ScalarType from, const void *src) +{ + unsigned int ito=to, ifrom=from; + + if(ito>pvString || ifrom>pvString) + throw std::runtime_error("castUnsafeV: Invalid types"); + + converters[ito][ifrom](count, dest, src); +} + +}} diff --git a/pvDataApp/misc/typeCast.h b/pvDataApp/misc/typeCast.h new file mode 100644 index 0000000..0717d0c --- /dev/null +++ b/pvDataApp/misc/typeCast.h @@ -0,0 +1,172 @@ +/** + * 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: Michael Davidsaver */ +#ifndef PVTYPECAST_H +#define PVTYPECAST_H + +#include +#include + +#include + +#include +#include +#include + +namespace epics { namespace pvData { + +typedef std::string String; + +namespace detail { + // parseToPOD wraps the epicsParse*() functions in one name + // and throws exceptions + void parseToPOD(const std::string&, char *out); + void parseToPOD(const std::string&, int8_t *out); + void parseToPOD(const std::string&, uint8_t *out); + void parseToPOD(const std::string&, int16_t *out); + void parseToPOD(const std::string&, uint16_t *out); + void parseToPOD(const std::string&, int32_t *out); + void parseToPOD(const std::string&, uint32_t *out); + void parseToPOD(const std::string&, int64_t *out); + void parseToPOD(const std::string&, uint64_t *out); + void parseToPOD(const std::string&, float *out); + void parseToPOD(const std::string&, double *out); + + /* want to pass POD types by value, + * and String by const reference + */ + template + struct cast_arg { typedef ARG arg; }; + template<> + struct cast_arg { typedef const String& arg; }; + + // trick std::ostream into treating char's as numbers + // by promoting char to int + template + struct print_cast { typedef T type; }; + template<> + struct print_cast { typedef int type; }; + template<> + struct print_cast { typedef signed int type; }; + template<> + struct print_cast { typedef unsigned int type; }; + + // default to C++ type casting + template + struct cast_helper { + static FORCE_INLINE TO op(FROM from) { + return static_cast(from); + } + }; + + // special handling when down-casting double to float + template<> + struct cast_helper { + static FORCE_INLINE float op(double from) { + return epicsConvertDoubleToFloat(from); + } + }; + + // print POD to string + // when String!=FROM + template + struct cast_helper::type> { + static String op(FROM from) { + typedef typename print_cast::type ptype; + std::ostringstream strm; + strm << (ptype)from; + if(strm.fail()) + throw std::runtime_error("Cast to string failed"); + return strm.str(); + } + }; + + // parse POD from string + // TO!=String + template + struct cast_helper::type> { + static FORCE_INLINE TO op(const String& from) { + TO ret; + parseToPOD(from, &ret); + return ret; + } + }; + +} // end detail + +/** @brief Casting/converting between supported scalar types. + * + * Supported types: uint8_t, int8_t, uint16_t, int16_t, + * uint32_t, int32_t, uint64_t, int64_t, + * float, double, String + * + * As defined in pvType.h + * + @throws std::runtime_error when the cast is not possible. + @throws std::bad_alloc when the cast is not possible. + * + @section convertg Conversion Guarantees + * + * Conversions which always produce a correct result. + * + * - signed integer -> larger signed integer + * - unsigned integer -> larger unsigned integer + * - integer -> float or double (where sizeof(integer) double + * + * Conversions where out of range inputs always produce + * a defined result, but may not be reversable. + * + * - double -> float. When abs(value) is outside the range + * [FLT_MIN, FLT_MAX] the value is clipped to FLT_MIN or FLT_MAX + * with the sign preserved. + * + * 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) + * + * Conversions where out of range inputs produce undefined + * results. + * + * - signed integer -> smaller signed integer + * - unsigned integer -> smaller unsigned integer + * - signed integer <-> unsigned integer + * - integer -> float or double (where sizeof(integer)>=sizeof(floating)) + * - float or double -> integer. The floating point value + * is rounded towards zero. However, the result for values + * too large to be represented by the integer type + * is not defined. + * + @section stringf String formats + * + * - Numbers beginning with 1-9 are parsed as base-10. + * - Numbers beginning with '0x' are parsed as base-16 + * - Numbers beginning with '0' are parsed as base-8. + * - Hex numbers are case insensitive. + * - Exponential numbers may use either 'e' or 'E'. + */ +template +static FORCE_INLINE TO castUnsafe(const FROM& from) +{ + return detail::cast_helper::op(from); +} + +void castUnsafeV(size_t count, ScalarType to, void *dest, ScalarType from, const void *src); + +//! Cast value to printable type +//! A no-op except for char types, which are cast to int +//! so that they are printed as numbers std::ostream operators. +template +static FORCE_INLINE +typename detail::print_cast::type +print_cast(const T& v) { return v; } + +}} // end namespace + +#endif // PVTYPECAST_H diff --git a/pvDataApp/property/pvEnumerated.cpp b/pvDataApp/property/pvEnumerated.cpp index ee00601..77f24d9 100644 --- a/pvDataApp/property/pvEnumerated.cpp +++ b/pvDataApp/property/pvEnumerated.cpp @@ -78,9 +78,8 @@ String PVEnumerated::getChoice() throw std::logic_error(notAttached); } int index = pvIndex->get(); - StringArrayData data; - pvChoices->get(0,pvChoices->getLength(),data); - return data.data[index]; + const PVStringArray::const_svector& data(pvChoices->view()); + return data[index]; } bool PVEnumerated::choicesMutable() @@ -91,15 +90,6 @@ bool PVEnumerated::choicesMutable() return pvChoices->isImmutable(); } -StringArrayPtr const & PVEnumerated:: getChoices() -{ - if(pvIndex.get()==NULL ) { - throw std::logic_error(notAttached); - } - StringArrayData data; - return pvChoices->getSharedVector(); -} - int32 PVEnumerated::getNumberChoices() { if(pvIndex.get()==NULL ) { @@ -108,13 +98,15 @@ int32 PVEnumerated::getNumberChoices() return pvChoices->getLength(); } -bool PVEnumerated:: setChoices(StringArray & choices) +bool PVEnumerated:: setChoices(const StringArray & choices) { if(pvIndex.get()==NULL ) { throw std::logic_error(notAttached); } if(pvChoices->isImmutable()) return false; - pvChoices->put(0,choices.size(),get(choices),0); + PVStringArray::svector data(choices.size()); + std::copy(choices.begin(), choices.end(), data.begin()); + pvChoices->replace(freeze(data)); return true; } diff --git a/pvDataApp/property/pvEnumerated.h b/pvDataApp/property/pvEnumerated.h index 4e2fbe0..7887908 100644 --- a/pvDataApp/property/pvEnumerated.h +++ b/pvDataApp/property/pvEnumerated.h @@ -30,9 +30,9 @@ public: int32 getIndex(); String getChoice(); bool choicesMutable(); - StringArrayPtr const & getChoices(); + inline PVStringArray::const_svector getChoices(){return pvChoices->view();} int32 getNumberChoices(); - bool setChoices(StringArray & choices); + bool setChoices(const StringArray & choices); private: static String notFound; static String notAttached; diff --git a/pvDataApp/pv/convert.h b/pvDataApp/pv/convert.h index 266aab2..6faead0 100644 --- a/pvDataApp/pv/convert.h +++ b/pvDataApp/pv/convert.h @@ -19,9 +19,9 @@ namespace epics { namespace pvData { -bool operator==(PVField&, PVField&); +bool operator==(const PVField&, const PVField&); -static inline bool operator!=(PVField& a, PVField& b) +static inline bool operator!=(const PVField& a, const PVField& b) {return !(a==b);} @@ -71,13 +71,16 @@ typedef std::tr1::shared_ptr ConvertPtr; class Convert { public: static ConvertPtr getConvert(); - ~Convert(); /** * Get the full fieldName for the pvField. * @param builder The builder that will have the result. * @param pvField The pvField. */ - void getFullName(StringBuilder buf,PVFieldPtr const & pvField); + void getFullName(StringBuilder buf,PVFieldPtr const & pvField) + { + *buf = pvField->getFullName(); + } + /** * Do fields have the same definition. * @@ -85,7 +88,11 @@ public: * @param Second field * @return (false, true) if the fields (are not, are) the same. */ - bool equals(PVFieldPtr const &a,PVFieldPtr const &b); + inline bool equals(PVFieldPtr const &a,PVFieldPtr const &b) + { + return *a==*b; + } + /** * Do fields have the same definition. * @@ -93,7 +100,11 @@ public: * @param Second field * @return (false, true) if the fields (are not, are) the same. */ - bool equals(PVField &a,PVField &b); + inline bool equals(PVField &a,PVField &b) + { + return a==b; + } + /** * Convert a PVField to a string. * @param buf buffer for the result @@ -101,14 +112,16 @@ public: * If a PVField is a structure or array be prepared for a very long string. * @param indentLevel indentation level */ - void getString(StringBuilder buf,PVFieldPtr const & pvField,int indentLevel); + inline void getString(StringBuilder buf,PVFieldPtr const & pvField,int indentLevel) + {getString(buf, pvField.get(), indentLevel);} /** * Convert a PVField to a string. * param buf buffer for the result * @param pv The PVField to convert to a string. * If the PVField is a structure or array be prepared for a very long string. */ - void getString(StringBuilder buf,PVFieldPtr const & pvField); + inline void getString(StringBuilder buf,PVFieldPtr const & pvField) + {getString(buf, pvField.get(), 0);} /** * Convert a PVField to a string. * @param buf buffer for the result @@ -123,7 +136,8 @@ public: * @param pv The PVField to convert to a string. * If the PVField is a structure or array be prepared for a very long string. */ - void getString(StringBuilder buf,PVField const * pvField); + inline void getString(StringBuilder buf,PVField const * pvField) + {getString(buf, pvField, 0);} /** * Convert from an array of String to a PVScalar * @param pv The PV. @@ -141,7 +155,11 @@ public: * @param from The String value to convert and put into a PV. * @throws std::logic_error if the String does not have a valid value. */ - void fromString(PVScalarPtr const & pv, String const & from); + void fromString(PVScalarPtr const & pv, String const & from) + { + pv->putFrom(from); + } + /** * Convert from a String to a PVScalarArray. * The String must be a comma separated set of values optionally enclosed in [] @@ -235,22 +253,6 @@ public: bool isCopyScalarArrayCompatible( ScalarArrayConstPtr const & from, ScalarArrayConstPtr const & to); - /** - * Convert from a source PV array to a destination PV array. - * @param from The source array. - * @param offset Starting element in the source. - * @param to The destination array. - * @param toOffset Starting element in the array. - * @param length Number of elements to transfer. - * @return Number of elements converted. - * @throws std::invalid_argument if the arguments are not compatible. - */ - std::size_t copyScalarArray( - PVScalarArrayPtr const & from, - std::size_t offset, - PVScalarArrayPtr const & to, - std::size_t toOffset, - std::size_t length); /** * Are from and to valid arguments for copyStructure. * They are only compatible if they have the same Structure description. @@ -294,459 +296,146 @@ public: * @param pv a PV * @return converted value */ - int8 toByte(PVScalarPtr const & pv); + inline int8 toByte(PVScalarPtr const & pv) { return pv->getAs();} /** * Convert a PV to a short. * @param pv a PV * @return converted value * @throws std::invalid_argument if the Type is not a numeric scalar */ - int16 toShort(PVScalarPtr const & pv); + inline int16 toShort(PVScalarPtr const & pv) { return pv->getAs();} /** * Convert a PV to a int. * @param pv a PV * @return converted value * @throws std::invalid_argument if the Type is not a numeric scalar */ - int32 toInt(PVScalarPtr const & pv); + inline int32 toInt(PVScalarPtr const & pv) { return pv->getAs();} /** * Convert a PV to an long * @param pv a PV * @return converted value * @throws std::invalid_argument if the Type is not a numeric scalar */ - int64 toLong(PVScalarPtr const & pv); + inline int64 toLong(PVScalarPtr const & pv) { return pv->getAs();} /** * Convert a PV to a ubyte. * @param pv a PV * @return converted value */ - uint8 toUByte(PVScalarPtr const & pv); + inline uint8 toUByte(PVScalarPtr const & pv) { return pv->getAs();} /** * Convert a PV to a ushort. * @param pv a PV * @return converted value * @throws std::invalid_argument if the Type is not a numeric scalar */ - uint16 toUShort(PVScalarPtr const & pv); + inline uint16 toUShort(PVScalarPtr const & pv) { return pv->getAs();} /** * Convert a PV to a uint. * @param pv a PV * @return converted value * @throws std::invalid_argument if the Type is not a numeric scalar */ - uint32 toUInt(PVScalarPtr const & pv); + inline uint32 toUInt(PVScalarPtr const & pv) { return pv->getAs();} /** * Convert a PV to an ulong * @param pv a PV * @return converted value * @throws std::invalid_argument if the Type is not a numeric scalar */ - uint64 toULong(PVScalarPtr const & pv); + inline uint64 toULong(PVScalarPtr const & pv) { return pv->getAs();} /** * Convert a PV to a float * @param pv a PV * @return converted value * @throws std::invalid_argument if the Type is not a numeric scalar */ - float toFloat(PVScalarPtr const & pv); + inline float toFloat(PVScalarPtr const & pv) { return pv->getAs();} /** * Convert a PV to a double * @param pv a PV * @return converted value * @throws std::invalid_argument if the Type is not a numeric scalar */ - double toDouble(PVScalarPtr const & pv); + inline double toDouble(PVScalarPtr const & pv) { return pv->getAs();} /** * Convert a PV to a String * @param pv a PV * @return converted value */ - String toString(PVScalarPtr const & pv); + inline String toString(PVScalarPtr const & pv) { return pv->getAs();} /** * Convert a PV from a byte * @param pv a PV * @param from value to put into PV * @throws std::invalid_argument if the Type is not a numeric scalar */ - void fromByte(PVScalarPtr const & pv,int8 from); + inline void fromByte(PVScalarPtr const & pv,int8 from) { pv->putFrom(from); } /** * Convert a PV from a short * @param pv a PV * @param from value to put into PV * @throws std::invalid_argument if the Type is not a numeric scalar */ - void fromShort(PVScalarPtr const & pv,int16 from); + inline void fromShort(PVScalarPtr const & pv,int16 from) { pv->putFrom(from); } /** * Convert a PV from an int * @param pv a PV * @param from value to put into PV * @throws std::invalid_argument if the Type is not a numeric scalar */ - void fromInt(PVScalarPtr const & pv, int32 from); + inline void fromInt(PVScalarPtr const & pv, int32 from) { pv->putFrom(from); } /** * Convert a PV from a long * @param pv a PV * @param from value to put into PV * @throws std::invalid_argument if the Type is not a numeric scalar */ - void fromLong(PVScalarPtr const & pv, int64 from); + inline void fromLong(PVScalarPtr const & pv, int64 from) { pv->putFrom(from); } /** * Convert a PV from a ubyte * @param pv a PV * @param from value to put into PV * @throws std::invalid_argument if the Type is not a numeric scalar */ - void fromUByte(PVScalarPtr const & pv,uint8 from); + inline void fromUByte(PVScalarPtr const & pv,uint8 from) { pv->putFrom(from); } /** * Convert a PV from a ushort * @param pv a PV * @param from value to put into PV * @throws std::invalid_argument if the Type is not a numeric scalar */ - void fromUShort(PVScalarPtr const & pv,uint16 from); + inline void fromUShort(PVScalarPtr const & pv,uint16 from) { pv->putFrom(from); } /** * Convert a PV from an uint * @param pv a PV * @param from value to put into PV * @throws std::invalid_argument if the Type is not a numeric scalar */ - void fromUInt(PVScalarPtr const & pv, uint32 from); + inline void fromUInt(PVScalarPtr const & pv, uint32 from) { pv->putFrom(from); } /** * Convert a PV from a ulong * @param pv a PV * @param from value to put into PV * @throws std::invalid_argument if the Type is not a numeric scalar */ - void fromULong(PVScalarPtr const & pv, uint64 from); + inline void fromULong(PVScalarPtr const & pv, uint64 from) { pv->putFrom(from); } /** * Convert a PV from a float * @param pv a PV * @param from value to put into PV * @throws std::invalid_argument if the Type is not a numeric scalar */ - void fromFloat(PVScalarPtr const & pv, float from); + inline void fromFloat(PVScalarPtr const & pv, float from) { pv->putFrom(from); } /** * Convert a PV from a double * @param pv a PV * @param from value to put into PV * @throws std::invalid_argument if the Type is not a numeric scalar */ - void fromDouble(PVScalarPtr const & pv, double from); - /** - * Convert a PV array to a byte array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param to where to put the PV data - * @param toOffset starting element in the array - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - std::size_t toByteArray(PVScalarArrayPtr const & pv, - std::size_t offset, - std::size_t length, - int8* to, - std::size_t toOffset); - /** - * Convert a PV array to a short array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param to where to put the PV data - * @param toOffset starting element in the array - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - std::size_t toShortArray(PVScalarArrayPtr const & pv, - std::size_t offset, - std::size_t length, - int16* to, - std::size_t toOffset); - /** - * Convert a PV array to an int array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param to where to put the PV data - * @param toOffset starting element in the array - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - std::size_t toIntArray(PVScalarArrayPtr const & pv, - std::size_t offset, - std::size_t length, - int32* to, - std::size_t toOffset); - /** - * Convert a PV array to a long array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param to where to put the PV data - * @param toOffset starting element in the array - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - std::size_t toLongArray(PVScalarArrayPtr const & pv, - std::size_t offset, - std::size_t length, - int64* to, - std::size_t toOffset); - /** - * Convert a PV array to a ubyte array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param to where to put the PV data - * @param toOffset starting element in the array - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - std::size_t toUByteArray(PVScalarArrayPtr const & pv, - std::size_t offset, - std::size_t length, - uint8* to, - std::size_t toOffset); - /** - * Convert a PV array to a ushort array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param to where to put the PV data - * @param toOffset starting element in the array - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - std::size_t toUShortArray(PVScalarArrayPtr const & pv, - std::size_t offset, - std::size_t length, - uint16* to, - std::size_t toOffset); - /** - * Convert a PV array to an uint array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param to where to put the PV data - * @param toOffset starting element in the array - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - std::size_t toUIntArray( - PVScalarArrayPtr const & pv, - std::size_t offset, - std::size_t length, - uint32* to, - std::size_t toOffset); - /** - * Convert a PV array to a ulong array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param to where to put the PV data - * @param toOffset starting element in the array - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - std::size_t toULongArray( - PVScalarArrayPtr const & pv, - std::size_t offset, - std::size_t length, - uint64* to, - std::size_t toOffset); - /** - * Convert a PV array to a float array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param to where to put the PV data - * @param toOffset starting element in the array - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - std::size_t toFloatArray( - PVScalarArrayPtr const & pv, - std::size_t offset, - std::size_t length, - float* to, - std::size_t toOffset); - /** - * Convert a PV array to a double array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param to where to put the PV data - * @param toOffset starting element in the array - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - std::size_t toDoubleArray( - PVScalarArrayPtr const & pv, - std::size_t offset, - std::size_t length, - double* to, std::size_t - toOffset); - /** - * Convert a PV array from a byte array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param from value to put into PV - * @param fromOffset - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - std::size_t fromByteArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const int8* from, std::size_t fromOffset); - std::size_t fromByteArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const ByteArray & from, std::size_t fromOffset); - /** - * Convert a PV array from a short array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param from value to put into PV - * @param fromOffset starting element in the source array - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - std::size_t fromShortArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const int16* from, std::size_t fromOffset); - std::size_t fromShortArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const ShortArray & from, std::size_t fromOffset); - /** - * Convert a PV array from an int array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param from value to put into PV - * @param fromOffset starting element in the source array - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - std::size_t fromIntArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const int32* from, std::size_t fromOffset); - std::size_t fromIntArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const IntArray & from, std::size_t fromOffset); - /** - * Convert a PV array from a long array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param from value to put into PV - * @param fromOffset starting element in the source array - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - std::size_t fromLongArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const int64* from, std::size_t fromOffset); - std::size_t fromLongArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const LongArray & from, std::size_t fromOffset); - /** - * Convert a PV array from a ubyte array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param from value to put into PV - * @param fromOffset - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - std::size_t fromUByteArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const uint8* from, std::size_t fromOffset); - std::size_t fromUByteArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const UByteArray & from, std::size_t fromOffset); - /** - * Convert a PV array from a ushort array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param from value to put into PV - * @param fromOffset starting element in the source array - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - std::size_t fromUShortArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const uint16* from, std::size_t fromOffset); - std::size_t fromUShortArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const UShortArray & from, std::size_t fromOffset); - /** - * Convert a PV array from an uint array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param from value to put into PV - * @param fromOffset starting element in the source array - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - std::size_t fromUIntArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const uint32* from, std::size_t fromOffset); - std::size_t fromUIntArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const UIntArray & from, std::size_t fromOffset); - /** - * Convert a PV array from a ulong array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param from value to put into PV - * @param fromOffset starting element in the source array - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - std::size_t fromULongArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const uint64* from, std::size_t fromOffset); - std::size_t fromULongArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const ULongArray & from, std::size_t fromOffset); - /** - * Convert a PV array from a float array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param from value to put into PV - * @param fromOffset starting element in the source array - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - std::size_t fromFloatArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const float* from, std::size_t fromOffset); - std::size_t fromFloatArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const FloatArray & from, std::size_t fromOffset); - /** - * Convert a PV array from a double array. - * @param pv a PV - * @param offset starting element in a PV - * @param length number of elements to transfer - * @param from value to put into PV - * @param fromOffset starting element in the source array - * @return number of elements converted - * @throws std::invalid_argument if the element type is not numeric - */ - std::size_t fromDoubleArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const double* from, std::size_t fromOffset); - std::size_t fromDoubleArray( - PVScalarArrayPtr & pv, std::size_t offset, std::size_t length, - const DoubleArray & from, std::size_t fromOffset); + inline void fromDouble(PVScalarPtr const & pv, double from) { pv->putFrom(from); } + /** * Convenience method for implementing toString. * It generates a newline and inserts blanks at the beginning of the newline. @@ -754,15 +443,9 @@ public: * @param indentLevel Indent level, Each level is four spaces. */ void newLine(StringBuilder buf, int indentLevel); -private: - Convert(); - PVDataCreatePtr pvDataCreate; - String trueString; - String falseString; - String illegalScalarType; }; -extern ConvertPtr getConvert(); +static inline ConvertPtr getConvert() { return Convert::getConvert(); } }} #endif /* CONVERT_H */ diff --git a/pvDataApp/pv/printer.h b/pvDataApp/pv/printer.h new file mode 100644 index 0000000..b9b60df --- /dev/null +++ b/pvDataApp/pv/printer.h @@ -0,0 +1,60 @@ +#ifndef PRINTER_H +#define PRINTER_H + +#include + +#include "pvData.h" + +namespace epics { namespace pvData { + +class PrinterBase +{ +public: + virtual void setStream(std::ostream&); + virtual void clearStream(); + + virtual void print(const PVField&); + +protected: + PrinterBase(); + virtual ~PrinterBase()=0; + + virtual void beginStructure(const PVStructure&); + virtual void endStructure(const PVStructure&); + + virtual void beginStructureArray(const PVStructureArray&); + virtual void endStructureArray(const PVStructureArray&); + + virtual void encodeScalar(const PVScalar&); + virtual void encodeArray(const PVScalarArray&); + virtual void encodeNull(); + + inline std::ostream& S() { return *strm; } + + void impl_print(const PVField&); +private: + std::ostream *strm; +}; + +class PrinterPlain : public PrinterBase +{ + size_t ilvl; +protected: + virtual void beginStructure(const PVStructure&); + virtual void endStructure(const PVStructure&); + + virtual void beginStructureArray(const PVStructureArray&); + virtual void endStructureArray(const PVStructureArray&); + + virtual void encodeScalar(const PVScalar&); + virtual void encodeArray(const PVScalarArray&); + virtual void encodeNull(); + +public: + PrinterPlain(); + virtual ~PrinterPlain(); +}; + +}} + +#endif // PRINTER_H diff --git a/pvDataApp/pv/pvData.h b/pvDataApp/pv/pvData.h index c1ffbc8..c48e36f 100644 --- a/pvDataApp/pv/pvData.h +++ b/pvDataApp/pv/pvData.h @@ -9,6 +9,15 @@ */ #ifndef PVDATA_H #define PVDATA_H + +#ifdef __GNUC__ +#define USAGE_DEPRECATED __attribute__((deprecated)) +#define USAGE_ERROR(MSG) __attribute__((error(MSG))) +#else +#define USAGE_DEPRECATED +#define USAGE_ERROR(MSG) +#endif + #include #include #include @@ -18,6 +27,8 @@ #include #include #include +#include +#include #if defined(__vxworks) && !defined(_WRS_VXWORKS_MAJOR) typedef class std::ios std::ios_base; @@ -96,7 +107,11 @@ class PVScalar; class PVScalarArray; class PVStructure; -class PVStructureArray; + + +template class PVScalarValue; +template class PVValueArray; + /** * typedef for a pointer to a PVAuxInfo. @@ -143,6 +158,8 @@ typedef std::vector::const_iterator PVStructurePtrArray_const__i /** * typedef for a pointer to a PVStructureArray. */ + +typedef PVValueArray PVStructureArray; typedef std::tr1::shared_ptr PVStructureArrayPtr; typedef std::vector PVStructureArrayPtrArray; typedef std::tr1::shared_ptr PVStructureArrayPtrArrayPtr; @@ -249,7 +266,13 @@ public: * Get the fieldName for this field. * @return The name or empty string if top level field. */ - String getFieldName() const ; + inline const String& getFieldName() const {return fieldName;} + /** + * Fully expand the name of this field using the + * names of its parent fields with a dot '.' seperating + * each name. + */ + String getFullName() const; /** * Register the message requester. * At most one requester can be registered. @@ -348,6 +371,7 @@ public: */ virtual std::ostream& dumpValue(std::ostream& o) const = 0; + protected: PVField::shared_pointer getPtrSelf() { @@ -370,7 +394,6 @@ private: bool immutable; RequesterPtr requester; PostHandlerPtr postHandler; - std::tr1::shared_ptr convert; friend class PVDataCreate; friend class PVStructure; }; @@ -381,6 +404,10 @@ std::ostream& operator<<(std::ostream& o, const PVField& f); * PVScalar is the base class for each scalar field. */ class PVScalar : public PVField { + // friend our child class(s) so that it + // can call protected methods of other + // PVScalar instances. + template friend class PVScalarValue; public: POINTER_DEFINITIONS(PVScalar); /** @@ -394,6 +421,47 @@ public: * @return the interface. */ const ScalarConstPtr getScalar() const ; + + /** + * Convert and return the scalar value in the requested type. + * Result type is determined from the function template argument + * which must be one of the ScalarType enums. + * Uses castUnsafe() for value conversion. + @code + PVScalar* pv = ...; + uint32 val = pv->getAs(); + @endcode + */ + template + inline T getAs() const { + T result; + this->getAs((void*)&result, (ScalarType)ScalarTypeID::value); + return result; + } +protected: + virtual void getAs(void *, ScalarType) const = 0; +public: + + /** + * Convert and assign the provided value. + * The value type is determined from the function template argument + * which must be one of the ScalarType enums. + * Uses castUnsafe() for value conversion. + @code + PVScalar* pv = ...; + pv->putFrom((int32)42); + @endcode + */ + template + inline void putFrom(T val) { + this->putFrom((const void*)&val, (ScalarType)ScalarTypeID::value); + } +protected: + virtual void putFrom(const void *, ScalarType) = 0; +public: + + virtual void assign(const PVScalar&) = 0; + protected: PVScalar(ScalarConstPtr const & scalar); }; @@ -408,6 +476,9 @@ public: typedef T value_type; typedef T* pointer; typedef const T* const_pointer; + + static const ScalarType typeCode; + /** * Destructor */ @@ -442,9 +513,42 @@ public: put(value); } + template + inline T1 getAs() const { + T1 result(castUnsafe(get())); + return result; + } + + template + inline void putFrom(T1 val) { + put(castUnsafe(val)); + } + protected: PVScalarValue(ScalarConstPtr const & scalar) : PVScalar(scalar) {} + virtual void getAs(void * result, ScalarType rtype) const + { + const T src = get(); + castUnsafeV(1, rtype, result, typeCode, (const void*)&src); + } + virtual void putFrom(const void *src, ScalarType stype) + { + T result; + castUnsafeV(1, typeCode, (void*)&result, stype, src); + put(result); + } + virtual void assign(const PVScalar& scalar) + { + if(this==&scalar) + return; + if(isImmutable()) + throw std::invalid_argument("Destination is immutable"); + T result; + scalar.getAs((void*)&result, typeCode); + put(result); + } + private: friend class PVDataCreate; }; @@ -452,7 +556,7 @@ private: /** * typedefs for the various possible scalar types. */ -typedef PVScalarValue PVBoolean; +typedef PVScalarValue PVBoolean; typedef PVScalarValue PVByte; typedef PVScalarValue PVShort; typedef PVScalarValue PVInt; @@ -500,7 +604,7 @@ public: /** * Destructor */ - virtual ~PVArray(); + virtual ~PVArray(){}; /** * Set the field to be immutable, i. e. it can no longer be modified. * This is permanent, i.e. once done the field can onot be made mutable. @@ -510,17 +614,17 @@ public: * Get the array length. * @return The length. */ - std::size_t getLength() const; + virtual std::size_t getLength() const = 0; /** * Set the array length. * @param The length. */ - virtual void setLength(std::size_t length); + virtual void setLength(std::size_t length) = 0; /** * Get the array capacity. * @return The capacity. */ - std::size_t getCapacity() const; + virtual std::size_t getCapacity() const = 0; /** * Can the capacity be changed. * @return (false,true) if (can not, can) be changed. @@ -541,9 +645,8 @@ public: protected: PVArray(FieldConstPtr const & field); - void setCapacityLength(std::size_t capacity,std::size_t length); private: - class PVArrayPvt * pImpl; + bool capacityMutable; friend class PVDataCreate; }; @@ -594,115 +697,62 @@ public: const ScalarArrayConstPtr getScalarArray() const ; protected: - PVScalarArray(ScalarArrayConstPtr const & scalarArray); -private: - friend class PVDataCreate; -}; - -/** - * This is provided by code that calls get. - */ -typedef PVArrayData StructureArrayData; - -/** - * Data class for a structureArray - */ -class PVStructureArray : public PVArray -{ + virtual void _getAsVoid(shared_vector&) const = 0; + virtual void _putFromVoid(const shared_vector&) = 0; public: - POINTER_DEFINITIONS(PVStructureArray); - typedef PVStructurePtr value_type; - typedef PVStructurePtr* pointer; - typedef const PVStructurePtr* const_pointer; - typedef PVArrayData ArrayDataType; - typedef std::vector vector; - typedef const std::vector const_vector; - typedef std::tr1::shared_ptr shared_vector; - typedef PVStructureArray &reference; - typedef const PVStructureArray& const_reference; - /** - * Destructor - */ - virtual ~PVStructureArray() {} - /** - * Set the array capacity. - * @param capacity The length. - */ - virtual void setCapacity(size_t capacity); - /** - * Set the array length. - * @param length The length. - */ - virtual void setLength(std::size_t length); - /** - * Get the introspection interface - * @return The interface. - */ - virtual StructureArrayConstPtr getStructureArray() const ; - /** - * Append new elements to the end of the array. - * @param number The number of elements to add. - * @return the new length of the array. - */ - virtual std::size_t append(std::size_t number); - /** - * Remove elements from the array. - * @param offset The offset of the first element to remove. - * @param number The number of elements to remove. - * @return (false,true) if the elements were removed. - */ - virtual bool remove(std::size_t offset,std::size_t number); - /** - * Compress. This removes all null elements from the array. - */ - virtual void compress(); - /** - * Get array elements - * @param offset The offset of the first element, - * @param length The number of elements to get. - * @param data The place where the data is placed. - */ - virtual std::size_t get(std::size_t offset, std::size_t length, - StructureArrayData &data); - /** - * Put data into the array. - * @param offset The offset of the first element, - * @param length The number of elements to get. - * @param from The new values to put into the array. - * @param fromOffset The offset in from. - * @return The number of elements put into the array. - */ - virtual std::size_t put(std::size_t offset,std::size_t length, - const_vector const & from, std::size_t fromOffset); - /** - * Share data from another source. - * @param value The data to share. - * @param capacity The capacity of the array. - * @param length The length of the array. - */ - virtual void shareData( - shared_vector const & value, - std::size_t capacity, - std::size_t length); - virtual void serialize(ByteBuffer *pbuffer, - SerializableControl *pflusher) const; - virtual void deserialize(ByteBuffer *buffer, - DeserializableControl *pflusher); - virtual void serialize(ByteBuffer *pbuffer, - SerializableControl *pflusher, std::size_t offset, std::size_t count) const ; - 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;} - virtual std::ostream& dumpValue(std::ostream& o) const; - virtual std::ostream& dumpValue(std::ostream& o, std::size_t index) const; + /** + * Fetch the current value and convert to the requested type. + * + * A copy is made if the requested type does not match + * the element type. If the types do match then + * no copy is made. + */ + template + void + getAs(shared_vector& out) const + { + shared_vector temp; + _getAsVoid(temp); + out = shared_vector_convert(temp); + } + + /** + * Assign the given value after conversion. + * + * A copy and element-wise conversion is performed unless + * the element type of the PVScalarArray matches the + * type of the provided data. + * If the types do match then a new refernce to the provided + * data is kept. + * + * Calls postPut() + */ + template + inline void putFrom(const shared_vector& inp) + { + shared_vector temp(static_shared_vector_cast(inp)); + _putFromVoid(temp); + } + + /** + * Assign the given PVScalarArray's value. + * + * A copy and element-wise conversion is performed unless + * the element type of the PVScalarArray matches the + * type of the provided data. + * If the types do match then a new refernce to the provided + * data is kept. + */ + void assign(PVScalarArray& pv) { + shared_vector temp; + pv._getAsVoid(temp); + _putFromVoid(temp); + } protected: - PVStructureArray(StructureArrayConstPtr const & structureArray); + PVScalarArray(ScalarArrayConstPtr const & scalarArray); private: - StructureArrayConstPtr structureArray; - shared_vector value; friend class PVDataCreate; }; @@ -934,99 +984,328 @@ private: friend class PVDataCreate; }; +namespace detail { + // adaptor to allow epics::pvData::shared_vector to hold a reference + // to a shared_ptr > + template + struct shared_ptr_vector_deletor { + typedef std::tr1::shared_ptr > shared_vector; + shared_vector vec; + shared_ptr_vector_deletor(const shared_vector& v) + :vec(v) {} + void operator()(T*){vec.reset();} + }; + + template + class PVVectorStorage : public Base + { + public: + typedef T value_type; + typedef T* pointer; + typedef const T* const_pointer; + + //TODO: full namespace can be removed along with local typedef 'shared_vector' + typedef ::epics::pvData::shared_vector svector; + typedef ::epics::pvData::shared_vector const_svector; + + // begin deprecated + typedef PVArrayData ArrayDataType; + typedef std::vector vector; + typedef const std::vector const_vector; + typedef std::tr1::shared_ptr shared_vector; + // end deprecated + + protected: + PVVectorStorage() : Base() {} + + template + PVVectorStorage(A a) : Base(a) {} + public: + virtual ~PVVectorStorage(){}; + + // Primative array manipulations + + //! Fetch a read-only view of the current array data + virtual const_svector view() const = 0; + + /** Exchange our contents for the provided. + * + @throws std::logic_error for Immutable arrays. + * + * Callers must ensure that postPut() is called + * after the last swap() operation. + * + * Before you call this directly, consider using + * the reuse(), or replace() methods. + */ + virtual void swap(const_svector& other) = 0; + + //! Discard current contents and replaced with the provided. + //! Fails for Immutable arrays + //! calls postPut() + virtual void replace(const const_svector& next) = 0; + + // Derived operations + + /** Remove and return the current array data + * or an unique copy if shared. + * + * Does @b not (and should not) call postPut() + * + * The returned shared_vector will + * have unique()==true. + */ + inline svector reuse() + { + const_svector result; + this->swap(result); + return thaw(result); + } + + /** + * Get array elements + * @param offset The offset of the first element, + * @param length The number of elements to get. + * @param data The place where the data is placed. + */ + std::size_t get( + std::size_t offset, std::size_t length, ArrayDataType &data) USAGE_DEPRECATED + { + const_svector ref = this->view(); + ref.slice(offset, length); + data.data.resize(ref.size()); + data.offset = 0; + std::copy(ref.begin(), ref.end(), data.data.begin()); + return ref.size(); + } + + /** + * Copy data into the array growing the length as needed. + * @param offset The offset of the first element, + * @param length The number of elements to get. + * @param from The new values to put into the array. + * @param fromOffset The offset in from. + * @return The number of elements put into the array. + * calls postPut() + */ + std::size_t put(std::size_t offset, + std::size_t length, const_pointer from, std::size_t fromOffset) USAGE_DEPRECATED + { + from += fromOffset; + + svector temp(this->reuse()); + if(temp.size() < length+offset) + temp.resize(length+offset); + else + temp.make_unique(); + + std::copy(from, from + length, temp.begin() + offset); + this->replace(freeze(temp)); + return length; + } + + std::size_t put(std::size_t offset, + std::size_t length, const_vector &from, std::size_t fromOffset) USAGE_DEPRECATED + { return this->put(offset,length, &from[0], fromOffset); } + + /** + * Share data from another source. + * @param value The data to share. + * @param capacity The capacity of the array. + * @param length The length of the array. + * Does @b not call postPut() + */ + void shareData( + shared_vector const & value, + std::size_t capacity, + std::size_t length) USAGE_DEPRECATED + { + vector& vref = *value.get(); + typename svector::shared_pointer_type p(&vref[0], + detail::shared_ptr_vector_deletor(value)); + const_svector temp(p, 0, std::min(length, vref.size())); + this->swap(temp); + } + + pointer get() const USAGE_DEPRECATED { + // evil unsafe cast! + return (pointer)this->view().data(); + } + + vector const & getVector() USAGE_ERROR("No longer implemented. Replace with view()"); + shared_vector const & getSharedVector() USAGE_ERROR("No longer implemented. Replace with view()"); + + }; +} // namespace detail + template -class PVValueArray : public PVScalarArray { +class PVValueArray : public detail::PVVectorStorage { + typedef detail::PVVectorStorage base_t; public: POINTER_DEFINITIONS(PVValueArray); typedef T value_type; typedef T* pointer; typedef const T* const_pointer; + + //TODO: full namespace can be removed along with local typedef 'shared_vector' + typedef ::epics::pvData::shared_vector svector; + typedef ::epics::pvData::shared_vector const_svector; + + // begin deprecated typedef PVArrayData ArrayDataType; typedef std::vector vector; typedef const std::vector const_vector; typedef std::tr1::shared_ptr shared_vector; typedef PVValueArray & reference; typedef const PVValueArray & const_reference; + // end deprecated + + static const ScalarType typeCode; /** * Destructor */ virtual ~PVValueArray() {} - /** - * Get array elements - * @param offset The offset of the first element, - * @param length The number of elements to get. - * @param data The place where the data is placed. - */ - virtual std::size_t get( - std::size_t offset, std::size_t length, ArrayDataType &data) = 0; - /** - * Put data into the array. - * @param offset The offset of the first element, - * @param length The number of elements to get. - * @param from The new values to put into the array. - * @param fromOffset The offset in from. - * @return The number of elements put into the array. - */ - 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); - /** - * Share data from another source. - * @param value The data to share. - * @param capacity The capacity of the array. - * @param length The length of the array. - */ - 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 { + const_svector v(this->view()); + typename const_svector::const_iterator it(v.begin()), + end(v.end()); o << '['; - std::size_t len = getLength(); - bool first = true; - for (std::size_t i = 0; i < len; i++) - { - if (first) - first = false; - else - o << ','; - dumpValue(o, i); - } + if(it!=end) { + o << print_cast(*it++); + for(; it!=end; ++it) + o << ',' << print_cast(*it); + + } return o << ']'; } std::ostream& dumpValue(std::ostream& o, size_t index) const { - return o << *(get() + index); + return o << print_cast(this->view().at(index)); } protected: + virtual void _getAsVoid(epics::pvData::shared_vector& out) const + { + out = static_shared_vector_cast(this->view()); + } + + virtual void _putFromVoid(const epics::pvData::shared_vector& in) + { + // TODO: try to re-use storage + replace(shared_vector_convert(in)); + } + PVValueArray(ScalarArrayConstPtr const & scalar) - : PVScalarArray(scalar) {} + : base_t(scalar) {} friend class PVDataCreate; }; -template -std::size_t PVValueArray::put( - std::size_t offset, - std::size_t length, - const_vector &from, - std::size_t fromOffset) -{ return put(offset,length, &from[0], fromOffset); } +/** + * This is provided by code that calls get. + */ +typedef PVArrayData StructureArrayData; + +/** + * Data class for a structureArray + */ +template<> +class PVValueArray : public detail::PVVectorStorage +{ + typedef detail::PVVectorStorage base_t; +public: + POINTER_DEFINITIONS(PVStructureArray); + typedef PVStructurePtr value_type; + typedef PVStructurePtr* pointer; + typedef const PVStructurePtr* const_pointer; + typedef PVArrayData ArrayDataType; + typedef std::vector vector; + typedef const std::vector const_vector; + typedef std::tr1::shared_ptr shared_vector; + typedef PVStructureArray &reference; + typedef const PVStructureArray& const_reference; + + //TODO: full namespace can be removed along with local typedef 'shared_vector' + typedef ::epics::pvData::shared_vector svector; + typedef ::epics::pvData::shared_vector const_svector; + /** + * Destructor + */ + virtual ~PVValueArray() {} + + virtual size_t getLength() const {return value.size();} + virtual size_t getCapacity() const {return value.capacity();} + + /** + * Set the array capacity. + * @param capacity The length. + */ + virtual void setCapacity(size_t capacity); + /** + * Set the array length. + * @param length The length. + */ + virtual void setLength(std::size_t length); + + /** + * Get the introspection interface + * @return The interface. + */ + StructureArrayConstPtr getStructureArray() const {return structureArray;} + /** + * Append new elements to the end of the array. + * @param number The number of elements to add. + * @return the new length of the array. + */ + virtual std::size_t append(std::size_t number); + /** + * Remove elements from the array. + * @param offset The offset of the first element to remove. + * @param number The number of elements to remove. + * @return (false,true) if the elements were removed. + */ + virtual bool remove(std::size_t offset,std::size_t number); + /** + * Compress. This removes all null elements from the array. + */ + virtual void compress(); + + virtual const_svector view() const { return value; } + virtual void swap(const_svector &other); + virtual void replace(const const_svector &other) { + value = other; + PVField::postPut(); + } + + virtual void serialize(ByteBuffer *pbuffer, + SerializableControl *pflusher) const; + virtual void deserialize(ByteBuffer *buffer, + DeserializableControl *pflusher); + virtual void serialize(ByteBuffer *pbuffer, + SerializableControl *pflusher, std::size_t offset, std::size_t count) const ; + + virtual std::ostream& dumpValue(std::ostream& o) const; + virtual std::ostream& dumpValue(std::ostream& o, std::size_t index) const; + +protected: + PVValueArray(StructureArrayConstPtr const & structureArray) + :base_t(structureArray) + ,structureArray(structureArray) + {} +private: + StructureArrayConstPtr structureArray; + const_svector value; + friend class PVDataCreate; +}; /** * Definitions for the various scalarArray types. */ -typedef PVArrayData BooleanArrayData; -typedef PVValueArray PVBooleanArray; +typedef PVArrayData BooleanArrayData; +typedef PVValueArray PVBooleanArray; typedef std::tr1::shared_ptr PVBooleanArrayPtr; typedef PVArrayData ByteArrayData; @@ -1171,6 +1450,9 @@ private: */ extern PVDataCreatePtr getPVDataCreate(); - + +#undef USAGE_DEPRECATED +#undef USAGE_ERROR + }} #endif /* PVDATA_H */ diff --git a/pvDataApp/pv/pvIntrospect.h b/pvDataApp/pv/pvIntrospect.h index defd954..5a087cc 100644 --- a/pvDataApp/pv/pvIntrospect.h +++ b/pvDataApp/pv/pvIntrospect.h @@ -191,6 +191,9 @@ namespace ScalarTypeFunc { * @param scalarType The type. */ void toString(StringBuilder builder,ScalarType scalarType); + + //! gives sizeof(T) where T depends on the scalar type id. + size_t elementSize(ScalarType id); }; /** @@ -439,7 +442,7 @@ public: * @param fieldIndex The index of the desired field. * @return The fieldName. */ - String getFieldName(std::size_t fieldIndex){return fieldNames[fieldIndex];} + String getFieldName(std::size_t fieldIndex) const {return fieldNames[fieldIndex];} /** * Convert the structure to a string and add it to builder. * @param builder The string builder. @@ -555,5 +558,46 @@ private: */ extern FieldCreatePtr getFieldCreate(); +/** Define a compile time mapping from + * type to enum value. + @code + ScalarType code = (ScalarType)ScalarTypeID::value; + assert(code==pvByte); + @endcode + * + * For unspecified types this evaluates to an invalid ScalarType + * value (eg -1). + */ +template +struct ScalarTypeID { enum {value=-1}; }; + +/** + * Static mapping from ScalarType enum to value type. + @code + typename ScalarTypeTraits::type value = 4; + @endcode + */ +template +struct ScalarTypeTraits {}; + +#define OP(ENUM, TYPE) \ +template<> struct ScalarTypeTraits {typedef TYPE type;}; \ +template<> struct ScalarTypeID { enum {value=ENUM}; }; \ +template<> struct ScalarTypeID { enum {value=ENUM}; }; + +OP(pvBoolean, boolean) +OP(pvByte, int8) +OP(pvShort, int16) +OP(pvInt, int32) +OP(pvLong, int64) +OP(pvUByte, uint8) +OP(pvUShort, uint16) +OP(pvUInt, uint32) +OP(pvULong, uint64) +OP(pvFloat, float) +OP(pvDouble, double) +OP(pvString, String) +#undef OP + }} #endif /* PVINTROSPECT_H */ diff --git a/pvDataApp/pv/pvType.h b/pvDataApp/pv/pvType.h index d25d40b..618b4fd 100644 --- a/pvDataApp/pv/pvType.h +++ b/pvDataApp/pv/pvType.h @@ -21,8 +21,10 @@ (_WRS_VXWORKS_MAJOR+0 <= 6) && (_WRS_VXWORKS_MINOR+0 < 9) typedef int intptr_t; typedef unsigned int uintptr_t; +#ifndef INT64_MAX #define INT64_MAX (0x7fffffffffffffffLL) #define UINT64_MAX (0xffffffffffffffffLL) +#endif #else #include #endif @@ -32,6 +34,14 @@ typedef unsigned int uintptr_t; namespace epics { namespace pvData { +namespace detail { + // Pick either type If or type Else to not be Cond + template + struct pick_type { typedef If type; }; + template + struct pick_type { typedef Else type; }; +} + /** * This is a set of typdefs used by pvData. */ @@ -39,7 +49,9 @@ namespace epics { namespace pvData { /** * boolean, i.e. can only have the values {@code false} or {@code true} */ -typedef uint8_t boolean; +typedef detail::pick_type::type + >::type boolean; /** * A 8 bit signed integer */ diff --git a/testApp/misc/Makefile b/testApp/misc/Makefile index 077f4eb..f627433 100644 --- a/testApp/misc/Makefile +++ b/testApp/misc/Makefile @@ -2,45 +2,48 @@ TOP=../.. include $(TOP)/configure/CONFIG +PROD_LIBS += pvData Com + PROD_HOST += testThread testThread_SRCS += testThread.cpp -testThread_LIBS += pvData Com PROD_HOST += testTimer testTimer_SRCS += testTimer.cpp -testTimer_LIBS += pvData Com PROD_HOST += testBitSet testBitSet_SRCS += testBitSet.cpp -testBitSet_LIBS += pvData Com PROD_HOST += testByteOrder testByteOrder_SRCS += testByteOrder.cpp -testByteOrder_LIBS += Com PROD_HOST += testByteBuffer testByteBuffer_SRCS += testByteBuffer.cpp -testByteBuffer_LIBS += pvData Com PROD_HOST += testBaseException testBaseException_SRCS += testBaseException.cpp -testBaseException_LIBS += pvData Com -PROD_HOST += testSerialization +TESTPROD += testSerialization testSerialization_SRCS += testSerialization.cpp -testSerialization_LIBS += pvData Com +TESTS += testSerialization PROD_HOST += testTimeStamp testTimeStamp_SRCS += testTimeStamp.cpp -testTimeStamp_LIBS += pvData Com PROD_HOST += testQueue testQueue_SRCS += testQueue.cpp -testQueue_LIBS += pvData Com PROD_HOST += testMessageQueue testMessageQueue_SRCS += testMessageQueue.cpp -testMessageQueue_LIBS += pvData Com + +TESTPROD += testTypeCast +testTypeCast_SRCS += testTypeCast.cpp +TESTS += testTypeCast + +TESTPROD += testSharedVector +testSharedVector_SRCS += testSharedVector.cpp +TESTS += testSharedVector + +TESTSCRIPTS_HOST += $(TESTS:%=%.t) include $(TOP)/configure/RULES #---------------------------------------- diff --git a/testApp/misc/testSerialization.cpp b/testApp/misc/testSerialization.cpp index a1fd98f..3549b5a 100644 --- a/testApp/misc/testSerialization.cpp +++ b/testApp/misc/testSerialization.cpp @@ -12,7 +12,9 @@ #include #include -#include +#include +#include +#include // for NELEMENTS #include #include @@ -45,6 +47,8 @@ using namespace epics::pvData; +namespace { + static SerializableControl* flusher; static DeserializableControl* control; static ByteBuffer* buffer; @@ -122,14 +126,23 @@ void serializationTest(PVFieldPtr const & field) { deserializedField->deserialize(buffer, control); // must equal - bool isEqual = getConvert()->equals(*field,*deserializedField); - assert(isEqual); + if(*field==*deserializedField) + testPass("Serialization round trip OK"); + else { + testFail("Serialization round trip did not match!"); + std::string buf; + field->toString(&buf); + testDiag("Expected: %s", buf.c_str()); + buf.clear(); + deserializedField->toString(&buf); + testDiag("Found: %s", buf.c_str()); + } } -void testEquals(std::ostream& ofile) { - ofile<<"Testing equals...\n"; +void testEquals() { + testDiag("Testing equals..."); PVDataCreatePtr factory = getPVDataCreate(); - assert(factory.get()!=NULL); + testOk1(factory.get()!=NULL); // be sure all is covered for (int i = pvBoolean; i < pvString; i++) @@ -138,32 +151,63 @@ void testEquals(std::ostream& ofile) { PVScalarPtr scalar1 = factory->createPVScalar(scalarType); PVScalarPtr scalar2 = factory->createPVScalar(scalarType); - assert((*scalar1)==(*scalar2)); + testOk1((*scalar1)==(*scalar2)); PVScalarArrayPtr array1 = factory->createPVScalarArray(scalarType); PVScalarArrayPtr array2 = factory->createPVScalarArray(scalarType); - assert((*array1)==(*array2)); + testOk1((*array1)==(*array2)); } // and a structure PVStructurePtr structure1 = factory->createPVStructure(getStandardField()->timeStamp()); PVStructurePtr structure2 = factory->createPVStructure(getStandardField()->timeStamp()); - assert((*structure1)==(*structure2)); + testOk1((*structure1)==(*structure2)); // and a structure array PVStructureArrayPtr structureArray1 = factory->createPVStructureArray(getFieldCreate()->createStructureArray(structure1->getStructure())); PVStructureArrayPtr structureArray2 = factory->createPVStructureArray(getFieldCreate()->createStructureArray(structure2->getStructure())); - assert((*structureArray1)==(*structureArray2)); - - ofile<<"!!! PASSED\n\n"; + testOk1((*structureArray1)==(*structureArray2)); } -void testScalar(std::ostream& ofile) { - ofile<<"Testing scalars...\n"; - PVDataCreatePtr factory = getPVDataCreate(); - assert(factory.get()!=NULL); +template +void testScalarType() +{ + typedef typename PVT::value_type value_type; - ofile<<"\tPVBoolean\n"; + testDiag("type %s", ScalarTypeFunc::name(PVT::typeCode)); + + typename PVT::shared_pointer pv = std::tr1::static_pointer_cast(getPVDataCreate()->createPVScalar(PVT::typeCode)); + + pv->put(0); + serializationTest(pv); + pv->put(42); + serializationTest(pv); + pv->put(std::numeric_limits::max()-1); + serializationTest(pv); + pv->put(std::numeric_limits::max()); + serializationTest(pv); + + if(std::numeric_limits::min()!=0) { + pv->put(-42); + serializationTest(pv); + pv->put(std::numeric_limits::min()+1); + serializationTest(pv); + pv->put(std::numeric_limits::min()); + serializationTest(pv); + } + + if(std::numeric_limits::has_infinity) { + pv->put(std::numeric_limits::infinity()); + serializationTest(pv); + } +} + +void testScalar() { + testDiag("Testing scalars..."); + PVDataCreatePtr factory = getPVDataCreate(); + testOk1(factory.get()!=NULL); + + testDiag("type %s", ScalarTypeFunc::name(pvBoolean)); PVBooleanPtr pvBoolean = std::tr1::static_pointer_cast(factory->createPVScalar(epics::pvData::pvBoolean)); pvBoolean->put(false); @@ -171,196 +215,19 @@ void testScalar(std::ostream& ofile) { pvBoolean->put(true); serializationTest(pvBoolean); - ofile<<"\tPVByte\n"; - PVBytePtr pvByte = - std::tr1::static_pointer_cast(factory->createPVScalar(epics::pvData::pvByte)); - pvByte->put(0); - serializationTest(pvByte); - pvByte->put(12); - serializationTest(pvByte); - pvByte->put(BYTE_MAX_VALUE); - serializationTest(pvByte); - pvByte->put(BYTE_MIN_VALUE); - serializationTest(pvByte); - - ofile<<"\tPVShort\n"; - PVShortPtr pvShort = - std::tr1::static_pointer_cast(factory->createPVScalar(epics::pvData::pvShort)); - pvShort->put(0); - serializationTest(pvShort); - pvShort->put(123); - serializationTest(pvShort); - pvShort->put(BYTE_MAX_VALUE); - serializationTest(pvShort); - pvShort->put(BYTE_MIN_VALUE); - serializationTest(pvShort); - pvShort->put(SHORT_MAX_VALUE); - serializationTest(pvShort); - pvShort->put(SHORT_MIN_VALUE); - serializationTest(pvShort); - - ofile<<"\tPVInt\n"; - PVIntPtr pvInt = - std::tr1::static_pointer_cast(factory->createPVScalar(epics::pvData::pvInt)); - pvInt->put(0); - serializationTest(pvInt); - pvInt->put(123456); - serializationTest(pvInt); - pvInt->put(BYTE_MAX_VALUE); - serializationTest(pvInt); - pvInt->put(BYTE_MIN_VALUE); - serializationTest(pvInt); - pvInt->put(SHORT_MAX_VALUE); - serializationTest(pvInt); - pvInt->put(SHORT_MIN_VALUE); - serializationTest(pvInt); - pvInt->put(INT_MAX_VALUE); - serializationTest(pvInt); - pvInt->put(INT_MIN_VALUE); - serializationTest(pvInt); - - ofile<<"\tPVLong\n"; - PVLongPtr pvLong = - std::tr1::static_pointer_cast(factory->createPVScalar(epics::pvData::pvLong)); - pvLong->put(0); - serializationTest(pvLong); - pvLong->put(12345678901LL); - serializationTest(pvLong); - pvLong->put(BYTE_MAX_VALUE); - serializationTest(pvLong); - pvLong->put(BYTE_MIN_VALUE); - serializationTest(pvLong); - pvLong->put(SHORT_MAX_VALUE); - serializationTest(pvLong); - pvLong->put(SHORT_MIN_VALUE); - serializationTest(pvLong); - pvLong->put(INT_MAX_VALUE); - serializationTest(pvLong); - pvLong->put(INT_MIN_VALUE); - serializationTest(pvLong); - pvLong->put(LONG_MAX_VALUE); - serializationTest(pvLong); - pvLong->put(LONG_MIN_VALUE); - serializationTest(pvLong); + testScalarType(); + testScalarType(); + testScalarType(); + testScalarType(); + testScalarType(); + testScalarType(); + testScalarType(); + testScalarType(); + testScalarType(); + testScalarType(); - ofile<<"\tPVUByte\n"; - PVUBytePtr pvUByte = - std::tr1::static_pointer_cast(factory->createPVScalar(epics::pvData::pvUByte)); - pvUByte->put(0); - serializationTest(pvUByte); - pvUByte->put(12); - serializationTest(pvUByte); - pvUByte->put(UBYTE_MAX_VALUE); - serializationTest(pvUByte); - pvUByte->put(BYTE_MAX_VALUE); - serializationTest(pvUByte); - pvUByte->put(BYTE_MIN_VALUE); - serializationTest(pvUByte); - - ofile<<"\tPVUShort\n"; - PVUShortPtr pvUShort = - std::tr1::static_pointer_cast(factory->createPVScalar(epics::pvData::pvUShort)); - pvUShort->put(0); - serializationTest(pvUShort); - pvUShort->put(1234); - serializationTest(pvUShort); - pvUShort->put(BYTE_MAX_VALUE); - serializationTest(pvUShort); - pvUShort->put(BYTE_MIN_VALUE); - serializationTest(pvUShort); - pvUShort->put(UBYTE_MAX_VALUE); - serializationTest(pvUShort); - pvUShort->put(SHORT_MAX_VALUE); - serializationTest(pvUShort); - pvUShort->put(SHORT_MIN_VALUE); - serializationTest(pvUShort); - pvUShort->put(USHORT_MAX_VALUE); - serializationTest(pvUShort); - - ofile<<"\tPVInt\n"; - PVIntPtr pvUInt = - std::tr1::static_pointer_cast(factory->createPVScalar(epics::pvData::pvUInt)); - pvUInt->put(0); - serializationTest(pvUInt); - pvUInt->put(123456); - serializationTest(pvUInt); - pvUInt->put(BYTE_MAX_VALUE); - serializationTest(pvUInt); - pvUInt->put(BYTE_MIN_VALUE); - serializationTest(pvUInt); - pvUInt->put(UBYTE_MAX_VALUE); - serializationTest(pvUInt); - pvUInt->put(SHORT_MAX_VALUE); - serializationTest(pvUInt); - pvUInt->put(SHORT_MIN_VALUE); - serializationTest(pvUInt); - pvUInt->put(USHORT_MAX_VALUE); - serializationTest(pvUInt); - pvUInt->put(INT_MAX_VALUE); - serializationTest(pvUInt); - pvUInt->put(INT_MIN_VALUE); - serializationTest(pvUInt); - pvUInt->put(UINT_MAX_VALUE); - serializationTest(pvUInt); - - ofile<<"\tPVLong\n"; - PVLongPtr pvULong = - std::tr1::static_pointer_cast(factory->createPVScalar(epics::pvData::pvULong)); - pvULong->put(0); - serializationTest(pvULong); - pvULong->put(12345678901LL); - serializationTest(pvULong); - pvULong->put(BYTE_MAX_VALUE); - serializationTest(pvULong); - pvULong->put(BYTE_MIN_VALUE); - serializationTest(pvULong); - pvULong->put(UBYTE_MAX_VALUE); - serializationTest(pvULong); - pvULong->put(SHORT_MAX_VALUE); - serializationTest(pvULong); - pvULong->put(SHORT_MIN_VALUE); - serializationTest(pvULong); - pvULong->put(USHORT_MAX_VALUE); - serializationTest(pvULong); - pvULong->put(INT_MAX_VALUE); - serializationTest(pvULong); - pvULong->put(INT_MIN_VALUE); - serializationTest(pvULong); - pvULong->put(UINT_MAX_VALUE); - serializationTest(pvULong); - pvULong->put(LONG_MAX_VALUE); - serializationTest(pvULong); - pvULong->put(LONG_MIN_VALUE); - serializationTest(pvULong); - pvULong->put(ULONG_MAX_VALUE); - serializationTest(pvULong); - - ofile<<"\tPVFloat\n"; - PVFloatPtr pvFloat = - std::tr1::static_pointer_cast(factory->createPVScalar(epics::pvData::pvFloat)); - pvFloat->put(0); - serializationTest(pvFloat); - pvFloat->put(12.345); - serializationTest(pvFloat); - pvFloat->put(FLOAT_MAX_VALUE); - serializationTest(pvFloat); - pvFloat->put(FLOAT_MIN_VALUE); - serializationTest(pvFloat); - - ofile<<"\tPVDouble\n"; - PVDoublePtr pvDouble = - std::tr1::static_pointer_cast(factory->createPVScalar(epics::pvData::pvDouble)); - pvDouble->put(0); - serializationTest(pvDouble); - pvDouble->put(12.345); - serializationTest(pvDouble); - pvDouble->put(DOUBLE_MAX_VALUE); - serializationTest(pvDouble); - pvDouble->put(DOUBLE_MIN_VALUE); - serializationTest(pvDouble); - - ofile<<"\tPVString\n"; + testDiag("type %s", ScalarTypeFunc::name(pvString)); PVStringPtr pvString = std::tr1::static_pointer_cast(factory->createPVScalar(epics::pvData::pvString)); pvString->put(""); @@ -377,167 +244,88 @@ void testScalar(std::ostream& ofile) { // huge string test pvString->put(String(10000, 'a')); serializationTest(pvString); - - // TODO unsigned test - - ofile<<"!!! PASSED\n\n"; } -void testArray(std::ostream& ofile) { - ofile<<"Testing arrays...\n"; +template +void testArrayType(const typename PVT::value_type* rdata, size_t len) +{ + typedef typename PVT::value_type value_type; - PVDataCreatePtr factory = getPVDataCreate(); - assert(factory.get()!=NULL); + typename PVT::svector empty(0), data(len); - ofile<<"\tPVBooleanArray\n"; - //bool boolEmpty[] = { false }; - //bool bv[] = { false, true, false, true, true }; - PVBooleanArrayPtr pvBoolean = - std::tr1::static_pointer_cast(factory->createPVScalarArray(epics::pvData::pvBoolean)); - //pvBoolean->put(0, 0, boolEmpty, 0); - serializationTest(pvBoolean); - //pvBoolean->put(0, 5, bv, 0); - serializationTest(pvBoolean); + std::copy(rdata, rdata+len, data.begin()); - ofile<<"\tPVByteArray\n"; - int8 byteEmpty[] = { 0 }; - int8 byv[] = { 0, 1, 2, -1, BYTE_MAX_VALUE, BYTE_MAX_VALUE-1, - BYTE_MIN_VALUE+1, BYTE_MIN_VALUE }; - PVByteArrayPtr pvByte = - std::tr1::static_pointer_cast(factory->createPVScalarArray(epics::pvData::pvByte)); - pvByte->put(0, 0, byteEmpty, 0); - serializationTest(pvByte); - pvByte->put(0, 8, byv, 0); - serializationTest(pvByte); + testDiag("type %s", ScalarTypeFunc::name(PVT::typeCode)); - ofile<<"\tPVShortArray\n"; - int16 shortEmpty[] = { 0 }; - int16 sv[] = { 0, 1, 2, -1, SHORT_MAX_VALUE, SHORT_MAX_VALUE-1, - SHORT_MIN_VALUE+1, SHORT_MIN_VALUE }; - PVShortArrayPtr pvShort = - std::tr1::static_pointer_cast(factory->createPVScalarArray(epics::pvData::pvShort)); - pvShort->put(0, 0, shortEmpty, 0); - serializationTest(pvShort); - pvShort->put(0, 8, sv, 0); - serializationTest(pvShort); + typename PVT::shared_pointer pv = std::tr1::static_pointer_cast(getPVDataCreate()->createPVScalarArray(PVT::typeCode)); - ofile<<"\tPVIntArray\n"; - int32 intEmpty[] = { 0 }; - int32 iv[] = { 0, 1, 2, -1, INT_MAX_VALUE, INT_MAX_VALUE-1, - INT_MIN_VALUE+1, INT_MIN_VALUE }; - PVIntArrayPtr pvInt = - std::tr1::static_pointer_cast(factory->createPVScalarArray(epics::pvData::pvInt)); - pvInt->put(0, 0, intEmpty, 0); - serializationTest(pvInt); - pvInt->put(0, 8, iv, 0); - serializationTest(pvInt); - - ofile<<"\tPVLongArray\n"; - int64 longEmpty[] = { 0 }; - int64 lv[] = { 0, 1, 2, -1, LONG_MAX_VALUE, LONG_MAX_VALUE-1, - LONG_MIN_VALUE+1, LONG_MIN_VALUE }; - PVLongArrayPtr pvLong = - std::tr1::static_pointer_cast(factory->createPVScalarArray(epics::pvData::pvLong)); - pvLong->put(0, 0, longEmpty, 0); - serializationTest(pvLong); - pvLong->put(0, 8, lv, 0); - serializationTest(pvLong); - - ofile<<"\tPVUByteArray\n"; - uint8 ubyteEmpty[] = { 0 }; - uint8 ubyv[] = { 0, 1, 2, -1, BYTE_MAX_VALUE, BYTE_MAX_VALUE-1, - BYTE_MIN_VALUE+1, BYTE_MIN_VALUE, UBYTE_MAX_VALUE }; - PVUByteArrayPtr pvUByte = - std::tr1::static_pointer_cast(factory->createPVScalarArray(epics::pvData::pvUByte)); - pvUByte->put(0, 0, ubyteEmpty, 0); - serializationTest(pvUByte); - pvUByte->put(0, 9, ubyv, 0); - serializationTest(pvUByte); - - ofile<<"\tPVUShortArray\n"; - uint16 ushortEmpty[] = { 0 }; - uint16 usv[] = { 0, 1, 2, -1, SHORT_MAX_VALUE, SHORT_MAX_VALUE-1, - SHORT_MIN_VALUE+1, SHORT_MIN_VALUE, USHORT_MAX_VALUE }; - PVUShortArrayPtr pvUShort = - std::tr1::static_pointer_cast(factory->createPVScalarArray(epics::pvData::pvUShort)); - pvUShort->put(0, 0, ushortEmpty, 0); - serializationTest(pvUShort); - pvUShort->put(0, 8, usv, 0); - serializationTest(pvUShort); - - ofile<<"\tPVUIntArray\n"; - uint32 uintEmpty[] = { 0 }; - uint32 uiv[] = { 0, 1, 2, -1, INT_MAX_VALUE, INT_MAX_VALUE-1, - INT_MIN_VALUE+1, INT_MIN_VALUE, UINT_MAX_VALUE }; - PVUIntArrayPtr pvUInt = - std::tr1::static_pointer_cast(factory->createPVScalarArray(epics::pvData::pvUInt)); - pvUInt->put(0, 0, uintEmpty, 0); - serializationTest(pvUInt); - pvUInt->put(0, 9, uiv, 0); - serializationTest(pvUInt); - - ofile<<"\tPVULongArray\n"; - uint64 ulongEmpty[] = { 0 }; - uint64 ulv[] = { 0, 1, 2, -1, LONG_MAX_VALUE, LONG_MAX_VALUE-1, - LONG_MIN_VALUE+1, LONG_MIN_VALUE, ULONG_MAX_VALUE }; - PVULongArrayPtr pvULong = - std::tr1::static_pointer_cast(factory->createPVScalarArray(epics::pvData::pvULong)); - pvULong->put(0, 0, ulongEmpty, 0); - serializationTest(pvULong); - pvULong->put(0, 9, ulv, 0); - serializationTest(pvULong); - - ofile<<"\tPVFloatArray\n"; - float floatEmpty[] = { (float)0.0 }; - float fv[] = { (float)0.0, (float)1.1, (float)2.3, (float)-1.4, - FLOAT_MAX_VALUE, FLOAT_MAX_VALUE-(float)123456.789, FLOAT_MIN_VALUE - +(float)1.1, FLOAT_MIN_VALUE }; - PVFloatArrayPtr pvFloat = - std::tr1::static_pointer_cast(factory->createPVScalarArray(epics::pvData::pvFloat)); - pvFloat->put(0, 0, floatEmpty, 0); - serializationTest(pvFloat); - pvFloat->put(0, 8, fv, 0); - serializationTest(pvFloat); - - ofile<<"\tPVDoubleArray\n"; - double doubleEmpty[] = { (double)0.0 }; - double dv[] = { (double)0.0, (double)1.1, (double)2.3, (double)-1.4, - DOUBLE_MAX_VALUE, DOUBLE_MAX_VALUE-(double)123456.789, - DOUBLE_MIN_VALUE+(double)1.1, DOUBLE_MIN_VALUE }; - PVDoubleArrayPtr pvDouble = - std::tr1::static_pointer_cast(factory->createPVScalarArray(epics::pvData::pvDouble)); - pvDouble->put(0, 0, doubleEmpty, 0); - serializationTest(pvDouble); - pvDouble->put(0, 8, dv, 0); - serializationTest(pvDouble); - - ofile<<"\tPVStringArray\n"; - String stringEmpty[] = { "" }; - String - strv[] = - { - "", - "a", - "a b", - " ", - "test", - "smile", - "this is a little longer string... maybe a little but longer... this makes test better", - String(10000, 'b') }; - PVStringArrayPtr pvString = - std::tr1::static_pointer_cast(factory->createPVScalarArray(epics::pvData::pvString)); - pvString->put(0, 0, stringEmpty, 0); - serializationTest(pvString); - pvString->put(0, 8, strv, 0); - serializationTest(pvString); - - ofile<<"!!! PASSED\n\n"; + pv->replace(freeze(empty)); + serializationTest(pv); + pv->replace(freeze(data)); + serializationTest(pv); } -void testNonInitialized(std::ostream& ofile) { - ofile<<"Testing non-initialized...\n"; +static const boolean bdata[] = {0, 1, 0, 1, 1}; + +static const int8 i8data[] = { 0, 1, 2, -1, BYTE_MAX_VALUE, BYTE_MAX_VALUE-1, + BYTE_MIN_VALUE+1, BYTE_MIN_VALUE }; +static const uint8 u8data[] = { 0, 1, 2, -1, UBYTE_MAX_VALUE, UBYTE_MAX_VALUE-1 }; + +static const int16 i16data[] = { 0, 1, 2, -1, SHORT_MAX_VALUE, SHORT_MAX_VALUE-1, + SHORT_MIN_VALUE+1, SHORT_MIN_VALUE }; +static const uint16 u16data[] = { 0, 1, 2, -1, USHORT_MAX_VALUE, USHORT_MAX_VALUE-1 }; + +static const int32 i32data[] = { 0, 1, 2, -1, INT_MAX_VALUE, INT_MAX_VALUE-1, + INT_MIN_VALUE+1, INT_MIN_VALUE }; +static const uint32 u32data[] = { 0, 1, 2, -1, UINT_MAX_VALUE, UINT_MAX_VALUE-1 }; + +static const int64 i64data[] = { 0, 1, 2, -1, LONG_MAX_VALUE, LONG_MAX_VALUE-1, + LONG_MIN_VALUE+1, LONG_MIN_VALUE }; +static const uint64 u64data[] = { 0, 1, 2, -1, ULONG_MAX_VALUE, ULONG_MAX_VALUE-1 }; + +static const double ddata[] = { (double)0.0, (double)1.1, (double)2.3, (double)-1.4, + DOUBLE_MAX_VALUE, DOUBLE_MAX_VALUE-(double)123456.789, + DOUBLE_MIN_VALUE+(double)1.1, DOUBLE_MIN_VALUE }; + +static const float fdata[] = { (float)0.0, (float)1.1, (float)2.3, (float)-1.4, + FLOAT_MAX_VALUE, FLOAT_MAX_VALUE-(float)123456.789, + FLOAT_MIN_VALUE+(float)1.1, FLOAT_MIN_VALUE }; + +static const String sdata[] = { + "", + "a", + "a b", + " ", + "test", + "smile", + "this is a little longer string... maybe a little but longer... this makes test better", + String(10000, 'b') +}; + +void testArray() { + testDiag("Testing arrays..."); + + testArrayType(bdata, NELEMENTS(bdata)); + + testArrayType(i8data, NELEMENTS(i8data)); + testArrayType(u8data, NELEMENTS(u8data)); + testArrayType(i16data, NELEMENTS(i16data)); + testArrayType(u16data, NELEMENTS(u16data)); + testArrayType(i32data, NELEMENTS(i32data)); + testArrayType(u32data, NELEMENTS(u32data)); + testArrayType(i64data, NELEMENTS(i64data)); + testArrayType(u64data, NELEMENTS(u64data)); + + testArrayType(ddata, NELEMENTS(ddata)); + testArrayType(fdata, NELEMENTS(fdata)); + + testArrayType(sdata, NELEMENTS(sdata)); +} + +void testNonInitialized() { + testDiag("Testing non-initialized..."); PVDataCreatePtr factory = getPVDataCreate(); - assert(factory.get()!=NULL); + testOk1(factory.get()!=NULL); // be sure all is covered for (int i = pvBoolean; i < pvString; i++) @@ -558,17 +346,15 @@ void testNonInitialized(std::ostream& ofile) { // and a structure array PVStructureArrayPtr structureArray = factory->createPVStructureArray(getFieldCreate()->createStructureArray(structure->getStructure())); serializationTest(structureArray); - - ofile<<"!!! PASSED\n\n"; } -void testStructure(std::ostream& ofile) { - ofile<<"Testing structure...\n"; +void testStructure() { + testDiag("Testing structure..."); PVDataCreatePtr factory = getPVDataCreate(); - assert(factory.get()!=NULL); + testOk1(factory.get()!=NULL); - ofile<<"\tSimple structure serialization\n"; + testDiag("\tSimple structure serialization"); PVStructurePtr pvStructure = factory->createPVStructure(getStandardField()->timeStamp()); pvStructure->getLongField("secondsPastEpoch")->put(123); pvStructure->getIntField("nanoSeconds")->put(456); @@ -576,21 +362,47 @@ void testStructure(std::ostream& ofile) { serializationTest(pvStructure); - ofile<<"\tComplex structure serialization\n"; + testDiag("\tComplex structure serialization"); pvStructure = factory->createPVStructure( getStandardField()->structureArray( getStandardField()->timeStamp(), "alarm,control,display,timeStamp") ); // TODO fill with data serializationTest(pvStructure); +} - ofile<<"!!! PASSED\n\n"; +void testStructureArray() { + testDiag("Testing structure array..."); + + PVDataCreatePtr factory = getPVDataCreate(); + testOk1(factory.get()!=NULL); + + StructureArrayConstPtr tstype( + getFieldCreate()->createStructureArray(getStandardField()->alarm())); + PVStructureArrayPtr pvArr = getPVDataCreate()->createPVStructureArray(tstype); + + testDiag("empty array"); + serializationTest(pvArr); + + pvArr->setLength(10); + + testDiag("All NULLs"); + serializationTest(pvArr); + + PVStructureArray::svector data(5); + + data[1] = getPVDataCreate()->createPVStructure(getStandardField()->alarm()); + data[4] = getPVDataCreate()->createPVStructure(getStandardField()->alarm()); + + pvArr->replace(freeze(data)); + + testDiag("Some NULLs"); + serializationTest(pvArr); } - -void testStructureId(std::ostream& ofile) { - ofile<<"Testing structureID...\n"; +void testStructureId() { + testDiag("Testing structureID..."); FieldCreatePtr fieldCreate = getFieldCreate(); @@ -607,15 +419,13 @@ void testStructureId(std::ostream& ofile) { StructureConstPtr structure2 = fieldCreate->createStructure("id2", fieldNames, fields); - assert(structureWithNoId!=structure1); - assert(structure1!=structure2); + testOk1(structureWithNoId!=structure1); + testOk1(structure1!=structure2); //serializationTest(structure1); PVStructurePtr pvStructure = getPVDataCreate()->createPVStructure(structure1); serializationTest(pvStructure); - - ofile<<"!!! PASSED\n\n"; } void serializatioTest(FieldConstPtr const & field) @@ -631,17 +441,15 @@ void serializatioTest(FieldConstPtr const & field) FieldConstPtr deserializedField = getFieldCreate()->deserialize(buffer, control); // must equal - bool isEqual = *field == *deserializedField; - assert(isEqual); - //assertEquals("field " + field.toString() + " serialization broken", field, deserializedField); + testOk1(*field == *deserializedField); } -void testIntrospectionSerialization(std::ostream& ofile) +void testIntrospectionSerialization() { - ofile<<"Testing introspection serialization...\n"; + testDiag("Testing introspection serialization..."); FieldCreatePtr factory = getFieldCreate(); - assert(factory.get()!=NULL); + testOk1(factory.get()!=NULL); // be sure all is covered for (int i = pvBoolean; i < pvString; i++) @@ -662,42 +470,35 @@ void testIntrospectionSerialization(std::ostream& ofile) // and a structure array StructureArrayConstPtr structureArray = factory->createStructureArray(structure); serializatioTest(structureArray); - - ofile<<"!!! PASSED\n\n"; } -void testStringCopy(std::ostream& ofile) { +void testStringCopy() { String s1 = "abc"; String s2 = s1; if (s1.c_str() != s2.c_str()) - ofile << "\n!!! implementation of epics::pvData::String assignment operator does not share content !!!\n\n"; + testDiag("implementation of epics::pvData::String assignment operator does not share content"); } -int main(int argc, char *argv[]) { - std::ofstream outfile; - std::ostream *out=NULL; - if(argc>1) { - outfile.open(argv[1]); - if(outfile.is_open()){ - out=&outfile; - }else{ - fprintf(stderr, "Failed to open test output file\n"); - } - } - if(!out) out=&std::cout; +} // end namespace + +MAIN(testSerialization) { + + testPlan(175); + flusher = new SerializableControlImpl(); control = new DeserializableControlImpl(); buffer = new ByteBuffer(1<<16); - testStringCopy(*out); + testStringCopy(); - testIntrospectionSerialization(*out); - testEquals(*out); - testNonInitialized(*out); + testIntrospectionSerialization(); + testEquals(); + testNonInitialized(); - testScalar(*out); - testArray(*out); - testStructure(*out); + testScalar(); + testArray(); + testStructure(); + testStructureArray(); delete buffer; @@ -705,6 +506,6 @@ int main(int argc, char *argv[]) { delete flusher; epicsExitCallAtExits(); - return 0; + return testDone(); } diff --git a/testApp/misc/testSharedVector.cpp b/testApp/misc/testSharedVector.cpp new file mode 100644 index 0000000..0c1487d --- /dev/null +++ b/testApp/misc/testSharedVector.cpp @@ -0,0 +1,558 @@ +/** + * 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: Michael Davidsaver */ + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "pv/sharedVector.h" + +static void testEmpty() +{ + testDiag("Test empty vector"); + epics::pvData::shared_vector empty, empty2; + + testOk1(empty.size()==0); + testOk1(empty.empty()); + testOk1(empty.begin()==empty.end()); + testOk1(empty.unique()); + + testOk1(empty.data()==NULL); + + testOk1(empty==empty); + testOk1(!(empty!=empty)); + testOk1(empty==empty2); + testOk1(!(empty!=empty2)); +} + +static void testInternalAlloc() +{ + testDiag("Test vector alloc w/ new[]"); + + epics::pvData::shared_vector internal(5); + + testOk1(internal.size()==5); + testOk1(!internal.empty()); + testOk1(internal.unique()); + testOk1(internal.data()!=NULL); + + testOk1(internal.begin()+5==internal.end()); + testOk1(internal.begin()==internal.end()-5); + testOk1(internal.begin()+2==internal.end()-3); + testOk1(internal.end()-internal.begin()==5); + + internal[2] = 42; + testOk1(internal[2]==42); + + epics::pvData::shared_vector internal2(15, 500); + + testOk1(internal2.size()==15); + testOk1(internal2[1]==500); + + internal.swap(internal2); + + testOk1(internal2.size()==5); + testOk1(internal.size()==15); + + internal.clear(); + + testOk1(internal.size()==0); + testOk1(internal.empty()); + testOk1(internal.unique()); + testOk1(internal.data()==NULL); +} + +namespace { + //Note: STL shared_ptr requires that deletors be copy constructable + template + struct callCounter { + std::tr1::shared_ptr count; + callCounter():count(new int){*count=0;} + callCounter(const callCounter& o):count(o.count) {}; + callCounter& operator=(const callCounter& o){count=o.count;} + void operator()(E){*count=1;} + }; +} + +static void testExternalAlloc() +{ + testDiag("Test vector external alloc"); + + // Simulate a failed malloc() or similar + int *oops=0; + epics::pvData::shared_vector nullPtr(oops, 42, 100); + + testOk1(nullPtr.size()==0); + testOk1(nullPtr.empty()); + testOk1(nullPtr.begin()==nullPtr.end()); + testOk1(nullPtr.unique()); + + testOk1(nullPtr.data()==NULL); + + int *raw=new int[5]; + epics::pvData::shared_vector newData(raw, 1, 4); + + testOk1(newData.size()==4); + testOk1(!newData.empty()); + + // check that offset is used + raw[1]=14; + testOk1(newData[0]==14); + + // Check use of custom deleter + int localVar[4] = {1,2,3,4}; + callCounter tracker; + testOk1(*tracker.count==0); + + epics::pvData::shared_vector locvar(localVar, + tracker, + 0, 4); + + testOk1(locvar[1]==2); + testOk1(*tracker.count==0); + + newData.swap(locvar); + + testOk1(*tracker.count==0); + + newData.clear(); + + testOk1(*tracker.count==1); +} + +static void testShare() +{ + testDiag("Test vector Sharing"); + + epics::pvData::shared_vector one, two(15); + epics::pvData::shared_vector three(two); + + testOk1(one.unique()); + testOk1(!two.unique()); + testOk1(!three.unique()); + + testOk1(two.data() == three.data()); + + one = two; + + testOk1(!one.unique()); + + testOk1(two.data() == one.data()); + + one = one; // no-op + + testOk1(two.data() == one.data()); + + one[1] = 43; + testOk1(two[1]==43); + testOk1(three[1]==43); + + one.make_unique(); + + testOk1(one[1]==43); + one[1] = 143; + testOk1(two[1]==43); + testOk1(three[1]==43); + + two.resize(two.size()); + + testOk1(two[1]==43); + two[1] = 243; + testOk1(one[1]==143); + testOk1(three[1]==43); + + testOk1(one.unique()); + testOk1(two.unique()); + testOk1(three.unique()); + + one.resize(2); + + testOk1(one.size()==2); + testOk1(one[1]==143); + testOk1(two.size()==15); + testOk1(three.size()==15); + + two.resize(20, 5000); + + testOk1(two[1]==243); + testOk1(one.size()==2); + testOk1(two.size()==20); + testOk1(three.size()==15); + + testOk1(two[19]==5000); +} + +static void testConst() +{ + testDiag("Test constant vector"); + + epics::pvData::shared_vector writable(15, 100); + + epics::pvData::shared_vector::reference wr = writable[0]; + epics::pvData::shared_vector::const_reference ror = writable[0]; + + testOk1(wr==ror); + + int *compare = writable.data(); + + testOk1(writable.unique()); + + // can re-target container, but data is R/O + epics::pvData::shared_vector rodata(freeze(writable)); + + epics::pvData::shared_vector::reference wcr = rodata[0]; + epics::pvData::shared_vector::const_reference rocr = rodata[0]; + + testOk1(wcr==rocr); + + testOk1(rodata.data()==compare); + writable = thaw(rodata); + + testOk1(writable.data()==compare); + + rodata = freeze(writable); + + testOk1(rodata.data()==compare); + + epics::pvData::shared_vector rodata2(rodata); + + testOk1(rodata.data()==rodata2.data()); + + rodata2.make_unique(); + + testOk1(rodata.data()!=rodata2.data()); +} + +static void testSlice() +{ + testDiag("Test vector slicing"); + + epics::pvData::shared_vector original(10, 100); + + epics::pvData::shared_vector half1(original), half2(original), half2a(original); + + half1.slice(0, 5); + half2.slice(5, 5); + half2a.slice(5); + + testOk1(half1.dataOffset()==0); + testOk1(half2.dataOffset()==5); + testOk1(half2a.dataOffset()==5); + + testOk1(half1.size()==5); + testOk1(half2.size()==5); + testOk1(half2a.size()==5); + + testOk1(half1.dataTotal()==10); + testOk1(half2.dataTotal()==5); + testOk1(half2a.dataTotal()==5); + + testOk1(original.data() == half1.data()); + testOk1(half2.data() == half2a.data()); + + half1.slice(100000); + half2.slice(1); + half2a.slice(1,1); + + testOk1(half1.dataOffset()==5); + testOk1(half2.dataOffset()==6); + testOk1(half2a.dataOffset()==6); + + testOk1(half1.size()==0); + testOk1(half2.size()==4); + testOk1(half2a.size()==1); + + testOk1(half1.dataTotal()==5); + testOk1(half2.dataTotal()==4); + testOk1(half2a.dataTotal()==4); + + half2.clear(); + testOk1(half2.dataOffset()==0); + testOk1(half2.dataCount()==0); + testOk1(half2.dataTotal()==0); + testOk1(half2.data()==NULL); +} + +static void testCapacity() +{ + testDiag("Test vector capacity"); + + epics::pvData::shared_vector vect(10, 100); + + int *peek = vect.dataPtr().get(); + + vect.slice(0, 5); + + testOk1(vect.size()==5); + testOk1(vect.dataTotal()==10); + testOk1(vect.dataPtr().get() == peek); + + vect.resize(6); + + testOk1(vect.dataPtr().get() == peek); + testOk1(vect.size()==6); + testOk1(vect.dataTotal()==10); + + vect.resize(10); + + testOk1(vect.dataPtr().get() == peek); + testOk1(vect.size()==10); + testOk1(vect.dataTotal()==10); + + vect.resize(11); + + testOk1(vect.dataPtr().get() != peek); + testOk1(vect.size()==11); + testOk1(vect.dataTotal()>=11); + + vect[1] = 124; + + vect.reserve(15); + + testOk1(vect.size()==11); + testOk1(vect.dataTotal()>=15); + + testOk1(vect[1]==124); +} + +static void testPush() +{ + epics::pvData::shared_vector vect; + + testDiag("Test push_back optimizations"); + + size_t nallocs = 0; + size_t cap = vect.capacity(); + + for(size_t s=0; s<16*1024; s++) { + vect.push_back(s); + + if(cap!=vect.capacity()) { + nallocs++; + cap = vect.capacity(); + } + } + + testDiag("push_back %ld times caused %ld re-allocations", + (unsigned long)vect.size(), + (unsigned long)nallocs); + + testOk1(nallocs==26); +} + +static void testVoid() +{ + testDiag("Test vecter cast to/from void"); + + epics::pvData::shared_vector typed(4); + + epics::pvData::shared_vector untyped2(epics::pvData::static_shared_vector_cast(typed)); + + testOk1(typed.dataPtr().get()==untyped2.dataPtr().get()); + testOk1(typed.size()*sizeof(int)==untyped2.size()); + + untyped2.slice(sizeof(int), 2*sizeof(int)); + + typed = epics::pvData::static_shared_vector_cast(untyped2); + + testOk1(typed.dataOffset()==1); + testOk1(typed.size()==2); +} + +struct dummyStruct {}; + +static void testNonPOD() +{ + testDiag("Test vector of non-POD types"); + + epics::pvData::shared_vector strings(6); + epics::pvData::shared_vector > structs(5); + + testOk1(strings[0].empty()); + testOk1(structs[0].get()==NULL); + + structs[1].reset(new dummyStruct); + dummyStruct *temp = structs[1].get(); + + epics::pvData::shared_vector > structs2(structs); + + testOk1(!structs.unique()); + testOk1(structs[1].unique()); + + testOk1(structs2[1].get()==temp); + + structs2.make_unique(); + + testOk1(structs.unique()); + testOk1(!structs[1].unique()); + + testOk1(structs2[1].get()==temp); +} + +static void testVectorConvert() +{ + testDiag("Test shared_vector_convert"); + + epics::pvData::shared_vector ints(6, 42), moreints; + epics::pvData::shared_vector floats; + epics::pvData::shared_vector strings; + epics::pvData::shared_vector voids; + + testOk1(ints.unique()); + + // no-op convert. Just returns another reference + moreints = epics::pvData::shared_vector_convert(ints); + + testOk1(!ints.unique()); + moreints.clear(); + + // conversion when both types are known. + // returns a new vector + floats = epics::pvData::shared_vector_convert(ints); + + testOk1(ints.unique()); + testOk1(floats.size()==ints.size()); + testOk1(floats.at(0)==42.0); + + // convert to void is static_shared_vector_cast() + // returns a reference + voids = epics::pvData::shared_vector_convert(ints); + + testOk1(!ints.unique()); + testOk1(voids.size()==ints.size()*sizeof(int)); + + // convert from void uses shared_vector::original_type() + // to find that the actual type is 'int'. + // returns a new vector + strings = epics::pvData::shared_vector_convert(voids); + + voids.clear(); + + testOk1(ints.unique()); + testOk1(strings.size()==ints.size()); + testOk1(strings.at(0)=="42"); +} + +static void testWeak() +{ + testDiag("Test weak_ptr counting"); + + epics::pvData::shared_vector data(6); + + testOk1(data.unique()); + + std::tr1::shared_ptr pdata(data.dataPtr()); + + testOk1(!data.unique()); + + pdata.reset(); + + testOk1(data.unique()); + + std::tr1::weak_ptr wdata(data.dataPtr()); + + testOk1(data.unique()); // True, but I wish it wasn't!!! + + pdata = wdata.lock(); + + testOk1(!data.unique()); +} + +static void testICE() +{ + testDiag("Test freeze and thaw"); + + epics::pvData::shared_vector A(6, 42), C; + epics::pvData::shared_vector B, D; + + int *check = A.data(); + + // check freeze w/ unique reference + + // clears A and moves reference to B + // no copy + B = epics::pvData::freeze(A); + + testOk1(A.unique()); + testOk1(B.unique()); + testOk1(A.size()==0); + testOk1(B.size()==6); + testOk1(A.data()!=check); + testOk1(B.data()==check); + + D = B; // create second const reference + + // clears D, but reference to B refrence + // to B remains, so a copy is made + C = epics::pvData::thaw(D); + + testOk1(B.unique()); + testOk1(C.unique()); + testOk1(B.size()==6); + testOk1(C.size()==6); + testOk1(B.data()==check); + testOk1(C.data()!=NULL); + testOk1(C.at(0)==42); + + C.clear(); + + // clears B and moves reference to A + // no copy + A = epics::pvData::thaw(B); + + testOk1(A.unique()); + testOk1(B.unique()); + testOk1(A.size()==6); + testOk1(B.size()==0); + testOk1(A.data()==check); + testOk1(B.data()!=check); + + C = A; // create second non-const reference + + testOk1(!A.unique()); + + try { + // would clear A, but remaining reference C + // fails operation. A not cleared + // and exception thrown + B = epics::pvData::freeze(A); + testFail("Froze non-unique vector!"); + } catch(std::runtime_error& e) { + testPass("freeze of non-unique throws runtime_error as expected"); + } +} + +MAIN(testSharedVector) +{ + testPlan(162); + testDiag("Tests for shared_vector"); + + testDiag("sizeof(shared_vector)=%lu", + (unsigned long)sizeof(epics::pvData::shared_vector)); + + testEmpty(); + testInternalAlloc(); + testExternalAlloc(); + testCapacity(); + testShare(); + testConst(); + testSlice(); + testPush(); + testVoid(); + testNonPOD(); + testVectorConvert(); + testWeak(); + testICE(); + return testDone(); +} diff --git a/testApp/misc/testTypeCast.cpp b/testApp/misc/testTypeCast.cpp new file mode 100644 index 0000000..dc74d60 --- /dev/null +++ b/testApp/misc/testTypeCast.cpp @@ -0,0 +1,407 @@ +/** + * 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: Michael Davidsaver */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "pv/typeCast.h" + +using epics::pvData::String; + +namespace { + + template + struct testequal { + static bool op(T A, T B) {return A==B; } + }; + template<> + struct testequal { + static bool op(double A, double B) {return fabs(A-B)<1e-300; } + }; + template<> + struct testequal { + static bool op(float A, float B) {return fabs(A-B)<1e-30; } + }; + + template + struct testcase { + static void op(TO expect, FROM inp) + { + std::ostringstream msg; + TO actual; + try { + actual = ::epics::pvData::castUnsafe(inp); + //actual = ::epics::pvData::detail::cast_helper::op(inp); + } catch(std::runtime_error& e) { + msg<<"Failed to cast " + < " + <::op(actual, expect)) { + msg<<"Failed cast gives unexpected value " + < " + < " + < + struct testfail { + static void op(FROM inp) + { + std::ostringstream msg; + TO actual; + try { + actual = ::epics::pvData::castUnsafe(inp); + msg<<"Failed to generate expected error " + < (" + < (" + <::op(VTO, VFRO) + +// Test cast and reverse +#define TEST2(TTO, VTO, TFRO, VFRO) TEST(TTO, VTO, TFRO, VFRO); TEST(TFRO, VFRO, TTO, VTO) + +#define FAIL(TTO, TFRO, VFRO) testfail::op(VFRO) + +} // end namespace + + +MAIN(testTypeCast) +{ + testPlan(110); + +try { + + int8_t xint8=0; + uint8_t xuint8=0; + int16_t xint16=0; + uint16_t xuint16=0; + int32_t xint32=0; + uint32_t xuint32=0; + int64_t xint64=0; + uint64_t xuint64=0; + float xfloat=0.0; + double xdouble=0.0; + epics::pvData::String xString("0"); + + typedef float float_t; + typedef double double_t; + typedef epics::pvData::String String_t; + + // force all possibilities to be compiled +#define CHECK(M, N) x## M = ::epics::pvData::castUnsafe(x## N); \ + std::transform(&x ## N, &x ## N+1, &x ## M, ::epics::pvData::castUnsafe) +//#define CHECK(M, N) x## M = ::epics::pvData::detail::cast_helper::op(x## N) + CHECK(int8, int8); + CHECK(int8, uint8); + CHECK(int8, int16); + CHECK(int8, uint16); + CHECK(int8, int32); + CHECK(int8, uint32); + CHECK(int8, int64); + CHECK(int8, uint64); + CHECK(int8, float); + CHECK(int8, double); + CHECK(int8, String); + + CHECK(uint8, int8); + CHECK(uint8, uint8); + CHECK(uint8, int16); + CHECK(uint8, uint16); + CHECK(uint8, int32); + CHECK(uint8, uint32); + CHECK(uint8, int64); + CHECK(uint8, uint64); + CHECK(uint8, float); + CHECK(uint8, double); + CHECK(uint8, String); + + CHECK(int16, int8); + CHECK(int16, uint8); + CHECK(int16, int16); + CHECK(int16, uint16); + CHECK(int16, int32); + CHECK(int16, uint32); + CHECK(int16, int64); + CHECK(int16, uint64); + CHECK(int16, float); + CHECK(int16, double); + CHECK(int16, String); + + CHECK(uint16, int8); + CHECK(uint16, uint8); + CHECK(uint16, int16); + CHECK(uint16, uint16); + CHECK(uint16, int32); + CHECK(uint16, uint32); + CHECK(uint16, int64); + CHECK(uint16, uint64); + CHECK(uint16, float); + CHECK(uint16, double); + CHECK(uint16, String); + + CHECK(int32, int8); + CHECK(int32, uint8); + CHECK(int32, int16); + CHECK(int32, uint16); + CHECK(int32, int32); + CHECK(int32, uint32); + CHECK(int32, int64); + CHECK(int32, uint64); + CHECK(int32, float); + CHECK(int32, double); + CHECK(int32, String); + + CHECK(uint32, int8); + CHECK(uint32, uint8); + CHECK(uint32, int16); + CHECK(uint32, uint16); + CHECK(uint32, int32); + CHECK(uint32, uint32); + CHECK(uint32, int64); + CHECK(uint32, uint64); + CHECK(uint32, float); + CHECK(uint32, double); + CHECK(uint32, String); + + CHECK(int64, int8); + CHECK(int64, uint8); + CHECK(int64, int16); + CHECK(int64, uint16); + CHECK(int64, int32); + CHECK(int64, uint32); + CHECK(int64, int64); + CHECK(int64, uint64); + CHECK(int64, float); + CHECK(int64, double); + //CHECK(int64, String); + + CHECK(uint64, int8); + CHECK(uint64, uint8); + CHECK(uint64, int16); + CHECK(uint64, uint16); + CHECK(uint64, int32); + CHECK(uint64, uint32); + CHECK(uint64, int64); + CHECK(uint64, uint64); + CHECK(uint64, float); + CHECK(uint64, double); + //CHECK(uint64, String); + + CHECK(float, int8); + CHECK(float, uint8); + CHECK(float, int16); + CHECK(float, uint16); + CHECK(float, int32); + CHECK(float, uint32); + CHECK(float, int64); + CHECK(float, uint64); + CHECK(float, float); + CHECK(float, double); + CHECK(float, String); + + CHECK(double, int8); + CHECK(double, uint8); + CHECK(double, int16); + CHECK(double, uint16); + CHECK(double, int32); + CHECK(double, uint32); + CHECK(double, int64); + CHECK(double, uint64); + CHECK(double, float); + CHECK(double, double); + CHECK(double, String); + + CHECK(String, int8); + CHECK(String, uint8); + CHECK(String, int16); + CHECK(String, uint16); + CHECK(String, int32); + CHECK(String, uint32); + CHECK(String, int64); + CHECK(String, uint64); + CHECK(String, float); + CHECK(String, double); + CHECK(String, String); +#undef CHECK + + testDiag("Integer signed <=> unsigned"); + + TEST2(uint8_t, std::numeric_limits::max(), int8_t, -1); + TEST2(uint16_t, std::numeric_limits::max(), int8_t, -1); + TEST2(uint32_t, std::numeric_limits::max(), int8_t, -1); + TEST2(uint64_t, std::numeric_limits::max(), int8_t, -1); + + testDiag("Integer unsigned promote (and demote when in range)"); + + TEST2(uint16_t, 0xff, uint8_t, 0xff); + TEST2(uint32_t, 0xffff, uint16_t, 0xffff); + TEST2(uint64_t, 0xffffffffu, uint32_t, 0xffffffffu); + + TEST2(int16_t, 0x7f, int8_t, 0x7f); + TEST2(int32_t, 0x7fff, int16_t, 0x7fff); + TEST2(int64_t, 0x7fffffff, int32_t, 0x7fffffff); + + testDiag("Double to int w/ round towards zero (aka truncation)"); + + TEST(int32_t, 2, double, 2.1); + TEST(int32_t, 2, double, 2.5); + TEST(int32_t, 2, double, 2.7); + TEST(int32_t, -2, double, -2.1); + TEST(int32_t, -2, double, -2.5); + TEST(int32_t, -2, double, -2.7); + + testDiag("Float to int w/ round towards zero (aka truncation)"); + + TEST(int32_t, 2, float, 2.1); + TEST(int32_t, 2, float, 2.5); + TEST(int32_t, 2, float, 2.7); + TEST(int32_t, -2, float, -2.1); + TEST(int32_t, -2, float, -2.5); + TEST(int32_t, -2, float, -2.7); + + testDiag("String Printing/parsing"); + + TEST2(String, "1", int32_t, 1); + TEST2(String, "-1", int32_t, -1); + TEST2(String, "1", int8_t, 1); + TEST2(String, "-1", int8_t, -1); + TEST2(String, "1", uint8_t, 1); + TEST2(String, "-1", char, -1); + + TEST2(String, "127", int32_t, std::numeric_limits::max()); + TEST2(String, "-128", int32_t, std::numeric_limits::min()); + TEST2(String, "255", int32_t, std::numeric_limits::max()); + + TEST2(String, "32767", int32_t, std::numeric_limits::max()); + TEST2(String, "-32768", int32_t, std::numeric_limits::min()); + TEST2(String, "65535", int32_t, std::numeric_limits::max()); + + TEST2(String, "2147483647", int32_t, std::numeric_limits::max()); + TEST2(String, "-2147483648", int32_t, std::numeric_limits::min()); + TEST2(String, "4294967295", uint32_t, std::numeric_limits::max()); + + TEST2(String, "9223372036854775807", int64_t, std::numeric_limits::max()); + TEST2(String, "-9223372036854775808", int64_t, std::numeric_limits::min()); + TEST2(String, "18446744073709551615", uint64_t, std::numeric_limits::max()); + + TEST2(String, "1.1", double, 1.1); + TEST2(String, "1.1e+100", double, 1.1e100); + TEST2(String, "1.1e-100", double, 1.1e-100); + + TEST(double, 1.1e100, String, "1.1E+100"); + + testDiag("String Parsing"); + + TEST(int32_t, 15, String, "0xf"); + TEST(int32_t, 15, String, "0xF"); + TEST(int32_t, -15, String, "-0xF"); + TEST(int32_t, 16, String, "0x10"); + TEST(int32_t, -16, String, "-0x10"); + + TEST(int32_t, 7, String, "07"); + TEST(int32_t, 8, String, "010"); + TEST(int32_t, -7, String, "-07"); + TEST(int32_t, -8, String, "-010"); + + TEST(int64_t, 15, String, "0xf"); + TEST(int64_t, 15, String, "0xF"); + TEST(int64_t, -15, String, "-0xF"); + TEST(int64_t, 16, String, "0x10"); + TEST(int64_t, -16, String, "-0x10"); + + TEST(int64_t, 7, String, "07"); + TEST(int64_t, 8, String, "010"); + TEST(int64_t, -7, String, "-07"); + TEST(int64_t, -8, String, "-010"); + + testDiag("String parsing errors"); + + FAIL(int32_t, String, "hello!"); + FAIL(int32_t, String, "42 is the answer"); + FAIL(int64_t, String, "hello!"); + FAIL(int64_t, String, "42 is the answer"); + FAIL(double, String, "hello!"); + FAIL(double, String, "42 is the answer"); + + FAIL(int8_t, String, "1000"); + FAIL(int8_t, String, "-1000"); +; + FAIL(double, String, "1e+10000000"); + + testDiag("Floating point overflows"); + + TEST(float, FLT_MAX, double, 1e300); + TEST(float, -FLT_MAX, double, -1e300); + TEST(float, FLT_MIN, double, 1e-300); + TEST(float, -FLT_MIN, double, -1e-300); + + xfloat = ::epics::pvData::castUnsafe(epicsNAN); + testOk(isnan( xfloat ), "Test cast double NAN to float NAN yields: %f", xfloat); + + { + std::string result[3]; + const int32_t in[3] = { 1234, 506001, 42424242 }; + + testDiag("Test vcast int32 -> String"); + epics::pvData::castUnsafeV(3, epics::pvData::pvString, (void*)result, + epics::pvData::pvInt, (void*)in); + testDiag("Yields %s %s %s", result[0].c_str(), result[1].c_str(), result[2].c_str()); + + testOk1(result[0]=="1234"); + testOk1(result[1]=="506001"); + testOk1(result[2]=="42424242"); + } + +} catch(std::exception& e) { + testAbort("Uncaught exception: %s", e.what()); +} + + return testDone(); +} diff --git a/testApp/property/testProperty.cpp b/testApp/property/testProperty.cpp index 923276c..4d1dc59 100644 --- a/testApp/property/testProperty.cpp +++ b/testApp/property/testProperty.cpp @@ -229,11 +229,11 @@ static void testEnumerated(FILE * fd,FILE */*auxfd*/) assert(result); int32 index = pvEnumerated.getIndex(); String choice = pvEnumerated.getChoice(); - StringArrayPtr const & choices = pvEnumerated.getChoices(); + PVStringArray::const_svector choices = pvEnumerated.getChoices(); int32 numChoices = pvEnumerated.getNumberChoices(); if(debug) { fprintf(fd,"index %d choice %s choices",index,choice.c_str()); - for(int i=0; i #include +#include +#include #include #include @@ -23,750 +25,42 @@ #include using namespace epics::pvData; -using std::tr1::static_pointer_cast; -static bool debug = false; - -static FieldCreatePtr fieldCreate; -static PVDataCreatePtr pvDataCreate; -static StandardFieldPtr standardField; -static StandardPVFieldPtr standardPVField; -static ConvertPtr convert; -static String builder(""); - -static void testConvertScalar(FILE *fd) { - PVScalarPtr pvBytePtr = pvDataCreate->createPVScalar(pvByte); - PVScalarPtr pvUBytePtr = pvDataCreate->createPVScalar(pvUByte); - PVScalarPtr pvShortPtr = pvDataCreate->createPVScalar(pvShort); - PVScalarPtr pvUShortPtr = pvDataCreate->createPVScalar(pvUShort); - PVScalarPtr pvIntPtr = pvDataCreate->createPVScalar(pvInt); - PVScalarPtr pvUIntPtr = pvDataCreate->createPVScalar(pvUInt); - PVScalarPtr pvLongPtr = pvDataCreate->createPVScalar(pvLong); - PVScalarPtr pvULongPtr = pvDataCreate->createPVScalar(pvULong); - PVScalarPtr pvFloatPtr = pvDataCreate->createPVScalar(pvFloat); - PVScalarPtr pvDoublePtr = pvDataCreate->createPVScalar(pvDouble); - - fprintf(fd,"testConvertScalar\n"); - if(debug) fprintf(fd,"\nfromByte\n"); - int8 bval = 127; - for(int i=0; i<3; i++) { - convert->fromByte(pvBytePtr, bval); - builder.clear(); pvBytePtr->toString(&builder); - if(debug) fprintf(fd,"byte %s\n",builder.c_str()); - convert->fromByte(pvUBytePtr, bval); - builder.clear(); pvUBytePtr->toString(&builder); - if(debug) fprintf(fd,"ubyte %s\n",builder.c_str()); - convert->fromByte(pvShortPtr, bval); - builder.clear(); pvShortPtr->toString(&builder); - if(debug) fprintf(fd,"short %s\n",builder.c_str()); - convert->fromByte(pvUShortPtr, bval); - builder.clear(); pvUShortPtr->toString(&builder); - if(debug) fprintf(fd,"ushort %s\n",builder.c_str()); - convert->fromByte(pvIntPtr, bval); - builder.clear(); pvIntPtr->toString(&builder); - if(debug) fprintf(fd,"int %s\n",builder.c_str()); - convert->fromByte(pvUIntPtr, bval); - builder.clear(); pvUIntPtr->toString(&builder); - if(debug) fprintf(fd,"uint %s\n",builder.c_str()); - convert->fromByte(pvLongPtr, bval); - builder.clear(); pvLongPtr->toString(&builder); - if(debug) fprintf(fd,"long %s\n",builder.c_str()); - convert->fromByte(pvULongPtr, bval); - builder.clear(); pvULongPtr->toString(&builder); - if(debug) fprintf(fd,"ulong %s\n",builder.c_str()); - convert->fromByte(pvFloatPtr, bval); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float %s\n",builder.c_str()); - convert->fromByte(pvDoublePtr, bval); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double %s\n",builder.c_str()); - convert->copyScalar(pvUBytePtr, pvFloatPtr); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - convert->copyScalar(pvUBytePtr, pvDoublePtr); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); - bval++; - } - fprintf(fd,"fromByte PASSED\n"); - - if(debug) fprintf(fd,"\nfromShort\n"); - int16 sval = 0x7fff; - for(int i=0; i<3; i++) { - convert->fromShort(pvBytePtr, sval); - builder.clear(); pvBytePtr->toString(&builder); - if(debug) fprintf(fd,"byte %s\n",builder.c_str()); - convert->fromShort(pvUBytePtr, sval); - builder.clear(); pvUBytePtr->toString(&builder); - if(debug) fprintf(fd,"ubyte %s\n",builder.c_str()); - convert->fromShort(pvShortPtr, sval); - builder.clear(); pvShortPtr->toString(&builder); - if(debug) fprintf(fd,"short %s\n",builder.c_str()); - convert->fromShort(pvUShortPtr, sval); - builder.clear(); pvUShortPtr->toString(&builder); - if(debug) fprintf(fd,"ushort %s\n",builder.c_str()); - convert->fromShort(pvIntPtr, sval); - builder.clear(); pvIntPtr->toString(&builder); - if(debug) fprintf(fd,"int %s\n",builder.c_str()); - convert->fromShort(pvUIntPtr, sval); - builder.clear(); pvUIntPtr->toString(&builder); - if(debug) fprintf(fd,"uint %s\n",builder.c_str()); - convert->fromShort(pvLongPtr, sval); - builder.clear(); pvLongPtr->toString(&builder); - if(debug) fprintf(fd,"long %s\n",builder.c_str()); - convert->fromShort(pvULongPtr, sval); - builder.clear(); pvULongPtr->toString(&builder); - if(debug) fprintf(fd,"ulong %s\n",builder.c_str()); - convert->fromShort(pvFloatPtr, sval); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float %s\n",builder.c_str()); - convert->fromShort(pvDoublePtr, sval); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double %s\n",builder.c_str()); - convert->copyScalar(pvUShortPtr, pvFloatPtr); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - convert->copyScalar(pvUShortPtr, pvDoublePtr); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); - sval++; - } - fprintf(fd,"fromShort PASSED\n"); - - if(debug) fprintf(fd,"\nfromInt\n"); - int32 ival = 0x7fffffff; - for(int i=0; i<3; i++) { - convert->fromInt(pvBytePtr, ival); - builder.clear(); pvBytePtr->toString(&builder); - if(debug) fprintf(fd,"byte %s\n",builder.c_str()); - convert->fromInt(pvUBytePtr, ival); - builder.clear(); pvUBytePtr->toString(&builder); - if(debug) fprintf(fd,"ubyte %s\n",builder.c_str()); - convert->fromInt(pvShortPtr, ival); - builder.clear(); pvShortPtr->toString(&builder); - if(debug) fprintf(fd,"short %s\n",builder.c_str()); - convert->fromInt(pvUShortPtr, ival); - builder.clear(); pvUShortPtr->toString(&builder); - if(debug) fprintf(fd,"ushort %s\n",builder.c_str()); - convert->fromInt(pvIntPtr, ival); - builder.clear(); pvIntPtr->toString(&builder); - if(debug) fprintf(fd,"int %s\n",builder.c_str()); - convert->fromInt(pvUIntPtr, ival); - builder.clear(); pvUIntPtr->toString(&builder); - if(debug) fprintf(fd,"uint %s\n",builder.c_str()); - convert->fromInt(pvLongPtr, ival); - builder.clear(); pvLongPtr->toString(&builder); - if(debug) fprintf(fd,"long %s\n",builder.c_str()); - convert->fromInt(pvULongPtr, ival); - builder.clear(); pvULongPtr->toString(&builder); - if(debug) fprintf(fd,"ulong %s\n",builder.c_str()); - convert->fromInt(pvFloatPtr, ival); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float %s\n",builder.c_str()); - convert->fromInt(pvDoublePtr, ival); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double %s\n",builder.c_str()); - convert->copyScalar(pvUIntPtr, pvFloatPtr); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - convert->copyScalar(pvUIntPtr, pvDoublePtr); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); - ival++; - } - fprintf(fd,"fromInt PASSED\n"); - - if(debug) fprintf(fd,"\nfromLong\n"); - int64 lval = 0x7fffffffffffffffLL; - for(int i=0; i<3; i++) { - convert->fromLong(pvBytePtr, lval); - builder.clear(); pvBytePtr->toString(&builder); - if(debug) fprintf(fd,"byte %s\n",builder.c_str()); - convert->fromLong(pvUBytePtr, lval); - builder.clear(); pvUBytePtr->toString(&builder); - if(debug) fprintf(fd,"ubyte %s\n",builder.c_str()); - convert->fromLong(pvShortPtr, lval); - builder.clear(); pvShortPtr->toString(&builder); - if(debug) fprintf(fd,"short %s\n",builder.c_str()); - convert->fromLong(pvUShortPtr, lval); - builder.clear(); pvUShortPtr->toString(&builder); - if(debug) fprintf(fd,"ushort %s\n",builder.c_str()); - convert->fromLong(pvIntPtr, lval); - builder.clear(); pvIntPtr->toString(&builder); - if(debug) fprintf(fd,"int %s\n",builder.c_str()); - convert->fromLong(pvUIntPtr, lval); - builder.clear(); pvUIntPtr->toString(&builder); - if(debug) fprintf(fd,"uint %s\n",builder.c_str()); - convert->fromLong(pvLongPtr, lval); - builder.clear(); pvLongPtr->toString(&builder); - if(debug) fprintf(fd,"long %s\n",builder.c_str()); - convert->fromLong(pvULongPtr, lval); - builder.clear(); pvULongPtr->toString(&builder); - if(debug) fprintf(fd,"ulong %s\n",builder.c_str()); - convert->fromLong(pvFloatPtr, lval); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float %s\n",builder.c_str()); - convert->fromLong(pvDoublePtr, lval); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double %s\n",builder.c_str()); - convert->copyScalar(pvULongPtr, pvFloatPtr); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - convert->copyScalar(pvULongPtr, pvDoublePtr); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); - lval++; - } - fprintf(fd,"fromLong PASSED\n"); - - if(debug) fprintf(fd,"\nfromUByte\n"); - uint8 ubval = 127; - for(int i=0; i<3; i++) { - convert->fromUByte(pvBytePtr, ubval); - builder.clear(); pvBytePtr->toString(&builder); - if(debug) fprintf(fd,"byte %s\n",builder.c_str()); - convert->fromUByte(pvUBytePtr, ubval); - builder.clear(); pvUBytePtr->toString(&builder); - if(debug) fprintf(fd,"ubyte %s\n",builder.c_str()); - convert->fromUByte(pvShortPtr, ubval); - builder.clear(); pvShortPtr->toString(&builder); - if(debug) fprintf(fd,"short %s\n",builder.c_str()); - convert->fromUByte(pvUShortPtr, ubval); - builder.clear(); pvUShortPtr->toString(&builder); - if(debug) fprintf(fd,"ushort %s\n",builder.c_str()); - convert->fromUByte(pvIntPtr, ubval); - builder.clear(); pvIntPtr->toString(&builder); - if(debug) fprintf(fd,"int %s\n",builder.c_str()); - convert->fromUByte(pvUIntPtr, ubval); - builder.clear(); pvUIntPtr->toString(&builder); - if(debug) fprintf(fd,"uint %s\n",builder.c_str()); - convert->fromUByte(pvLongPtr, ubval); - builder.clear(); pvLongPtr->toString(&builder); - if(debug) fprintf(fd,"long %s\n",builder.c_str()); - convert->fromUByte(pvULongPtr, ubval); - builder.clear(); pvULongPtr->toString(&builder); - if(debug) fprintf(fd,"ulong %s\n",builder.c_str()); - convert->fromUByte(pvFloatPtr, ubval); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float %s\n",builder.c_str()); - convert->fromUByte(pvDoublePtr, ubval); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double %s\n",builder.c_str()); - convert->copyScalar(pvUBytePtr, pvFloatPtr); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - convert->copyScalar(pvUBytePtr, pvDoublePtr); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); - ubval++; - } - fprintf(fd,"fromUByte PASSED\n"); - - if(debug) fprintf(fd,"\nfromUShort\n"); - uint16 usval = 0x7fff; - for(int i=0; i<3; i++) { - convert->fromUShort(pvBytePtr, usval); - builder.clear(); pvBytePtr->toString(&builder); - if(debug) fprintf(fd,"byte %s\n",builder.c_str()); - convert->fromUShort(pvUBytePtr, usval); - builder.clear(); pvUBytePtr->toString(&builder); - if(debug) fprintf(fd,"ubyte %s\n",builder.c_str()); - convert->fromUShort(pvShortPtr, usval); - builder.clear(); pvShortPtr->toString(&builder); - if(debug) fprintf(fd,"short %s\n",builder.c_str()); - convert->fromUShort(pvUShortPtr, usval); - builder.clear(); pvUShortPtr->toString(&builder); - if(debug) fprintf(fd,"ushort %s\n",builder.c_str()); - convert->fromUShort(pvIntPtr, usval); - builder.clear(); pvIntPtr->toString(&builder); - if(debug) fprintf(fd,"int %s\n",builder.c_str()); - convert->fromUShort(pvUIntPtr, usval); - builder.clear(); pvUIntPtr->toString(&builder); - if(debug) fprintf(fd,"uint %s\n",builder.c_str()); - convert->fromUShort(pvLongPtr, usval); - builder.clear(); pvLongPtr->toString(&builder); - if(debug) fprintf(fd,"long %s\n",builder.c_str()); - convert->fromUShort(pvULongPtr, usval); - builder.clear(); pvULongPtr->toString(&builder); - if(debug) fprintf(fd,"ulong %s\n",builder.c_str()); - convert->fromUShort(pvFloatPtr, usval); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float %s\n",builder.c_str()); - convert->fromUShort(pvDoublePtr, usval); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double %s\n",builder.c_str()); - convert->copyScalar(pvUShortPtr, pvFloatPtr); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - convert->copyScalar(pvUShortPtr, pvDoublePtr); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); - usval++; - } - fprintf(fd,"fromUShort PASSED\n"); - - if(debug) fprintf(fd,"\nfromUInt\n"); - uint32 uival = 0x7fffffff; - for(int i=0; i<3; i++) { - convert->fromUInt(pvBytePtr, uival); - builder.clear(); pvBytePtr->toString(&builder); - if(debug) fprintf(fd,"byte %s\n",builder.c_str()); - convert->fromUInt(pvUBytePtr, uival); - builder.clear(); pvUBytePtr->toString(&builder); - if(debug) fprintf(fd,"ubyte %s\n",builder.c_str()); - convert->fromUInt(pvShortPtr, uival); - builder.clear(); pvShortPtr->toString(&builder); - if(debug) fprintf(fd,"short %s\n",builder.c_str()); - convert->fromUInt(pvUShortPtr, uival); - builder.clear(); pvUShortPtr->toString(&builder); - if(debug) fprintf(fd,"ushort %s\n",builder.c_str()); - convert->fromUInt(pvIntPtr, uival); - builder.clear(); pvIntPtr->toString(&builder); - if(debug) fprintf(fd,"int %s\n",builder.c_str()); - convert->fromUInt(pvUIntPtr, uival); - builder.clear(); pvUIntPtr->toString(&builder); - if(debug) fprintf(fd,"uint %s\n",builder.c_str()); - convert->fromUInt(pvLongPtr, uival); - builder.clear(); pvLongPtr->toString(&builder); - if(debug) fprintf(fd,"long %s\n",builder.c_str()); - convert->fromUInt(pvULongPtr, uival); - builder.clear(); pvULongPtr->toString(&builder); - if(debug) fprintf(fd,"ulong %s\n",builder.c_str()); - convert->fromUInt(pvFloatPtr, uival); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float %s\n",builder.c_str()); - convert->fromUInt(pvDoublePtr, uival); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double %s\n",builder.c_str()); - convert->copyScalar(pvUIntPtr, pvFloatPtr); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - convert->copyScalar(pvUIntPtr, pvDoublePtr); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); - uival++; - } - fprintf(fd,"fromUInt PASSED\n"); - - if(debug) fprintf(fd,"\nfromULong\n"); - uint64 ulval = 0x7fffffffffffffffLL; - for(int i=0; i<3; i++) { - convert->fromULong(pvBytePtr, ulval); - builder.clear(); pvBytePtr->toString(&builder); - if(debug) fprintf(fd,"byte %s\n",builder.c_str()); - convert->fromULong(pvUBytePtr, ulval); - builder.clear(); pvUBytePtr->toString(&builder); - if(debug) fprintf(fd,"ubyte %s\n",builder.c_str()); - convert->fromULong(pvShortPtr, ulval); - builder.clear(); pvShortPtr->toString(&builder); - if(debug) fprintf(fd,"short %s\n",builder.c_str()); - convert->fromULong(pvUShortPtr, ulval); - builder.clear(); pvUShortPtr->toString(&builder); - if(debug) fprintf(fd,"ushort %s\n",builder.c_str()); - convert->fromULong(pvIntPtr, ulval); - builder.clear(); pvIntPtr->toString(&builder); - if(debug) fprintf(fd,"int %s\n",builder.c_str()); - convert->fromULong(pvUIntPtr, ulval); - builder.clear(); pvUIntPtr->toString(&builder); - if(debug) fprintf(fd,"uint %s\n",builder.c_str()); - convert->fromULong(pvLongPtr, ulval); - builder.clear(); pvLongPtr->toString(&builder); - if(debug) fprintf(fd,"long %s\n",builder.c_str()); - convert->fromULong(pvULongPtr, ulval); - builder.clear(); pvULongPtr->toString(&builder); - if(debug) fprintf(fd,"ulong %s\n",builder.c_str()); - convert->fromULong(pvFloatPtr, ulval); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float %s\n",builder.c_str()); - convert->fromULong(pvDoublePtr, ulval); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double %s\n",builder.c_str()); - convert->copyScalar(pvULongPtr, pvFloatPtr); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - convert->copyScalar(pvULongPtr, pvDoublePtr); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); - ulval++; - } - fprintf(fd,"fromULong PASSED\n"); -} - -static void testConvertScalarArray(FILE *fd) { - PVScalarArrayPtr pvBytePtr = pvDataCreate->createPVScalarArray(pvByte); - PVScalarArrayPtr pvUBytePtr = pvDataCreate->createPVScalarArray(pvUByte); - PVScalarArrayPtr pvShortPtr = pvDataCreate->createPVScalarArray(pvShort); - PVScalarArrayPtr pvUShortPtr = pvDataCreate->createPVScalarArray(pvUShort); - PVScalarArrayPtr pvIntPtr = pvDataCreate->createPVScalarArray(pvInt); - PVScalarArrayPtr pvUIntPtr = pvDataCreate->createPVScalarArray(pvUInt); - PVScalarArrayPtr pvLongPtr = pvDataCreate->createPVScalarArray(pvLong); - PVScalarArrayPtr pvULongPtr = pvDataCreate->createPVScalarArray(pvULong); - PVScalarArrayPtr pvFloatPtr = pvDataCreate->createPVScalarArray(pvFloat); - PVScalarArrayPtr pvDoublePtr = pvDataCreate->createPVScalarArray(pvDouble); - - fprintf(fd,"testConvertScalarArray\n"); - if(debug) fprintf(fd,"\nfromByte\n"); - size_t length = 4; - int8 barray[length]; - int8 bval = 127; - barray[0] = bval; - for(size_t i=1; ifromByteArray(pvBytePtr,0,length,barray,0); - builder.clear(); pvBytePtr->toString(&builder); - if(debug) fprintf(fd,"byte %s\n",builder.c_str()); - convert->fromByteArray(pvUBytePtr,0,length,barray,0); - builder.clear(); pvUBytePtr->toString(&builder); - if(debug) fprintf(fd,"ubyte %s\n",builder.c_str()); - convert->fromByteArray(pvShortPtr,0,length,barray,0); - builder.clear(); pvShortPtr->toString(&builder); - if(debug) fprintf(fd,"short %s\n",builder.c_str()); - convert->fromByteArray(pvUShortPtr,0,length,barray,0); - builder.clear(); pvUShortPtr->toString(&builder); - if(debug) fprintf(fd,"ushort %s\n",builder.c_str()); - convert->fromByteArray(pvIntPtr,0,length,barray,0); - builder.clear(); pvIntPtr->toString(&builder); - if(debug) fprintf(fd,"int %s\n",builder.c_str()); - convert->fromByteArray(pvUIntPtr,0,length,barray,0); - builder.clear(); pvUIntPtr->toString(&builder); - if(debug) fprintf(fd,"uint %s\n",builder.c_str()); - convert->fromByteArray(pvLongPtr,0,length,barray,0); - builder.clear(); pvLongPtr->toString(&builder); - if(debug) fprintf(fd,"long %s\n",builder.c_str()); - convert->fromByteArray(pvULongPtr,0,length,barray,0); - builder.clear(); pvULongPtr->toString(&builder); - if(debug) fprintf(fd,"ulong %s\n",builder.c_str()); - convert->fromByteArray(pvFloatPtr,0,length,barray,0); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float %s\n",builder.c_str()); - convert->fromByteArray(pvDoublePtr,0,length,barray,0); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double %s\n",builder.c_str()); - convert->copyScalarArray(pvUBytePtr,0, pvFloatPtr,0,length); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - convert->copyScalarArray(pvUBytePtr,0, pvDoublePtr,0,length); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); - fprintf(fd,"fromByte PASSED\n"); - - if(debug) fprintf(fd,"\nfromShort\n"); - int16 sarray[length]; - int16 sval = 0x7fff; - sarray[0] = sval; - for(size_t i=1; ifromShortArray(pvBytePtr,0,length,sarray,0); - builder.clear(); pvBytePtr->toString(&builder); - if(debug) fprintf(fd,"byte %s\n",builder.c_str()); - convert->fromShortArray(pvUBytePtr,0,length,sarray,0); - builder.clear(); pvUBytePtr->toString(&builder); - if(debug) fprintf(fd,"ubyte %s\n",builder.c_str()); - convert->fromShortArray(pvShortPtr,0,length,sarray,0); - builder.clear(); pvShortPtr->toString(&builder); - if(debug) fprintf(fd,"short %s\n",builder.c_str()); - convert->fromShortArray(pvUShortPtr,0,length,sarray,0); - builder.clear(); pvUShortPtr->toString(&builder); - if(debug) fprintf(fd,"ushort %s\n",builder.c_str()); - convert->fromShortArray(pvIntPtr,0,length,sarray,0); - builder.clear(); pvIntPtr->toString(&builder); - if(debug) fprintf(fd,"int %s\n",builder.c_str()); - convert->fromShortArray(pvUIntPtr,0,length,sarray,0); - builder.clear(); pvUIntPtr->toString(&builder); - if(debug) fprintf(fd,"uint %s\n",builder.c_str()); - convert->fromShortArray(pvLongPtr,0,length,sarray,0); - builder.clear(); pvLongPtr->toString(&builder); - if(debug) fprintf(fd,"long %s\n",builder.c_str()); - convert->fromShortArray(pvULongPtr,0,length,sarray,0); - builder.clear(); pvULongPtr->toString(&builder); - if(debug) fprintf(fd,"ulong %s\n",builder.c_str()); - convert->fromShortArray(pvFloatPtr,0,length,sarray,0); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float %s\n",builder.c_str()); - convert->fromShortArray(pvDoublePtr,0,length,sarray,0); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double %s\n",builder.c_str()); - convert->copyScalarArray(pvUShortPtr,0, pvFloatPtr,0,length); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - convert->copyScalarArray(pvUShortPtr,0, pvDoublePtr,0,length); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); - fprintf(fd,"fromShort PASSED\n"); - - if(debug) fprintf(fd,"\nfromInt\n"); - int32 iarray[length]; - int32 ival = 0x7fffffff; - iarray[0] = ival; - for(size_t i=1; ifromIntArray(pvBytePtr,0,length,iarray,0); - builder.clear(); pvBytePtr->toString(&builder); - if(debug) fprintf(fd,"byte %s\n",builder.c_str()); - convert->fromIntArray(pvUBytePtr,0,length,iarray,0); - builder.clear(); pvUBytePtr->toString(&builder); - if(debug) fprintf(fd,"ubyte %s\n",builder.c_str()); - convert->fromIntArray(pvShortPtr,0,length,iarray,0); - builder.clear(); pvShortPtr->toString(&builder); - if(debug) fprintf(fd,"short %s\n",builder.c_str()); - convert->fromIntArray(pvUShortPtr,0,length,iarray,0); - builder.clear(); pvUShortPtr->toString(&builder); - if(debug) fprintf(fd,"ushort %s\n",builder.c_str()); - convert->fromIntArray(pvIntPtr,0,length,iarray,0); - builder.clear(); pvIntPtr->toString(&builder); - if(debug) fprintf(fd,"int %s\n",builder.c_str()); - convert->fromIntArray(pvUIntPtr,0,length,iarray,0); - builder.clear(); pvUIntPtr->toString(&builder); - if(debug) fprintf(fd,"uint %s\n",builder.c_str()); - convert->fromIntArray(pvLongPtr,0,length,iarray,0); - builder.clear(); pvLongPtr->toString(&builder); - if(debug) fprintf(fd,"long %s\n",builder.c_str()); - convert->fromIntArray(pvULongPtr,0,length,iarray,0); - builder.clear(); pvULongPtr->toString(&builder); - if(debug) fprintf(fd,"ulong %s\n",builder.c_str()); - convert->fromIntArray(pvFloatPtr,0,length,iarray,0); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float %s\n",builder.c_str()); - convert->fromIntArray(pvDoublePtr,0,length,iarray,0); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double %s\n",builder.c_str()); - convert->copyScalarArray(pvUIntPtr,0, pvFloatPtr,0,length); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - convert->copyScalarArray(pvUIntPtr,0, pvDoublePtr,0,length); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); - fprintf(fd,"fromInt PASSED\n"); - - if(debug) fprintf(fd,"\nfromLong\n"); - int64 larray[length]; - int64 lval = 0x7fffffffffffffffLL; - larray[0] = lval; - for(size_t i=1; ifromLongArray(pvBytePtr,0,length,larray,0); - builder.clear(); pvBytePtr->toString(&builder); - if(debug) fprintf(fd,"byte %s\n",builder.c_str()); - convert->fromLongArray(pvUBytePtr,0,length,larray,0); - builder.clear(); pvUBytePtr->toString(&builder); - if(debug) fprintf(fd,"ubyte %s\n",builder.c_str()); - convert->fromLongArray(pvShortPtr,0,length,larray,0); - builder.clear(); pvShortPtr->toString(&builder); - if(debug) fprintf(fd,"short %s\n",builder.c_str()); - convert->fromLongArray(pvUShortPtr,0,length,larray,0); - builder.clear(); pvUShortPtr->toString(&builder); - if(debug) fprintf(fd,"ushort %s\n",builder.c_str()); - convert->fromLongArray(pvIntPtr,0,length,larray,0); - builder.clear(); pvIntPtr->toString(&builder); - if(debug) fprintf(fd,"int %s\n",builder.c_str()); - convert->fromLongArray(pvUIntPtr,0,length,larray,0); - builder.clear(); pvUIntPtr->toString(&builder); - if(debug) fprintf(fd,"uint %s\n",builder.c_str()); - convert->fromLongArray(pvLongPtr,0,length,larray,0); - builder.clear(); pvLongPtr->toString(&builder); - if(debug) fprintf(fd,"long %s\n",builder.c_str()); - convert->fromLongArray(pvULongPtr,0,length,larray,0); - builder.clear(); pvULongPtr->toString(&builder); - if(debug) fprintf(fd,"ulong %s\n",builder.c_str()); - convert->fromLongArray(pvFloatPtr,0,length,larray,0); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float %s\n",builder.c_str()); - convert->fromLongArray(pvDoublePtr,0,length,larray,0); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double %s\n",builder.c_str()); - convert->copyScalarArray(pvULongPtr,0, pvFloatPtr,0,length); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - convert->copyScalarArray(pvULongPtr,0, pvDoublePtr,0,length); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); - fprintf(fd,"fromLong PASSED\n"); - - if(debug) fprintf(fd,"\nfromUByte\n"); - uint8 ubarray[length]; - uint8 ubval = 127; - ubarray[0] = ubval; - for(size_t i=1; ifromUByteArray(pvBytePtr,0,length,ubarray,0); - builder.clear(); pvBytePtr->toString(&builder); - if(debug) fprintf(fd,"byte %s\n",builder.c_str()); - convert->fromUByteArray(pvUBytePtr,0,length,ubarray,0); - builder.clear(); pvUBytePtr->toString(&builder); - if(debug) fprintf(fd,"ubyte %s\n",builder.c_str()); - convert->fromUByteArray(pvShortPtr,0,length,ubarray,0); - builder.clear(); pvShortPtr->toString(&builder); - if(debug) fprintf(fd,"short %s\n",builder.c_str()); - convert->fromUByteArray(pvUShortPtr,0,length,ubarray,0); - builder.clear(); pvUShortPtr->toString(&builder); - if(debug) fprintf(fd,"ushort %s\n",builder.c_str()); - convert->fromUByteArray(pvIntPtr,0,length,ubarray,0); - builder.clear(); pvIntPtr->toString(&builder); - if(debug) fprintf(fd,"int %s\n",builder.c_str()); - convert->fromUByteArray(pvUIntPtr,0,length,ubarray,0); - builder.clear(); pvUIntPtr->toString(&builder); - if(debug) fprintf(fd,"uint %s\n",builder.c_str()); - convert->fromUByteArray(pvLongPtr,0,length,ubarray,0); - builder.clear(); pvLongPtr->toString(&builder); - if(debug) fprintf(fd,"long %s\n",builder.c_str()); - convert->fromUByteArray(pvULongPtr,0,length,ubarray,0); - builder.clear(); pvULongPtr->toString(&builder); - if(debug) fprintf(fd,"ulong %s\n",builder.c_str()); - convert->fromUByteArray(pvFloatPtr,0,length,ubarray,0); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float %s\n",builder.c_str()); - convert->fromUByteArray(pvDoublePtr,0,length,ubarray,0); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double %s\n",builder.c_str()); - convert->copyScalarArray(pvUBytePtr,0, pvFloatPtr,0,length); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - convert->copyScalarArray(pvUBytePtr,0, pvDoublePtr,0,length); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); - fprintf(fd,"fromUByte PASSED\n"); - - if(debug) fprintf(fd,"\nfromUShort\n"); - uint16 usarray[length]; - uint16 usval = 0x7fff; - usarray[0] = usval; - for(size_t i=1; ifromUShortArray(pvBytePtr,0,length,usarray,0); - builder.clear(); pvBytePtr->toString(&builder); - if(debug) fprintf(fd,"byte %s\n",builder.c_str()); - convert->fromUShortArray(pvUBytePtr,0,length,usarray,0); - builder.clear(); pvUBytePtr->toString(&builder); - if(debug) fprintf(fd,"ubyte %s\n",builder.c_str()); - convert->fromUShortArray(pvShortPtr,0,length,usarray,0); - builder.clear(); pvShortPtr->toString(&builder); - if(debug) fprintf(fd,"short %s\n",builder.c_str()); - convert->fromUShortArray(pvUShortPtr,0,length,usarray,0); - builder.clear(); pvUShortPtr->toString(&builder); - if(debug) fprintf(fd,"ushort %s\n",builder.c_str()); - convert->fromUShortArray(pvIntPtr,0,length,usarray,0); - builder.clear(); pvIntPtr->toString(&builder); - if(debug) fprintf(fd,"int %s\n",builder.c_str()); - convert->fromUShortArray(pvUIntPtr,0,length,usarray,0); - builder.clear(); pvUIntPtr->toString(&builder); - if(debug) fprintf(fd,"uint %s\n",builder.c_str()); - convert->fromUShortArray(pvLongPtr,0,length,usarray,0); - builder.clear(); pvLongPtr->toString(&builder); - if(debug) fprintf(fd,"long %s\n",builder.c_str()); - convert->fromUShortArray(pvULongPtr,0,length,usarray,0); - builder.clear(); pvULongPtr->toString(&builder); - if(debug) fprintf(fd,"ulong %s\n",builder.c_str()); - convert->fromUShortArray(pvFloatPtr,0,length,usarray,0); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float %s\n",builder.c_str()); - convert->fromUShortArray(pvDoublePtr,0,length,usarray,0); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double %s\n",builder.c_str()); - convert->copyScalarArray(pvUShortPtr,0, pvFloatPtr,0,length); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - convert->copyScalarArray(pvUShortPtr,0, pvDoublePtr,0,length); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); - fprintf(fd,"fromUShort PASSED\n"); - - if(debug) fprintf(fd,"\nfromUInt\n"); - uint32 uiarray[length]; - uint32 uival = 0x7fffffff; - uiarray[0] = uival; - for(size_t i=1; ifromUIntArray(pvBytePtr,0,length,uiarray,0); - builder.clear(); pvBytePtr->toString(&builder); - if(debug) fprintf(fd,"byte %s\n",builder.c_str()); - convert->fromUIntArray(pvUBytePtr,0,length,uiarray,0); - builder.clear(); pvUBytePtr->toString(&builder); - if(debug) fprintf(fd,"ubyte %s\n",builder.c_str()); - convert->fromUIntArray(pvShortPtr,0,length,uiarray,0); - builder.clear(); pvShortPtr->toString(&builder); - if(debug) fprintf(fd,"short %s\n",builder.c_str()); - convert->fromUIntArray(pvUShortPtr,0,length,uiarray,0); - builder.clear(); pvUShortPtr->toString(&builder); - if(debug) fprintf(fd,"ushort %s\n",builder.c_str()); - convert->fromUIntArray(pvIntPtr,0,length,uiarray,0); - builder.clear(); pvIntPtr->toString(&builder); - if(debug) fprintf(fd,"int %s\n",builder.c_str()); - convert->fromUIntArray(pvUIntPtr,0,length,uiarray,0); - builder.clear(); pvUIntPtr->toString(&builder); - if(debug) fprintf(fd,"uint %s\n",builder.c_str()); - convert->fromUIntArray(pvLongPtr,0,length,uiarray,0); - builder.clear(); pvLongPtr->toString(&builder); - if(debug) fprintf(fd,"long %s\n",builder.c_str()); - convert->fromUIntArray(pvULongPtr,0,length,uiarray,0); - builder.clear(); pvULongPtr->toString(&builder); - if(debug) fprintf(fd,"ulong %s\n",builder.c_str()); - convert->fromUIntArray(pvFloatPtr,0,length,uiarray,0); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float %s\n",builder.c_str()); - convert->fromUIntArray(pvDoublePtr,0,length,uiarray,0); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double %s\n",builder.c_str()); - convert->copyScalarArray(pvUIntPtr,0, pvFloatPtr,0,length); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - convert->copyScalarArray(pvUIntPtr,0, pvDoublePtr,0,length); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); - fprintf(fd,"fromUInt PASSED\n"); - - if(debug) fprintf(fd,"\nfromULong\n"); - uint64 ularray[length]; - uint64 ulval = 0x7fffffffffffffffLL; - ularray[0] = ulval; - for(size_t i=1; ifromULongArray(pvBytePtr,0,length,ularray,0); - builder.clear(); pvBytePtr->toString(&builder); - if(debug) fprintf(fd,"byte %s\n",builder.c_str()); - convert->fromULongArray(pvUBytePtr,0,length,ularray,0); - builder.clear(); pvUBytePtr->toString(&builder); - if(debug) fprintf(fd,"ubyte %s\n",builder.c_str()); - convert->fromULongArray(pvShortPtr,0,length,ularray,0); - builder.clear(); pvShortPtr->toString(&builder); - if(debug) fprintf(fd,"short %s\n",builder.c_str()); - convert->fromULongArray(pvUShortPtr,0,length,ularray,0); - builder.clear(); pvUShortPtr->toString(&builder); - if(debug) fprintf(fd,"ushort %s\n",builder.c_str()); - convert->fromULongArray(pvIntPtr,0,length,ularray,0); - builder.clear(); pvIntPtr->toString(&builder); - if(debug) fprintf(fd,"int %s\n",builder.c_str()); - convert->fromULongArray(pvUIntPtr,0,length,ularray,0); - builder.clear(); pvUIntPtr->toString(&builder); - if(debug) fprintf(fd,"uint %s\n",builder.c_str()); - convert->fromULongArray(pvLongPtr,0,length,ularray,0); - builder.clear(); pvLongPtr->toString(&builder); - if(debug) fprintf(fd,"long %s\n",builder.c_str()); - convert->fromULongArray(pvULongPtr,0,length,ularray,0); - builder.clear(); pvULongPtr->toString(&builder); - if(debug) fprintf(fd,"ulong %s\n",builder.c_str()); - convert->fromULongArray(pvFloatPtr,0,length,ularray,0); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float %s\n",builder.c_str()); - convert->fromULongArray(pvDoublePtr,0,length,ularray,0); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double %s\n",builder.c_str()); - convert->copyScalarArray(pvULongPtr,0, pvFloatPtr,0,length); - builder.clear(); pvFloatPtr->toString(&builder); - if(debug) fprintf(fd,"float from unsigned %s\n",builder.c_str()); - convert->copyScalarArray(pvULongPtr,0, pvDoublePtr,0,length); - builder.clear(); pvDoublePtr->toString(&builder); - if(debug) fprintf(fd,"double from unsigned %s\n",builder.c_str()); - fprintf(fd,"fromLong PASSED\n"); -} - -int main(int argc,char *argv[]) +static void testFromString() { - char *fileName = 0; - if(argc>1) fileName = argv[1]; - FILE * fd = stdout; - if(fileName!=0 && fileName[0]!=0) { - fd = fopen(fileName,"w+"); - } - fieldCreate = getFieldCreate(); - pvDataCreate = getPVDataCreate(); - standardField = getStandardField(); - standardPVField = getStandardPVField(); - convert = getConvert(); - testConvertScalar(fd); - testConvertScalarArray(fd); - fprintf(fd,"THIS NEEDS MANY MORE TESTS AND ASSERTS\n"); - return(0); + StringArray inp(2); + + inp[0] = "0"; + inp[1] = "1"; + + PVScalarArrayPtr A(getPVDataCreate()->createPVScalarArray(pvInt)); + PVScalarArrayPtr B(getPVDataCreate()->createPVScalarArray(pvString)); + + testOk1(2==getConvert()->fromStringArray(A, 0, inp.size(), inp, 0)); + testOk1(2==getConvert()->fromStringArray(B, 0, inp.size(), inp, 0)); + + PVIntArrayPtr Ax(std::tr1::static_pointer_cast(A)); + PVStringArrayPtr Bx(std::tr1::static_pointer_cast(B)); + + PVIntArray::const_svector Adata(Ax->view()); + PVStringArray::const_svector Bdata(Bx->view()); + + testOk1(inp.size()==Adata.size()); + if(inp.size()==Adata.size()) + testOk1(Adata[0]==0 && Adata[1]==1); + else + testFail("Can't compare"); + + testOk1(inp.size()==Bdata.size()); + if(inp.size()==Bdata.size()) + testOk1(Bdata[0]=="0" && Bdata[1]=="1"); + else + testFail("Can't compare"); } +MAIN(testConvert) +{ + testPlan(0); + testFromString(); + return testDone(); +} diff --git a/testApp/pv/testIntrospect.cpp b/testApp/pv/testIntrospect.cpp index 3577f2b..f9531f1 100644 --- a/testApp/pv/testIntrospect.cpp +++ b/testApp/pv/testIntrospect.cpp @@ -12,8 +12,8 @@ #include #include -#include -#include +#include +#include #include #include @@ -23,130 +23,190 @@ using namespace epics::pvData; -static bool debug = false; - static FieldCreatePtr fieldCreate; static PVDataCreatePtr pvDataCreate; static StandardFieldPtr standardField; -static String builder(""); -static void testScalarCommon(FILE * fd,ScalarType stype, +static void testScalarCommon(ScalarType stype, bool isInteger,bool isNumeric,bool isPrimitive) { + String builder; ScalarConstPtr pscalar = fieldCreate->createScalar(stype); Type type = pscalar->getType(); - assert(type==scalar); + testOk1(type==scalar); builder.clear(); TypeFunc::toString(&builder,type); - assert(builder.compare("scalar")==0); + testOk1(builder.compare("scalar")==0); ScalarType scalarType = pscalar->getScalarType(); - assert(scalarType==stype); - assert(ScalarTypeFunc::isInteger(scalarType)==isInteger); - assert(ScalarTypeFunc::isNumeric(scalarType)==isNumeric); - assert(ScalarTypeFunc::isPrimitive(scalarType)==isPrimitive); - builder.clear(); - pscalar->toString(&builder); - if(debug) fprintf(fd,"%s\n",builder.c_str()); + testOk1(scalarType==stype); + testOk1(ScalarTypeFunc::isInteger(scalarType)==isInteger); + testOk1(ScalarTypeFunc::isNumeric(scalarType)==isNumeric); + testOk1(ScalarTypeFunc::isPrimitive(scalarType)==isPrimitive); } -static void testScalar(FILE * fd) { - if(debug) fprintf(fd,"\ntestScalar\n"); - testScalarCommon(fd,pvBoolean,false,false,true); - testScalarCommon(fd,pvByte,true,true,true); - testScalarCommon(fd,pvShort,true,true,true); - testScalarCommon(fd,pvInt,true,true,true); - testScalarCommon(fd,pvLong,true,true,true); - testScalarCommon(fd,pvFloat,false,true,true); - testScalarCommon(fd,pvDouble,false,true,true); - testScalarCommon(fd,pvString,false,false,false); - fprintf(fd,"testScalar PASSED\n"); +static void testScalar() { + testDiag("testScalar"); + testScalarCommon(pvBoolean,false,false,true); + testScalarCommon(pvByte,true,true,true); + testScalarCommon(pvShort,true,true,true); + testScalarCommon(pvInt,true,true,true); + testScalarCommon(pvLong,true,true,true); + testScalarCommon(pvFloat,false,true,true); + testScalarCommon(pvDouble,false,true,true); + testScalarCommon(pvString,false,false,false); } -static void testScalarArrayCommon(FILE * fd,ScalarType stype, +static void testScalarArrayCommon(ScalarType stype, bool isInteger,bool isNumeric,bool isPrimitive) { + String builder; ScalarArrayConstPtr pscalar = fieldCreate->createScalarArray(stype); Type type = pscalar->getType(); - assert(type==scalarArray); + testOk1(type==scalarArray); builder.clear(); TypeFunc::toString(&builder,type); - assert(builder.compare("scalarArray")==0); + testOk1(builder.compare("scalarArray")==0); ScalarType scalarType = pscalar->getElementType(); - assert(scalarType==stype); - assert(ScalarTypeFunc::isInteger(scalarType)==isInteger); - assert(ScalarTypeFunc::isNumeric(scalarType)==isNumeric); - assert(ScalarTypeFunc::isPrimitive(scalarType)==isPrimitive); - builder.clear(); - pscalar->toString(&builder); - if(debug) fprintf(fd,"%s\n",builder.c_str()); + testOk1(scalarType==stype); + testOk1(ScalarTypeFunc::isInteger(scalarType)==isInteger); + testOk1(ScalarTypeFunc::isNumeric(scalarType)==isNumeric); + testOk1(ScalarTypeFunc::isPrimitive(scalarType)==isPrimitive); } -static void testScalarArray(FILE * fd) { - if(debug) fprintf(fd,"\ntestScalarArray\n"); - testScalarArrayCommon(fd,pvBoolean,false,false,true); - testScalarArrayCommon(fd,pvByte,true,true,true); - testScalarArrayCommon(fd,pvShort,true,true,true); - testScalarArrayCommon(fd,pvInt,true,true,true); - testScalarArrayCommon(fd,pvLong,true,true,true); - testScalarArrayCommon(fd,pvFloat,false,true,true); - testScalarArrayCommon(fd,pvDouble,false,true,true); - testScalarArrayCommon(fd,pvString,false,false,false); - fprintf(fd,"testScalarArray PASSED\n"); +static void testScalarArray() { + testDiag("testScalarArray"); + testScalarArrayCommon(pvBoolean,false,false,true); + testScalarArrayCommon(pvByte,true,true,true); + testScalarArrayCommon(pvShort,true,true,true); + testScalarArrayCommon(pvInt,true,true,true); + testScalarArrayCommon(pvLong,true,true,true); + testScalarArrayCommon(pvFloat,false,true,true); + testScalarArrayCommon(pvDouble,false,true,true); + testScalarArrayCommon(pvString,false,false,false); } -static void testSimpleStructure(FILE * fd) { - if(debug) fprintf(fd,"\ntestSimpleStructure\n"); - String properties("alarm,timeStamp,display,control,valueAlarm"); - StructureConstPtr ptop = standardField->scalar(pvDouble,properties); - builder.clear(); - ptop->toString(&builder); - if(debug) fprintf(fd,"%s\n",builder.c_str()); - fprintf(fd,"testSimpleStructure PASSED\n"); -} - -static StructureConstPtr createPowerSupply() { - size_t nfields = 3; - String properties("alarm"); - StringArray names; - names.reserve(nfields); - FieldConstPtrArray powerSupply; - powerSupply.reserve(nfields); - names.push_back("voltage"); - powerSupply.push_back(standardField->scalar(pvDouble,properties)); - names.push_back("power"); - powerSupply.push_back(standardField->scalar(pvDouble,properties)); - names.push_back("current"); - powerSupply.push_back(standardField->scalar(pvDouble,properties)); - return fieldCreate->createStructure(names,powerSupply); -} - -static void testStructureArray(FILE * fd) { - if(debug) fprintf(fd,"\ntestStructureArray\n"); - String properties("alarm,timeStamp"); - StructureConstPtr powerSupply = createPowerSupply(); - StructureConstPtr top = standardField->structureArray( - powerSupply,properties); - builder.clear(); - top->toString(&builder); - if(debug) fprintf(fd,"%s\n",builder.c_str()); - fprintf(fd,"testStructureArray PASSED\n"); -} - -int main(int argc,char *argv[]) +static void testStructure() { - char *fileName = 0; - if(argc>1) fileName = argv[1]; - FILE * fd = stdout; - if(fileName!=0 && fileName[0]!=0) { - fd = fopen(fileName,"w+"); - } + testDiag("testStructure"); + StringArray names1(2); + names1[0] = "innerA"; + names1[1] = "innerB"; + FieldConstPtrArray fields1(2); + fields1[0] = fieldCreate->createScalar(pvDouble); + fields1[1] = fieldCreate->createScalarArray(pvString); + + StructureConstPtr struct1 = fieldCreate->createStructure(names1, fields1); + + testOk1(struct1->getNumberFields()==2); + testOk1(struct1->getField("innerA")==fields1[0]); + testOk1(struct1->getField("innerB")==fields1[1]); + testOk1(struct1->getFieldIndex("innerA")==0); + testOk1(struct1->getFieldIndex("innerB")==1); + testOk1(struct1->getField(0)==fields1[0]); + testOk1(struct1->getField(1)==fields1[1]); + testOk1(struct1->getFieldName(0)==names1[0]); + testOk1(struct1->getFieldName(1)==names1[1]); + + testOk1(struct1->getID() == Structure::DEFAULT_ID); + + testOk1(fields1 == struct1->getFields()); // vector equality + + StringArray names2(2); + names2[0] = "outerA"; + names2[1] = "outerB"; + FieldConstPtrArray fields2(2); + fields2[0] = fieldCreate->createScalar(pvInt); + fields2[1] = std::tr1::static_pointer_cast(struct1); + + StructureConstPtr struct2 = fieldCreate->createStructure(names2, fields2); + + testOk1(struct2->getNumberFields()==2); // not recursive + testOk1(struct2->getField(1)==fields2[1]); + + StructureArrayConstPtr struct1arr = fieldCreate->createStructureArray(struct1); + + testOk1(struct1arr->getStructure()==struct1); + testOk1(struct1arr->getID()=="structure[]"); +} + +#define testExcept(EXCEPT, CMD) try{ CMD; testFail( "No exception from: " #CMD); } \ +catch(EXCEPT& e) {testPass("Got expected exception from: " #CMD);} \ +catch(std::exception& e) {testFail("Got wrong exception %s(%s) from: " #CMD, typeid(e).name(),e.what());} \ +catch(...) {testFail("Got unknown execption from: " #CMD);} + +static void testError() +{ + testDiag("testError"); + ScalarType invalidtype = (ScalarType)9999; + + testExcept(std::invalid_argument, ScalarTypeFunc::getScalarType("invalidtype")); + + testExcept(std::invalid_argument, ScalarTypeFunc::elementSize(invalidtype)); + + testExcept(std::invalid_argument, ScalarTypeFunc::name(invalidtype)); + + testOk1(!ScalarTypeFunc::isInteger(invalidtype)); + testOk1(!ScalarTypeFunc::isUInteger(invalidtype)); + testOk1(!ScalarTypeFunc::isNumeric(invalidtype)); + testOk1(!ScalarTypeFunc::isPrimitive(invalidtype)); + + testExcept(std::invalid_argument, fieldCreate->createScalar(invalidtype)); + testExcept(std::invalid_argument, fieldCreate->createScalarArray(invalidtype)); + + StringArray names; + FieldConstPtrArray fields(1); + + // fails because names.size()!=fields.size() + testExcept(std::invalid_argument, fieldCreate->createStructure(names,fields)); + + names.resize(1);; + + // fails because names[0].size()==0 + testExcept(std::invalid_argument, fieldCreate->createStructure(names,fields)); + + names[0] = "hello"; + + // fails because fields[0].get()==NULL + testExcept(std::invalid_argument, fieldCreate->createStructure(names,fields)); + + fields[0] = std::tr1::static_pointer_cast(fieldCreate->createScalar(pvDouble)); + + testOk1(fieldCreate->createStructure(names,fields).get()!=NULL); +} + +static void testMapping() +{ +#define OP(TYPE, ENUM) \ + testOk1(typeid(ScalarTypeTraits::type)==typeid(TYPE)); \ + testOk1(ENUM==(ScalarType)ScalarTypeID::value); \ + testOk1(ENUM==(ScalarType)ScalarTypeID::value); + OP(boolean, pvBoolean) + OP(int8, pvByte) + OP(int16, pvShort) + OP(int32, pvInt) + OP(int64, pvLong) + OP(uint8, pvUByte) + OP(uint16, pvUShort) + OP(uint32, pvUInt) + OP(uint64, pvULong) + OP(float, pvFloat) + OP(double, pvDouble) + OP(String, pvString) +#undef OP + + testOk1((ScalarType)ScalarTypeID::value==(ScalarType)-1); +} + +MAIN(testIntrospect) +{ + testPlan(161); fieldCreate = getFieldCreate(); pvDataCreate = getPVDataCreate(); standardField = getStandardField(); - testScalar(fd); - testScalarArray(fd); - testSimpleStructure(fd); - testStructureArray(fd); - return(0); + testScalar(); + testScalarArray(); + testStructure(); + testError(); + testMapping(); + return testDone(); } - diff --git a/testApp/pv/testOperators.cpp b/testApp/pv/testOperators.cpp index 2f38f3a..2926486 100644 --- a/testApp/pv/testOperators.cpp +++ b/testApp/pv/testOperators.cpp @@ -66,9 +66,10 @@ int main(int, char **) pvStructure = standardPVField->scalarArray(pvDouble,"alarm,timeStamp"); std::cout << *pvStructure << std::endl; - double values[] = { 1.1, 2.2, 3.3 }; + PVDoubleArray::svector values(3); + values[0] = 1.1; values[1] = 2.2; values[2] = 3.3; PVDoubleArrayPtr darray = std::tr1::dynamic_pointer_cast(pvStructure->getScalarArrayField("value", pvDouble)); - darray->put(0, 3, values, 0); + darray->replace(freeze(values)); std::cout << *darray << std::endl; std::cout << format::array_at(1) << *darray << std::endl; @@ -76,14 +77,13 @@ int main(int, char **) StructureConstPtr structure = standardField->scalar(pvDouble, "alarm,timeStamp"); pvStructure = standardPVField->structureArray(structure,"alarm,timeStamp"); size_t num = 2; - PVStructurePtrArray pvStructures; - pvStructures.reserve(num); + PVStructureArray::svector pvStructures(num); for(size_t i=0; icreatePVStructure(structure)); + pvStructures[i]= + pvDataCreate->createPVStructure(structure); } PVStructureArrayPtr pvStructureArray = pvStructure->getStructureArrayField("value"); - pvStructureArray->put(0, num, pvStructures, 0); + pvStructureArray->replace(freeze(pvStructures)); std::cout << *pvStructure << std::endl; return 0; diff --git a/testApp/pv/testPVScalarArray.cpp b/testApp/pv/testPVScalarArray.cpp index e709831..c32e807 100644 --- a/testApp/pv/testPVScalarArray.cpp +++ b/testApp/pv/testPVScalarArray.cpp @@ -14,6 +14,8 @@ #include #include +#include +#include #include #include @@ -25,352 +27,165 @@ using namespace epics::pvData; using std::tr1::static_pointer_cast; -static bool debug = false; +namespace { -static FieldCreatePtr fieldCreate = getFieldCreate(); -static PVDataCreatePtr pvDataCreate = getPVDataCreate(); -static StandardFieldPtr standardField = getStandardField(); -static StandardPVFieldPtr standardPVField = getStandardPVField(); -static ConvertPtr convert = getConvert(); -static String builder; -static String alarmTimeStamp("alarm,timeStamp"); -static String alarmTimeStampValueAlarm("alarm,timeStamp,valueAlarm"); -static String allProperties("alarm,timeStamp,display,control,valueAlarm"); -static FILE * fd = NULL; -static size_t length = 4; - -static void byteArray() +static void testFactory() { - if(debug) fprintf(fd,"\nbyteArray\n"); - PVScalarArrayPtr pvScalarArray = pvDataCreate->createPVScalarArray(pvByte);; - PVByteArrayPtr pvByteArray = static_pointer_cast(pvScalarArray); - ByteArray value; - value.reserve(length); - int8 xxx = 0x7f; - for(size_t i = 0; iput(0,length,value,0); - builder.clear(); - pvByteArray->toString(&builder); - if(debug) fprintf(fd,"put\n%s\n",builder.c_str()); - convert->fromByteArray(pvScalarArray,0,length,value,0); - builder.clear(); - pvByteArray->toString(&builder); - if(debug) fprintf(fd,"convert\n%s\n",builder.c_str()); - ByteArrayData data; - pvByteArray->get(0,length,data); - ByteArray_iterator iter = data.data.begin(); - if(debug) fprintf(fd,"iter ["); - for(iter=data.data.begin();iter!=data.data.end();++iter) { - if(debug) fprintf(fd,"%d ",*iter); + testDiag("Check array creation"); + + for(ScalarType e=pvBoolean; e<=pvString; e=(ScalarType)(1+(int)e)) + { + testDiag("Check type %s", ScalarTypeFunc::name(e)); + PVScalarArrayPtr arr = getPVDataCreate()->createPVScalarArray(e); + testOk1(arr.get()!=NULL); + if(!arr.get()) + continue; + testOk1(arr->getScalarArray()->getElementType()==e); + testOk1(arr->getLength()==0); + arr->setLength(10); + testOk1(arr->getLength()==10); + testOk1(arr->getCapacity()>=10); + arr->setLength(0); + testOk1(arr->getLength()==0); } - if(debug) fprintf(fd,"]\n"); - if(debug) fprintf(fd,"raw ["); - int8 * pdata = get(data.data); - for(size_t i=0; i +bool hasUniqueVector(const typename PVT::shared_pointer& pv) { - if(debug) fprintf(fd,"\nubyteArray\n"); - PVScalarArrayPtr pvScalarArray = pvDataCreate->createPVScalarArray(pvUByte);; - PVUByteArrayPtr pvUByteArray = static_pointer_cast(pvScalarArray); - UByteArray value; - value.reserve(length); - uint8 xxx = 0x7f; - for(size_t i = 0; iput(0,length,value,0); - builder.clear(); - pvUByteArray->toString(&builder); - if(debug) fprintf(fd,"put\n%s\n",builder.c_str()); - convert->fromUByteArray(pvScalarArray,0,length,value,0); - builder.clear(); - pvUByteArray->toString(&builder); - if(debug) fprintf(fd,"convert\n%s\n",builder.c_str()); - UByteArrayData data; - pvUByteArray->get(0,length,data); - UByteArray_iterator iter = data.data.begin(); - if(debug) fprintf(fd,"iter ["); - for(iter=data.data.begin();iter!=data.data.end();++iter) { - if(debug) fprintf(fd,"%u ",*iter); - } - if(debug) fprintf(fd,"]\n"); - if(debug) fprintf(fd,"raw ["); - uint8 * pdata = get(data.data); - for(size_t i=0; iswap(data); + bool ret = data.unique(); + pv->swap(data); + return ret; } -static void longArray() +template +struct basicTestData { + static inline void fill(typename PVT::svector& data) { + data.resize(100); + for(size_t i=0; i +struct basicTestData { + static inline void fill(PVStringArray::svector& data) { + PVIntArray::svector idata; + basicTestData::fill(idata); + data.resize(idata.size()); + castUnsafeV(data.size(), pvString, data.data(), pvInt, idata.data()); + } +}; + +template +static void testBasic() { - if(debug) fprintf(fd,"\nlongArray\n"); - PVScalarArrayPtr pvScalarArray = pvDataCreate->createPVScalarArray(pvLong);; - PVLongArrayPtr pvLongArray = static_pointer_cast(pvScalarArray); - LongArray value; - value.reserve(length); - int64 xxx = 0x7fffffffffffffffLL; - for(size_t i = 0; iput(0,length,value,0); - builder.clear(); - pvLongArray->toString(&builder); - if(debug) fprintf(fd,"put\n%s\n",builder.c_str()); - convert->fromLongArray(pvScalarArray,0,length,value,0); - builder.clear(); - pvLongArray->toString(&builder); - if(debug) fprintf(fd,"convert\n%s\n",builder.c_str()); - LongArrayData data; - pvLongArray->get(0,length,data); - LongArray_iterator iter = data.data.begin(); - if(debug) fprintf(fd,"iter ["); - for(iter=data.data.begin();iter!=data.data.end();++iter) { - if(debug) fprintf(fd,"%lli ",(long long)*iter); + testDiag("Check basic array operations for %s", typeid(PVT).name()); + + typename PVT::shared_pointer arr1 = static_pointer_cast(getPVDataCreate()->createPVScalarArray(PVT::typeCode)); + typename PVT::shared_pointer arr2 = static_pointer_cast(getPVDataCreate()->createPVScalarArray(PVT::typeCode)); + + testOk1(*arr1==*arr2); + testOk1(*arr1==*arr1); + testOk1(*arr1->getScalarArray()==*arr2->getScalarArray()); + + typename PVT::svector data; + data.reserve(200); + basicTestData::fill(data); + + typename PVT::const_svector cdata(freeze(data)); + + testOk1(cdata.unique()); + arr1->replace(cdata); + testOk1(!cdata.unique()); + + { + typename PVT::const_svector avoid; + arr1->PVScalarArray::getAs(avoid); + testOk1(avoid.data()==cdata.data()); + testOk1(avoid.data()==arr1->view().data()); } - if(debug) fprintf(fd,"]\n"); - if(debug) fprintf(fd,"raw ["); - int64 * pdata = get(data.data); - for(size_t i=0; igetLength()==cdata.size()); + + testOk1(*arr1!=*arr2); + + cdata.clear(); + + testOk1(hasUniqueVector(arr1)); + + arr2->assign(*arr1); + + testOk1(*arr1==*arr2); + testOk1(!hasUniqueVector(arr1)); + + arr2->swap(cdata); + arr2->postPut(); + + testOk1(arr2->getLength()==0); + testOk1(cdata.size()==arr1->getLength()); + + PVIntArray::const_svector idata; + arr1->PVScalarArray::getAs(idata); + + testOk1(idata.at(1)==10); + + PVIntArray::svector wdata(thaw(idata)); + + wdata.at(1) = 42; + + idata = freeze(wdata); + + arr1->PVScalarArray::putFrom(idata); + + testOk1(castUnsafe(arr1->view()[1])==42); } -static void ulongArray() +static void testShare() { - if(debug) fprintf(fd,"\nulongArray\n"); - PVScalarArrayPtr pvScalarArray = pvDataCreate->createPVScalarArray(pvULong);; - PVULongArrayPtr pvULongArray = static_pointer_cast(pvScalarArray); - ULongArray value; - value.reserve(length); - uint64 xxx = 0x7fffffffffffffffLL; - for(size_t i = 0; iput(0,length,value,0); - builder.clear(); - pvULongArray->toString(&builder); - if(debug) fprintf(fd,"put\n%s\n",builder.c_str()); - convert->fromULongArray(pvScalarArray,0,length,value,0); - builder.clear(); - pvULongArray->toString(&builder); - if(debug) fprintf(fd,"convert\n%s\n",builder.c_str()); - ULongArrayData data; - pvULongArray->get(0,length,data); - ULongArray_iterator iter = data.data.begin(); - if(debug) fprintf(fd,"iter ["); - for(iter=data.data.begin();iter!=data.data.end();++iter) { - if(debug) fprintf(fd,"%llu ",(long long unsigned)*iter); - } - if(debug) fprintf(fd,"]\n"); - if(debug) fprintf(fd,"raw ["); - uint64 * pdata = get(data.data); - for(size_t i=0; i(getPVDataCreate()->createPVScalarArray(pvInt)); + PVStringArrayPtr sarr = static_pointer_cast(getPVDataCreate()->createPVScalarArray(pvString)); + + PVIntArray::const_svector idata(4, 1); + + sarr->PVScalarArray::putFrom(idata); // copy and convert + + testOk1(idata.unique()); + + iarr->PVScalarArray::putFrom(idata); // take a reference + + testOk1(!idata.unique()); + + idata.clear(); + PVIntArray::const_svector cdata; + + sarr->PVScalarArray::getAs(cdata); // copy and convert + + testOk1(cdata.unique()); + + iarr->PVScalarArray::getAs(cdata); // take a reference + + testOk1(!cdata.unique()); } -static void floatArray() -{ - if(debug) fprintf(fd,"\nfloatArray\n"); - PVScalarArrayPtr pvScalarArray = pvDataCreate->createPVScalarArray(pvFloat);; - PVFloatArrayPtr pvFloatArray = static_pointer_cast(pvScalarArray); - FloatArray value; - value.reserve(length); - for(size_t i = 0; iput(0,length,value,0); - builder.clear(); - pvFloatArray->toString(&builder); - if(debug) fprintf(fd,"put\n%s\n",builder.c_str()); - convert->fromFloatArray(pvScalarArray,0,length,value,0); - builder.clear(); - pvFloatArray->toString(&builder); - if(debug) fprintf(fd,"convert\n%s\n",builder.c_str()); - FloatArrayData data; - pvFloatArray->get(0,length,data); - FloatArray_iterator iter = data.data.begin(); - if(debug) fprintf(fd,"iter ["); - for(iter=data.data.begin();iter!=data.data.end();++iter) { - if(debug) fprintf(fd,"%f ",*iter); - } - if(debug) fprintf(fd,"]\n"); - if(debug) fprintf(fd,"raw ["); - float * pdata = get(data.data); - for(size_t i=0; icreatePVScalarArray(pvDouble);; - PVDoubleArrayPtr pvDoubleArray = static_pointer_cast(pvScalarArray); - DoubleArray value; - value.reserve(length); - for(size_t i = 0; iput(0,length,value,0); - builder.clear(); - pvDoubleArray->toString(&builder); - if(debug) fprintf(fd,"put\n%s\n",builder.c_str()); - convert->fromDoubleArray(pvScalarArray,0,length,value,0); - builder.clear(); - pvDoubleArray->toString(&builder); - if(debug) fprintf(fd,"convert\n%s\n",builder.c_str()); - DoubleArrayData data; - pvDoubleArray->get(0,length,data); - DoubleArray_iterator iter = data.data.begin(); - if(debug) fprintf(fd,"iter ["); - for(iter=data.data.begin();iter!=data.data.end();++iter) { - if(debug) fprintf(fd,"%lf ",*iter); - } - if(debug) fprintf(fd,"]\n"); - if(debug) fprintf(fd,"raw ["); - double * pdata = get(data.data); - for(size_t i=0; i(); + testBasic(); + testBasic(); + testBasic(); + testBasic(); + testShare(); + return testDone(); } - -static void stringArray() -{ - if(debug) fprintf(fd,"\nstringArray\n"); - PVScalarArrayPtr pvScalarArray = pvDataCreate->createPVScalarArray(pvString);; - PVStringArrayPtr pvStringArray = static_pointer_cast(pvScalarArray); - StringArray value; - value.reserve(length); - for(size_t i = 0; iput(0,length,value,0); - builder.clear(); - pvStringArray->toString(&builder); - if(debug) fprintf(fd,"put\n%s\n",builder.c_str()); - convert->fromStringArray(pvScalarArray,0,length,value,0); - builder.clear(); - pvStringArray->toString(&builder); - if(debug) fprintf(fd,"convert\n%s\n",builder.c_str()); - StringArrayData data; - pvStringArray->get(0,length,data); - StringArray_iterator iter = data.data.begin(); - if(debug) fprintf(fd,"iter ["); - for(iter=data.data.begin();iter!=data.data.end();++iter) { - String val = *iter; - if(debug) fprintf(fd,"%s ",val.c_str()); - } - if(debug) fprintf(fd,"]\n"); - if(debug) fprintf(fd,"raw ["); - String* pdata = get(data.data); - for(size_t i=0; icreatePVScalarArray(pvDouble);; - PVDoubleArrayPtr pvDoubleArray = static_pointer_cast(pvScalarArray); - DoubleArray value; - value.reserve(length); - for(size_t i = 0; iput(0,length,value,0); - PVDoubleArrayPtr pvShareArray = static_pointer_cast( - pvDataCreate->createPVScalarArray(pvDouble)); - pvShareArray->shareData( - pvDoubleArray->getSharedVector(), - pvDoubleArray->getCapacity(), - pvDoubleArray->getLength()); - printf("pvDoubleArray->get() %p pvShareArray->get() %p\n",pvDoubleArray->get(),pvShareArray->get()); - printf("pvDoubleArray->getVector() %p pvShareArray->getVector() %p\n", - &(pvDoubleArray->getVector()),&(pvShareArray->getVector())); - printf("pvDoubleArray->getSharedVector() %p pvShareArray->getSharedVector() %p\n", - &(pvDoubleArray->getSharedVector()),&(pvShareArray->getSharedVector())); - assert(pvDoubleArray->get()==pvShareArray->get()); - builder.clear(); - pvShareArray->toString(&builder); - if(debug) fprintf(fd,"pvShare\n%s\n",builder.c_str()); - fprintf(fd,"shareArray PASSED\n"); -} - -int main(int argc,char *argv[]) -{ - char *fileName = 0; - if(argc>1) fileName = argv[1]; - fd = stdout; - if(fileName!=0 && fileName[0]!=0) { - fd = fopen(fileName,"w+"); - } - byteArray(); - ubyteArray(); - longArray(); - ulongArray(); - floatArray(); - doubleArray(); - stringArray(); - shareArray(); - return(0); -} - diff --git a/testApp/pv/testPVStructureArray.cpp b/testApp/pv/testPVStructureArray.cpp index 8614271..f5701fb 100644 --- a/testApp/pv/testPVStructureArray.cpp +++ b/testApp/pv/testPVStructureArray.cpp @@ -22,101 +22,138 @@ #include #include -using namespace epics::pvData; +#include +#include -static bool debug = false; +using namespace epics::pvData; static FieldCreatePtr fieldCreate; static PVDataCreatePtr pvDataCreate; static StandardFieldPtr standardField; static StandardPVFieldPtr standardPVField; static ConvertPtr convert; -static String buffer; -static void testPVStructureArray(FILE * fd) { - if(debug) fprintf(fd,"/ntestPVStructureArray\n"); - StructureArrayConstPtr alarm( - fieldCreate->createStructureArray(standardField->alarm())); - PVStructureArrayPtr pvAlarmStructure( - pvDataCreate->createPVStructureArray(alarm)); - PVStructurePtrArray palarms; - size_t na=2; - palarms.reserve(na); - for(size_t i=0; icreatePVStructure(standardField->alarm())); - } - pvAlarmStructure->put(0,2,palarms,0); - buffer.clear(); - pvAlarmStructure->toString(&buffer); - if(debug) fprintf(fd,"pvAlarmStructure\n%s\n",buffer.c_str()); - PVStructureArrayPtr copy(pvDataCreate->createPVStructureArray(alarm)); - convert->copyStructureArray(pvAlarmStructure,copy); - buffer.clear(); - copy->toString(&buffer); - if(debug) fprintf(fd,"copy\n%s\n",buffer.c_str()); - fprintf(fd,"testPVStructureArray PASSED\n"); -} - -static StructureConstPtr getPowerSupplyStructure() { - String properties("alarm"); - FieldConstPtrArray fields; - StringArray fieldNames; - fields.reserve(3); - fieldNames.reserve(3); - fieldNames.push_back("voltage"); - fieldNames.push_back("power"); - fieldNames.push_back("current"); - fields.push_back(standardField->scalar(pvDouble,properties)); - fields.push_back(standardField->scalar(pvDouble,properties)); - fields.push_back(standardField->scalar(pvDouble,properties)); - StructureConstPtr structure = fieldCreate->createStructure( - "powerSupply_t",fieldNames,fields); - return structure; -} - -static void testPowerSupplyArray(FILE * fd) { - if(debug) fprintf(fd,"/ntestPowerSupplyArray\n"); - PVStructurePtr powerSupplyArrayStruct = standardPVField->structureArray( - getPowerSupplyStructure(),String("alarm,timeStamp")); - PVStructureArrayPtr powerSupplyArray = - powerSupplyArrayStruct->getStructureArrayField(String("value")); - assert(powerSupplyArray.get()!=NULL); - int offset = powerSupplyArray->append(5); - if(debug) fprintf(fd,"offset %d\n",offset); - buffer.clear(); - powerSupplyArrayStruct->toString(&buffer); - if(debug) fprintf(fd,"after append 5\n%s\n",buffer.c_str()); - powerSupplyArray->remove(0,2); - buffer.clear(); - powerSupplyArrayStruct->toString(&buffer); - if(debug) fprintf(fd,"after remove(0,2)\n%s\n",buffer.c_str()); - powerSupplyArray->remove(2,1); - buffer.clear(); - powerSupplyArrayStruct->toString(&buffer); - if(debug) fprintf(fd,"after remove 2,1%s\n",buffer.c_str()); - powerSupplyArray->compress(); - buffer.clear(); - powerSupplyArrayStruct->toString(&buffer); - if(debug) fprintf(fd,"after compress%s\n",buffer.c_str()); - fprintf(fd,"testPowerSupplyArray PASSED\n"); -} - -int main(int argc,char *argv[]) +static void testBasic() { - char *fileName = 0; - if(argc>1) fileName = argv[1]; - FILE * fd = stdout; - if(fileName!=0 && fileName[0]!=0) { - fd = fopen(fileName,"w+"); - } + testDiag("Basic structure array ops"); + + StructureArrayConstPtr alarmtype( + fieldCreate->createStructureArray(standardField->alarm())); + + PVStructureArrayPtr alarmarr(pvDataCreate->createPVStructureArray(alarmtype)); + + testOk1(alarmarr->getLength()==0); + + alarmarr->setLength(5); + + testOk1(alarmarr->getLength()==5); + + PVStructureArray::const_svector aview = alarmarr->view(); + + testOk1(aview.size()==5); + testOk1(aview[4].get()==NULL); + + alarmarr->append(2); + + testOk1(alarmarr->getLength()==7); + + aview = alarmarr->view(); + + testOk1(aview[4].get()==NULL); + testOk1(aview[5].get()!=NULL); + testOk1(aview[6].get()!=NULL); +} + +static void testCompress() +{ + testDiag("Test structure array compress"); + + StructureArrayConstPtr alarmtype( + fieldCreate->createStructureArray(standardField->alarm())); + + PVStructureArrayPtr alarmarr(pvDataCreate->createPVStructureArray(alarmtype)); + + alarmarr->setLength(5); + + testOk1(alarmarr->getLength()==5); + + alarmarr->compress(); + + testOk1(alarmarr->getLength()==0); + + alarmarr->setLength(4); + + testOk1(alarmarr->getLength()==4); + + PVStructureArray::svector contents(10); + + contents[2] = pvDataCreate->createPVStructure(standardField->alarm()); + contents[4] = pvDataCreate->createPVStructure(standardField->alarm()); + contents[5] = pvDataCreate->createPVStructure(standardField->alarm()); + contents[8] = pvDataCreate->createPVStructure(standardField->alarm()); + + PVStructureArray::const_svector scont(freeze(contents)); + + alarmarr->replace(scont); + + testOk1(!scont.unique()); + testOk1(alarmarr->getLength()==10); + + alarmarr->compress(); + + testOk1(scont.unique()); // a realloc happened + testOk1(alarmarr->getLength()==4); + + PVStructureArray::svector compressed(alarmarr->reuse()); + + testOk1(scont[2]==compressed[0]); + testOk1(scont[4]==compressed[1]); + testOk1(scont[5]==compressed[2]); + testOk1(scont[8]==compressed[3]); +} + +static void testRemove() +{ + testDiag("Test structure array remove"); + + PVStructureArray::svector contents(10); + + for(size_t i=0; icreatePVStructure(standardField->alarm()); + + StructureArrayConstPtr alarmtype( + fieldCreate->createStructureArray(standardField->alarm())); + PVStructureArrayPtr alarmarr(pvDataCreate->createPVStructureArray(alarmtype)); + + PVStructureArray::const_svector scont(freeze(contents)); + + alarmarr->replace(scont); + + alarmarr->remove(0, 10); // all + + testOk1(alarmarr->getLength()==0); + + alarmarr->replace(scont); + + alarmarr->remove(1, 1); + + PVStructureArray::const_svector check(alarmarr->view()); + + testOk1(scont[0]==check[0]); + testOk1(scont[2]==check[1]); + testOk1(scont[3]==check[2]); +} + +MAIN(testPVStructureArray) +{ + testPlan(0); + testDiag("Testing structure array handling"); fieldCreate = getFieldCreate(); pvDataCreate = getPVDataCreate(); standardField = getStandardField(); standardPVField = getStandardPVField(); - convert = getConvert(); - testPVStructureArray(fd); - testPowerSupplyArray(fd); - return(0); + testBasic(); + testCompress(); + testRemove(); + return testDone(); } - diff --git a/testApp/pv/testStandardPVField.cpp b/testApp/pv/testStandardPVField.cpp index 7c19ccd..11a276b 100644 --- a/testApp/pv/testStandardPVField.cpp +++ b/testApp/pv/testStandardPVField.cpp @@ -70,14 +70,13 @@ int main(int, char **) StructureConstPtr structure = standardField->scalar(pvDouble, "alarm,timeStamp"); pvStructure = standardPVField->structureArray(structure,"alarm,timeStamp"); size_t num = 2; - PVStructurePtrArray pvStructures; - pvStructures.reserve(num); + PVStructureArray::svector pvStructures(num); for(size_t i=0; icreatePVStructure(structure)); + pvStructures[i]= + pvDataCreate->createPVStructure(structure); } PVStructureArrayPtr pvStructureArray = pvStructure->getStructureArrayField("value"); - pvStructureArray->put(0, num, pvStructures, 0); + pvStructureArray->replace(freeze(pvStructures)); builder.clear(); pvStructure->toString(&builder); print("structureArrayTest");