From b4e44289826ec0ed75793a110ea5d68a72be0cff Mon Sep 17 00:00:00 2001 From: Georgiy Frolov Date: Mon, 10 Aug 2015 18:57:28 -0400 Subject: [PATCH 1/9] Initial type-safe ID wrapper. --- inc/osvr/Util/ID.h | 67 ++++++++++++++++++++++++++++++++++++ src/osvr/Util/CMakeLists.txt | 1 + 2 files changed, 68 insertions(+) create mode 100644 inc/osvr/Util/ID.h diff --git a/inc/osvr/Util/ID.h b/inc/osvr/Util/ID.h new file mode 100644 index 000000000..f7a68d7fe --- /dev/null +++ b/inc/osvr/Util/ID.h @@ -0,0 +1,67 @@ +/** @file + @brief Header + + @date 2015 + + @author + Sensics, Inc. + +*/ + +// Copyright 2015 Sensics, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef INCLUDED_ID_h_GUID_137CA336_382A_4796_7735_4521F02D5AC2 +#define INCLUDED_ID_h_GUID_137CA336_382A_4796_7735_4521F02D5AC2 + +// Internal Includes +// - none + +// Library/third-party includes +// - none + +// Standard includes +#include +#include + +/// idea from the +/// http://www.ilikebigbits.com/blog/2014/5/6/type-safe-identifiers-in-c +template class ID { + public: + static ID invalid() { return ID(); } + + // Default constructor which will set m_val to a 0xffffffff (UINT32 max) + // and signify empty. + ID() : m_val(0xffffffff) {} + + // Explicit constructor: + explicit ID(impl val) : m_val(val) {} + + bool empty() const { return m_val == 0xffffffff ? true : false; } + + operator impl & () {return m_val; } + friend bool operator==(ID a, ID b) { return a.m_val == b.m_val; } + friend bool operator!=(ID a, ID b) { return a.m_val != b.m_val; } + + impl& value() { return m_val; } + impl value() const { return m_val; } + + private: + impl m_val; +}; + +typedef ID StringID; +typedef ID PeerStringID; + +#endif // INCLUDED_ID_h_GUID_137CA336_382A_4796_7735_4521F02D5AC2 diff --git a/src/osvr/Util/CMakeLists.txt b/src/osvr/Util/CMakeLists.txt index f61f9f206..ca9e7b170 100644 --- a/src/osvr/Util/CMakeLists.txt +++ b/src/osvr/Util/CMakeLists.txt @@ -43,6 +43,7 @@ set(API "${HEADER_LOCATION}/EigenExtras.h" "${HEADER_LOCATION}/EigenInterop.h" "${HEADER_LOCATION}/Flag.h" + "${HEADER_LOCATION}/ID.h" "${HEADER_LOCATION}/GenericCaller.h" "${HEADER_LOCATION}/GenericDeleter.h" "${HEADER_LOCATION}/GuardInterface.h" From a3ad7c84f73401fd044e0d25afcb71ee2c23a3db Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 21 Sep 2015 16:21:39 -0500 Subject: [PATCH 2/9] Substantially overhaul the type-safe ID template. No more overriding operator& or providing implicit conversion. It's also now properly in a namespace, and uses traits classes to determine the underlying value type as well as the "invalid/empty" sentinel value. --- inc/osvr/Util/ID.h | 67 ------------------- inc/osvr/Util/StringIds.h | 46 +++++++++++++ inc/osvr/Util/TypeSafeId.h | 124 +++++++++++++++++++++++++++++++++++ src/osvr/Util/CMakeLists.txt | 3 +- 4 files changed, 172 insertions(+), 68 deletions(-) delete mode 100644 inc/osvr/Util/ID.h create mode 100644 inc/osvr/Util/StringIds.h create mode 100644 inc/osvr/Util/TypeSafeId.h diff --git a/inc/osvr/Util/ID.h b/inc/osvr/Util/ID.h deleted file mode 100644 index f7a68d7fe..000000000 --- a/inc/osvr/Util/ID.h +++ /dev/null @@ -1,67 +0,0 @@ -/** @file - @brief Header - - @date 2015 - - @author - Sensics, Inc. - -*/ - -// Copyright 2015 Sensics, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef INCLUDED_ID_h_GUID_137CA336_382A_4796_7735_4521F02D5AC2 -#define INCLUDED_ID_h_GUID_137CA336_382A_4796_7735_4521F02D5AC2 - -// Internal Includes -// - none - -// Library/third-party includes -// - none - -// Standard includes -#include -#include - -/// idea from the -/// http://www.ilikebigbits.com/blog/2014/5/6/type-safe-identifiers-in-c -template class ID { - public: - static ID invalid() { return ID(); } - - // Default constructor which will set m_val to a 0xffffffff (UINT32 max) - // and signify empty. - ID() : m_val(0xffffffff) {} - - // Explicit constructor: - explicit ID(impl val) : m_val(val) {} - - bool empty() const { return m_val == 0xffffffff ? true : false; } - - operator impl & () {return m_val; } - friend bool operator==(ID a, ID b) { return a.m_val == b.m_val; } - friend bool operator!=(ID a, ID b) { return a.m_val != b.m_val; } - - impl& value() { return m_val; } - impl value() const { return m_val; } - - private: - impl m_val; -}; - -typedef ID StringID; -typedef ID PeerStringID; - -#endif // INCLUDED_ID_h_GUID_137CA336_382A_4796_7735_4521F02D5AC2 diff --git a/inc/osvr/Util/StringIds.h b/inc/osvr/Util/StringIds.h new file mode 100644 index 000000000..6c961f6c1 --- /dev/null +++ b/inc/osvr/Util/StringIds.h @@ -0,0 +1,46 @@ +/** @file + @brief Header + + @date 2015 + + @author + Sensics, Inc. + +*/ + +// Copyright 2015 Sensics, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef INCLUDED_StringIds_h_GUID_080FD2D7_0F0B_438B_E71E_7D2836C8921B +#define INCLUDED_StringIds_h_GUID_080FD2D7_0F0B_438B_E71E_7D2836C8921B + +// Internal Includes +#include + +// Library/third-party includes +// - none + +// Standard includes +// - none + +namespace osvr { +namespace util { + struct LocalStringIdTag; + struct PeerStringIdTag; + typedef TypeSafeId StringID; + typedef TypeSafeId PeerStringID; +} // namespace util +} // namespace osvr + +#endif // INCLUDED_StringIds_h_GUID_080FD2D7_0F0B_438B_E71E_7D2836C8921B diff --git a/inc/osvr/Util/TypeSafeId.h b/inc/osvr/Util/TypeSafeId.h new file mode 100644 index 000000000..3f750abb5 --- /dev/null +++ b/inc/osvr/Util/TypeSafeId.h @@ -0,0 +1,124 @@ +/** @file + @brief Header + + @date 2015 + + @author + Sensics, Inc. + +*/ + +// Copyright 2015 Sensics, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef INCLUDED_TypeSafeId_h_GUID_137CA336_382A_4796_7735_4521F02D5AC2 +#define INCLUDED_TypeSafeId_h_GUID_137CA336_382A_4796_7735_4521F02D5AC2 + +// Internal Includes +#include + +// Library/third-party includes +// - none + +// Standard includes +#include + +namespace osvr { +namespace util { + /// @brief Namespace for traits templates associated with + /// ::osvr::util::TypeSafeId + namespace typesafeid_traits { + /// @brief Explicitly specialize for your tag type if you want a + /// different + /// underlying type. + template struct WrappedType { typedef uint32_t type; }; + + /// @brief Explicitly specialize for your tag type if you want a + /// different signal value for invalid/empty: default is the maximum + /// representable value for your type. + template struct SentinelValue { + typedef typename WrappedType::type wrapped_type; + static wrapped_type get() { + return std::numeric_limits::max(); + } + }; + + } // namespace typesafeid_traits + + /// @brief A generic typesafe (as long as you use differing tag types) + /// wrapper for identifiers (typically integers). + /// + /// @tparam Tag any type - does not have to be defined, just declared (so + /// `struct mytag;` somewhere is fine). The tag serves to make integer IDs + /// have distinct types, and also serves as a look-up key in the + /// ::osvr::util::typesafeid_traits classes for underlying integer type and + /// sentinel empty/invalid value. + /// + /// Initial implementation inspired by + /// http://www.ilikebigbits.com/blog/2014/5/6/type-safe-identifiers-in-c + /// though this version now strays quite far by strengthening type-safety + /// and encapsulation, and by using traits classes to specify details based + /// on tag type alone. + template class TypeSafeId { + public: + /// @brief The type of the current class. + typedef TypeSafeId type; + + /// @brief The contained/wrapped type. + typedef typename typesafeid_traits::WrappedType::type wrapped_type; + + /// @brief Static factory method to return an invalid/empty ID. + static type invalid() { return type(); } + + // Default constructor which will set m_val to the empty/invalid value. + TypeSafeId() : m_val(sentinel()) {} + + // Explicit constructor from the wrapped type + explicit TypeSafeId(wrapped_type val) : m_val(val) {} + + /// @brief Check whether the ID is empty/invalid + bool empty() const { return m_val == sentinel(); } + + /// @brief Read-only accessor to the (non-type-safe!) wrapped value + wrapped_type value() const { return m_val; } + + /// @brief Reference accessor to the (non-type-safe!) wrapped value + wrapped_type & value() { return m_val; } + + private: + /// @brief Utility function to access the SentinelValue trait. + static wrapped_type sentinel() { + return typesafeid_traits::SentinelValue::get(); + } + wrapped_type m_val; + }; + + /// @brief Equality comparison operator for type-safe IDs + /// @relates ::osvr::util::TypeSafeId + template + inline bool operator==(TypeSafeId const a, TypeSafeId const b) { + return a.value() == b.value(); + } + + /// @brief Inequality comparison operator for type-safe IDs + /// @relates ::osvr::util::TypeSafeId + template + inline bool operator!=(TypeSafeId const a, TypeSafeId const b) { + return a.value() != b.value(); + } + +} // namespace util +} // namespace osvr + +#endif // INCLUDED_TypeSafeId_h_GUID_137CA336_382A_4796_7735_4521F02D5AC2 diff --git a/src/osvr/Util/CMakeLists.txt b/src/osvr/Util/CMakeLists.txt index ca9e7b170..565c40614 100644 --- a/src/osvr/Util/CMakeLists.txt +++ b/src/osvr/Util/CMakeLists.txt @@ -43,7 +43,6 @@ set(API "${HEADER_LOCATION}/EigenExtras.h" "${HEADER_LOCATION}/EigenInterop.h" "${HEADER_LOCATION}/Flag.h" - "${HEADER_LOCATION}/ID.h" "${HEADER_LOCATION}/GenericCaller.h" "${HEADER_LOCATION}/GenericDeleter.h" "${HEADER_LOCATION}/GuardInterface.h" @@ -81,6 +80,7 @@ set(API "${HEADER_LOCATION}/StdInt.h" "${HEADER_LOCATION}/StringBufferBuilder.h" "${HEADER_LOCATION}/StringLiteralFileToString.h" + "${HEADER_LOCATION}/StringIds.h" "${HEADER_LOCATION}/TimeValue.h" "${HEADER_LOCATION}/TimeValueC.h" "${HEADER_LOCATION}/TimeValue_fwd.h" @@ -88,6 +88,7 @@ set(API "${HEADER_LOCATION}/TreeNode_fwd.h" "${HEADER_LOCATION}/TreeTraversalVisitor.h" "${HEADER_LOCATION}/TypePack.h" + "${HEADER_LOCATION}/TypeSafeId.h" "${HEADER_LOCATION}/UniquePtr.h" "${HEADER_LOCATION}/UniqueContainer.h" "${HEADER_LOCATION}/Util.h" From 50ab9ff07a055fb77a537bc55cacf1fc7e693483 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 21 Sep 2015 16:19:30 -0500 Subject: [PATCH 3/9] Serialization for TypeSafeId --- inc/osvr/Common/SerializationTraits.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/inc/osvr/Common/SerializationTraits.h b/inc/osvr/Common/SerializationTraits.h index 34c6999f6..4d28ff5cb 100644 --- a/inc/osvr/Common/SerializationTraits.h +++ b/inc/osvr/Common/SerializationTraits.h @@ -32,6 +32,7 @@ #include #include #include +#include // Library/third-party includes #include @@ -510,6 +511,15 @@ namespace common { f(val.data[2]); } }; + + template + struct SimpleStructSerialization> + : SimpleStructSerializationBase { + template static void apply(F &f, T &val) { + f(val.value()); + } + }; + } // namespace serialization } // namespace common From 5d6227dd7ccf9709c91b7a70cd21a0b57112f732 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 21 Sep 2015 11:10:42 -0500 Subject: [PATCH 4/9] Add serialization traits for std::vector. Includes some basic tests. --- inc/osvr/Common/SerializationTraits.h | 46 ++++++++++++++++++++++++ tests/cplusplus/Common/Serialization.cpp | 43 ++++++++++++++++++++++ 2 files changed, 89 insertions(+) diff --git a/inc/osvr/Common/SerializationTraits.h b/inc/osvr/Common/SerializationTraits.h index 4d28ff5cb..943783611 100644 --- a/inc/osvr/Common/SerializationTraits.h +++ b/inc/osvr/Common/SerializationTraits.h @@ -40,6 +40,7 @@ // Standard includes #include +#include #include namespace osvr { @@ -493,6 +494,51 @@ namespace common { } }; + template + struct SerializationTraits< + DefaultSerializationTag>, void> + : BaseSerializationTraits> { + using value_type = std::vector; + using param_type = value_type const &; + using reference_type = value_type &; + typedef BaseSerializationTraits> Base; + typedef DefaultSerializationTag> tag_type; + + template + static void serialize(BufferType &buf, param_type val, + tag_type const &) { + serializeRaw(buf, static_cast(val.size())); + for (auto &elt : val) { + serializeRaw(buf, elt); + } + } + + template + static void deserialize(BufferReaderType &buf, reference_type val, + tag_type const &) { + uint32_t n; + deserializeRaw(buf, n); + val.clear(); + val.reserve(n); + for (uint32_t i = 0; i < n; ++i) { + ValueType elt; + deserializeRaw(buf, elt); + val.push_back(elt); + } + } + + static size_t spaceRequired(size_t existingBytes, param_type val, + tag_type const &) { + size_t bytes = existingBytes; + bytes += getBufferSpaceRequiredRaw( + bytes, static_cast(val.size())); + for (auto &elt : val) { + bytes += getBufferSpaceRequiredRaw(bytes, elt); + } + return bytes - existingBytes; + } + }; + template <> struct SimpleStructSerialization : SimpleStructSerializationBase { diff --git a/tests/cplusplus/Common/Serialization.cpp b/tests/cplusplus/Common/Serialization.cpp index 5bdbc4611..074b2cb22 100644 --- a/tests/cplusplus/Common/Serialization.cpp +++ b/tests/cplusplus/Common/Serialization.cpp @@ -151,6 +151,27 @@ TYPED_TEST(ArithmeticRawSerialization, RoundTrip0) { ASSERT_EQ(reader.bytesRemaining(), 0); } +TYPED_TEST(ArithmeticRawSerialization, VectorRoundTrip) { + Buffer<> buf; + TypeParam in(0); + static const auto count = 5; + std::vector inVal; + for (int i = 0; i < count; ++i) { + in += 1.8; + inVal.push_back(in); + } + + osvr::common::serialization::serializeRaw(buf, inVal); + ASSERT_GE(buf.size(), sizeof(uint32_t) + count * sizeof(TypeParam)); + + auto reader = buf.startReading(); + + std::vector outVal(1); + osvr::common::serialization::deserializeRaw(reader, outVal); + ASSERT_EQ(inVal, outVal); + ASSERT_EQ(reader.bytesRemaining(), 0); +} + #ifdef _MSC_VER /// Disable "truncation of constant value" warning here. #pragma warning(push) @@ -231,6 +252,28 @@ TEST(BoolSerialization, RoundTripFalse) { ASSERT_EQ(reader.bytesRemaining(), 0); } +TEST(StringVectorSerialization, RoundTrip) { + auto buf = Buffer<>{}; + using TypeParam = std::vector; + auto inVal = TypeParam{}; + auto os = std::ostringstream{}; + static const auto count = 10; + for (int i = 0; i < count; ++i) { + inVal.push_back(os.str()); + os << "x"; + } + + osvr::common::serialization::serializeRaw(buf, inVal); + ASSERT_GE(buf.size(), sizeof(uint32_t) + count * sizeof(char)); + + auto reader = buf.startReading(); + + auto outVal = TypeParam{}; + osvr::common::serialization::deserializeRaw(reader, outVal); + ASSERT_EQ(inVal, outVal); + ASSERT_EQ(reader.bytesRemaining(), 0); +} + class SerializationAlignment : public ::testing::Test { public: virtual void SetUp() { From 596730bd5f36aa0632961d4821068820e55a6f57 Mon Sep 17 00:00:00 2001 From: Georgiy Frolov Date: Mon, 21 Sep 2015 16:34:44 -0500 Subject: [PATCH 5/9] Initial RegisteredStringMap implementation. Some modifications on rebase. --- inc/osvr/Common/RegisteredStringMap.h | 116 ++++++++++++++++ src/osvr/Common/CMakeLists.txt | 2 + src/osvr/Common/RegisteredStringMap.cpp | 170 ++++++++++++++++++++++++ 3 files changed, 288 insertions(+) create mode 100644 inc/osvr/Common/RegisteredStringMap.h create mode 100644 src/osvr/Common/RegisteredStringMap.cpp diff --git a/inc/osvr/Common/RegisteredStringMap.h b/inc/osvr/Common/RegisteredStringMap.h new file mode 100644 index 000000000..f4beac7da --- /dev/null +++ b/inc/osvr/Common/RegisteredStringMap.h @@ -0,0 +1,116 @@ +/** @file + @brief Header + + @date 2015 + + @author + Sensics, Inc. + +*/ + +// Copyright 2015 Sensics, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef INCLUDED_RegisteredStringMap_h_GUID_066235BE_3687_44AD_C2A4_593D6E6780F3 +#define INCLUDED_RegisteredStringMap_h_GUID_066235BE_3687_44AD_C2A4_593D6E6780F3 + +// Internal Includes +#include +#include + +// Library/third-party includes +#include + +// Standard includes +#include + +namespace osvr { +namespace common { + + /// map + typedef std::map RegistryList; + + /// @todo change this to serialized bytestream in the future + typedef Json::Value SerializedStringMap; + + /// Centralize a string registry. Basically, the server side, and part + /// of the client side internals. + class RegisteredStringMap { + public: + /// @brief Constructor + OSVR_COMMON_EXPORT RegisteredStringMap(); + + OSVR_COMMON_EXPORT ~RegisteredStringMap(); + + /// retrieve the ID for the current name or register new ID and return + /// that + OSVR_COMMON_EXPORT util::StringID getStringID(std::string const &str); + + /// retrieve the name of the string given the ID + /// returns empty string if nothing found + OSVR_COMMON_EXPORT std::string getNameFromID(util::StringID &id) const; + + /// package the entire (current) map into bytestream and return its copy + /// will be used to transport of maps between server and client + OSVR_COMMON_EXPORT SerializedStringMap getMap() const; + + /// add new entry to the string map and return new ID + OSVR_COMMON_EXPORT util::StringID + registerStringID(std::string const &str); + + OSVR_COMMON_EXPORT bool isUpdateAvailable(); + + OSVR_COMMON_EXPORT void printCurrentMap(); + + protected: + /// keep track of number of entries in the registry, + /// may not be needed if we stick with vectors + int m_numEntries; + RegistryList m_regEntries; + + /// special flag that gets switched whenever new element is inserted; + bool m_updateMap; + }; + + /// This is like a RegisteredStringMap, except it also knows that some peer + /// also has a string map, likely with some of the same strings, but with + /// different ids. Used in reconciliation between server and client since + /// they are + /// separate entities + class CorrelatedStringMap : public RegisteredStringMap { + public: + /// @brief Constructor + OSVR_COMMON_EXPORT CorrelatedStringMap(); + + OSVR_COMMON_EXPORT ~CorrelatedStringMap(); + + /// This is the extra method used by clients, to convert from server's + /// ids. Will return NULL if peerID to Local ID mapping doesn't exist + OSVR_COMMON_EXPORT util::StringID + convertPeerToLocalID(util::PeerStringID peerID) const; + + /// This populates the data structure used by the above method. + OSVR_COMMON_EXPORT void setupPeerMappings(SerializedStringMap peerdata); + + /// This will add the mapping or ignore it if it's present + void addPeerToLocalMapping(util::PeerStringID peerID, + util::StringID localID); + + private: + /// keeps the peer to local string ID mappings + std::vector> mappings; + }; +} // namespace common +} // namespace osvr +#endif // INCLUDED_RegisteredStringMap_h_GUID_066235BE_3687_44AD_C2A4_593D6E6780F3 diff --git a/src/osvr/Common/CMakeLists.txt b/src/osvr/Common/CMakeLists.txt index e5621df77..574134afe 100644 --- a/src/osvr/Common/CMakeLists.txt +++ b/src/osvr/Common/CMakeLists.txt @@ -87,6 +87,7 @@ set(API "${HEADER_LOCATION}/ProcessDeviceDescriptor.h" "${HEADER_LOCATION}/RawMessageType.h" "${HEADER_LOCATION}/RawSenderType.h" + "${HEADER_LOCATION}/RegisteredStringMap.h" "${HEADER_LOCATION}/ReportFromCallback.h" "${HEADER_LOCATION}/ReportMap.h" "${HEADER_LOCATION}/ReportState.h" @@ -152,6 +153,7 @@ set(SOURCE ProcessDeviceDescriptor.cpp RawMessageType.cpp RawSenderType.cpp + RegisteredStringMap.cpp ResolveFullTree.cpp ResolveTreeNode.cpp RouteContainer.cpp diff --git a/src/osvr/Common/RegisteredStringMap.cpp b/src/osvr/Common/RegisteredStringMap.cpp new file mode 100644 index 000000000..738d47ba9 --- /dev/null +++ b/src/osvr/Common/RegisteredStringMap.cpp @@ -0,0 +1,170 @@ +/** @file + @brief Implementation + + @date 2015 + + @author + Sensics, Inc. + + +*/ + +// Copyright 2015 Sensics, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Internal Includes +#include + +// Library/third-party includes +#include + +// Standard includes +#include + +namespace osvr { +namespace common { + + /// @brief set the initial number of entries to zero, and flag to update the + /// Map (since it's new) + RegisteredStringMap::RegisteredStringMap() + : m_numEntries(0), m_updateMap(true) {} + + /// @todo add proper destructor + RegisteredStringMap::~RegisteredStringMap() {} + + /// @brief helper function to print size and contents of the map + void RegisteredStringMap::printCurrentMap() { + + std::cout << "Current map contains " << m_regEntries.size() + << " entries: " << std::endl; + for (auto &entry : m_regEntries) { + std::cout << "ID: " << entry.second.value() << "; " + << "Name: " << entry.first << std::endl; + } + } + + SerializedStringMap RegisteredStringMap::getMap() const { + + Json::Value serializedMap; + + for (auto &entry : m_regEntries) { + + serializedMap[entry.first] = entry.second.value(); + } + return serializedMap; + } + + util::StringID + RegisteredStringMap::registerStringID(std::string const &str) { + + // we've checked the entries before and haven't found so we'll just add + // new one + std::string name = str; + util::StringID newID(m_regEntries.size()); + + m_regEntries.insert(std::make_pair(name, newID)); + m_numEntries++; + + m_updateMap = true; + return newID; + } + + util::StringID RegisteredStringMap::getStringID(std::string const &str) { + + // check the existing registry first + for (auto &entry : m_regEntries) { + // found a matching name, NOTE: CaSe Sensitive + if (boost::equals(str, entry.first)) { + m_updateMap = false; + return entry.second; + } + } + + // we didn't find an entry in the registry so we'll add a new one + return registerStringID(str); + } + + std::string RegisteredStringMap::getNameFromID(util::StringID &id) const { + + // requested non-existent ID (include sanity check) + if (id.value() >= m_regEntries.size()) { + // returning empty string + return std::string(); + } + + // entries should be ordered 0-.. with new ones + // appending to the end, so we should be safe at pulling by vector index + + for (auto &entry : m_regEntries) { + if (entry.second == id) { + // found name for this ID + return entry.first; + } + } + // returning empty string + return std::string(); + }; + + bool RegisteredStringMap::isUpdateAvailable() { return m_updateMap; } + + CorrelatedStringMap::CorrelatedStringMap() {} + + /// @todo add proper destructor + CorrelatedStringMap::~CorrelatedStringMap() {} + + util::StringID + CorrelatedStringMap::convertPeerToLocalID(util::PeerStringID peerID) const { + + // go thru the mappings and return an empty StringID if nothing's found + for (auto &mapping : mappings) { + + if (mapping.first == peerID) { + return mapping.second; + } + } + + return util::StringID(); + } + + void CorrelatedStringMap::addPeerToLocalMapping(util::PeerStringID peerID, + util::StringID localID) { + + // there should be 1 to 1 mapping between peer and local IDs, + // so if we find one, it should be correct + for (auto &mapping : mappings) { + // got a match + if ((mapping.first == peerID) && (mapping.second == localID)) { + return; + } + } + // add new mapping + mappings.push_back(std::make_pair(peerID, localID)); + } + + void CorrelatedStringMap::setupPeerMappings(SerializedStringMap peerData) { + + // go thru the peerData, you get name and id + // this name may already be stored in correlatedMap + // so we get the localID first (or register it) + // then store it in the mappings + + for (auto &name : peerData.getMemberNames()) { + + util::PeerStringID peerID(peerData[name].asUInt()); + util::StringID localID = getStringID(name); + addPeerToLocalMapping(peerID, localID); + } + } +} +} From ccbab7e851924751993e3052a784c5efe0723210 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Thu, 17 Sep 2015 18:06:01 -0500 Subject: [PATCH 6/9] Major re-work of the RegisteredStringMap --- inc/osvr/Common/RegisteredStringMap.h | 59 ++++------ src/osvr/Common/RegisteredStringMap.cpp | 137 +++++++----------------- 2 files changed, 60 insertions(+), 136 deletions(-) diff --git a/inc/osvr/Common/RegisteredStringMap.h b/inc/osvr/Common/RegisteredStringMap.h index f4beac7da..5ef51d620 100644 --- a/inc/osvr/Common/RegisteredStringMap.h +++ b/inc/osvr/Common/RegisteredStringMap.h @@ -38,62 +38,47 @@ namespace osvr { namespace common { - /// map - typedef std::map RegistryList; - - /// @todo change this to serialized bytestream in the future - typedef Json::Value SerializedStringMap; - /// Centralize a string registry. Basically, the server side, and part /// of the client side internals. class RegisteredStringMap { public: - /// @brief Constructor - OSVR_COMMON_EXPORT RegisteredStringMap(); - - OSVR_COMMON_EXPORT ~RegisteredStringMap(); - /// retrieve the ID for the current name or register new ID and return /// that OSVR_COMMON_EXPORT util::StringID getStringID(std::string const &str); /// retrieve the name of the string given the ID /// returns empty string if nothing found - OSVR_COMMON_EXPORT std::string getNameFromID(util::StringID &id) const; - - /// package the entire (current) map into bytestream and return its copy - /// will be used to transport of maps between server and client - OSVR_COMMON_EXPORT SerializedStringMap getMap() const; - - /// add new entry to the string map and return new ID - OSVR_COMMON_EXPORT util::StringID - registerStringID(std::string const &str); + OSVR_COMMON_EXPORT std::string getStringFromId(util::StringID id) const; - OSVR_COMMON_EXPORT bool isUpdateAvailable(); + /// Has a new entry been added since the flag was last cleared? + OSVR_COMMON_EXPORT bool isModified() const; + /// Clear the modified flag + OSVR_COMMON_EXPORT void clearModifiedFlag(); OSVR_COMMON_EXPORT void printCurrentMap(); + OSVR_COMMON_EXPORT std::vector getEntries() const; + protected: - /// keep track of number of entries in the registry, - /// may not be needed if we stick with vectors - int m_numEntries; - RegistryList m_regEntries; + std::vector m_regEntries; /// special flag that gets switched whenever new element is inserted; - bool m_updateMap; + bool m_modified = false; }; /// This is like a RegisteredStringMap, except it also knows that some peer /// also has a string map, likely with some of the same strings, but with /// different ids. Used in reconciliation between server and client since - /// they are - /// separate entities - class CorrelatedStringMap : public RegisteredStringMap { + /// they are separate entities + class CorrelatedStringMap { public: - /// @brief Constructor - OSVR_COMMON_EXPORT CorrelatedStringMap(); + /// retrieve the ID for the current name or register new ID and return + /// that + OSVR_COMMON_EXPORT util::StringID getStringID(std::string const &str); - OSVR_COMMON_EXPORT ~CorrelatedStringMap(); + /// retrieve the name of the string given the ID + /// returns empty string if nothing found + OSVR_COMMON_EXPORT std::string getStringFromId(util::StringID id) const; /// This is the extra method used by clients, to convert from server's /// ids. Will return NULL if peerID to Local ID mapping doesn't exist @@ -101,15 +86,13 @@ namespace common { convertPeerToLocalID(util::PeerStringID peerID) const; /// This populates the data structure used by the above method. - OSVR_COMMON_EXPORT void setupPeerMappings(SerializedStringMap peerdata); - - /// This will add the mapping or ignore it if it's present - void addPeerToLocalMapping(util::PeerStringID peerID, - util::StringID localID); + OSVR_COMMON_EXPORT void + setupPeerMappings(std::vector const &peerEntries); private: + RegisteredStringMap m_local; /// keeps the peer to local string ID mappings - std::vector> mappings; + std::vector m_remoteToLocal; }; } // namespace common } // namespace osvr diff --git a/src/osvr/Common/RegisteredStringMap.cpp b/src/osvr/Common/RegisteredStringMap.cpp index 738d47ba9..ee416226d 100644 --- a/src/osvr/Common/RegisteredStringMap.cpp +++ b/src/osvr/Common/RegisteredStringMap.cpp @@ -35,135 +35,76 @@ namespace osvr { namespace common { - /// @brief set the initial number of entries to zero, and flag to update the - /// Map (since it's new) - RegisteredStringMap::RegisteredStringMap() - : m_numEntries(0), m_updateMap(true) {} - - /// @todo add proper destructor - RegisteredStringMap::~RegisteredStringMap() {} - /// @brief helper function to print size and contents of the map void RegisteredStringMap::printCurrentMap() { - + auto n = m_regEntries.size(); std::cout << "Current map contains " << m_regEntries.size() << " entries: " << std::endl; - for (auto &entry : m_regEntries) { - std::cout << "ID: " << entry.second.value() << "; " - << "Name: " << entry.first << std::endl; + for (decltype(n) i = 0; i < n; ++i) { + std::cout << "ID: " << i << "; " + << "Name: " << m_regEntries[i] << std::endl; } } - SerializedStringMap RegisteredStringMap::getMap() const { - - Json::Value serializedMap; - - for (auto &entry : m_regEntries) { - - serializedMap[entry.first] = entry.second.value(); - } - return serializedMap; - } - - util::StringID - RegisteredStringMap::registerStringID(std::string const &str) { - - // we've checked the entries before and haven't found so we'll just add - // new one - std::string name = str; - util::StringID newID(m_regEntries.size()); - - m_regEntries.insert(std::make_pair(name, newID)); - m_numEntries++; - - m_updateMap = true; - return newID; - } - util::StringID RegisteredStringMap::getStringID(std::string const &str) { - - // check the existing registry first - for (auto &entry : m_regEntries) { - // found a matching name, NOTE: CaSe Sensitive - if (boost::equals(str, entry.first)) { - m_updateMap = false; - return entry.second; - } + auto entry = std::find(begin(m_regEntries), end(m_regEntries), str); + if (end(m_regEntries) != entry) { + // we found it. + return util::StringID(std::distance(begin(m_regEntries), entry)); } // we didn't find an entry in the registry so we'll add a new one - return registerStringID(str); + auto ret = util::StringID( + m_regEntries.size()); // will be the location of the next insert. + m_regEntries.push_back(str); + m_modified = true; + return ret; } - std::string RegisteredStringMap::getNameFromID(util::StringID &id) const { + std::string RegisteredStringMap::getStringFromId(util::StringID id) const { // requested non-existent ID (include sanity check) if (id.value() >= m_regEntries.size()) { // returning empty string + /// @todo should we throw here? return std::string(); } - // entries should be ordered 0-.. with new ones - // appending to the end, so we should be safe at pulling by vector index - - for (auto &entry : m_regEntries) { - if (entry.second == id) { - // found name for this ID - return entry.first; - } - } - // returning empty string - return std::string(); + return m_regEntries[id.value()]; }; - bool RegisteredStringMap::isUpdateAvailable() { return m_updateMap; } + bool RegisteredStringMap::isModified() const { return m_modified; } + void RegisteredStringMap::clearModifiedFlag() { m_modified = false; } + std::vector RegisteredStringMap::getEntries() const { + return m_regEntries; + } - CorrelatedStringMap::CorrelatedStringMap() {} + util::StringID CorrelatedStringMap::getStringID(std::string const &str) { + return m_local.getStringID(str); + } - /// @todo add proper destructor - CorrelatedStringMap::~CorrelatedStringMap() {} + std::string CorrelatedStringMap::getStringFromId(util::StringID id) const { + return m_local.getStringFromId(id); + } util::StringID CorrelatedStringMap::convertPeerToLocalID(util::PeerStringID peerID) const { - - // go thru the mappings and return an empty StringID if nothing's found - for (auto &mapping : mappings) { - - if (mapping.first == peerID) { - return mapping.second; - } + if (peerID.empty()) { + return util::StringID(); } - - return util::StringID(); - } - - void CorrelatedStringMap::addPeerToLocalMapping(util::PeerStringID peerID, - util::StringID localID) { - - // there should be 1 to 1 mapping between peer and local IDs, - // so if we find one, it should be correct - for (auto &mapping : mappings) { - // got a match - if ((mapping.first == peerID) && (mapping.second == localID)) { - return; - } + if (peerID.value() >= m_remoteToLocal.size()) { + throw std::out_of_range("Peer ID out of range!"); } - // add new mapping - mappings.push_back(std::make_pair(peerID, localID)); + return util::StringID(m_remoteToLocal[peerID.value()]); } - void CorrelatedStringMap::setupPeerMappings(SerializedStringMap peerData) { - - // go thru the peerData, you get name and id - // this name may already be stored in correlatedMap - // so we get the localID first (or register it) - // then store it in the mappings - - for (auto &name : peerData.getMemberNames()) { - - util::PeerStringID peerID(peerData[name].asUInt()); - util::StringID localID = getStringID(name); - addPeerToLocalMapping(peerID, localID); + void CorrelatedStringMap::setupPeerMappings( + std::vector const &peerEntries) { + m_remoteToLocal.clear(); + auto n = peerEntries.size(); + for (uint32_t i = 0; i < n; ++i) { + m_remoteToLocal.push_back( + m_local.getStringID(peerEntries[i]).value()); } } } From a6dabcb82b2e7e8be8fb07ce009c50434162c30f Mon Sep 17 00:00:00 2001 From: Georgiy Frolov Date: Mon, 21 Sep 2015 18:34:27 -0400 Subject: [PATCH 7/9] add unit tests for registered string map --- tests/cplusplus/Common/CMakeLists.txt | 1 + tests/cplusplus/Common/RegStringMap.cpp | 137 ++++++++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 tests/cplusplus/Common/RegStringMap.cpp diff --git a/tests/cplusplus/Common/CMakeLists.txt b/tests/cplusplus/Common/CMakeLists.txt index a5b0bb854..9adee405a 100644 --- a/tests/cplusplus/Common/CMakeLists.txt +++ b/tests/cplusplus/Common/CMakeLists.txt @@ -15,6 +15,7 @@ endif() add_executable(TestCommon DummyTree.h PathTreeResolution.cpp + RegStringMap.cpp Serialization.cpp SerializationExamples.cpp "${PROJECT_SOURCE_DIR}/examples/internals/SerializationTraitExample_Simple.h" diff --git a/tests/cplusplus/Common/RegStringMap.cpp b/tests/cplusplus/Common/RegStringMap.cpp new file mode 100644 index 000000000..e05906ab7 --- /dev/null +++ b/tests/cplusplus/Common/RegStringMap.cpp @@ -0,0 +1,137 @@ +/** @file + @brief Implementation + + @date 2015 + + @author + Sensics, Inc. + +*/ + +// Copyright 2015 Sensics, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Internal Includes +#include + +// Library/third-party includes +#include "gtest/gtest.h" + +// Standard includes +#include + +using osvr::util::StringID; +using osvr::util::PeerStringID; +using osvr::common::RegisteredStringMap; +using osvr::common::CorrelatedStringMap; + +class RegisteredStringMapTest : public ::testing::Test { + public: + RegisteredStringMapTest() {} + + RegisteredStringMap regMap; + CorrelatedStringMap corMap; + + StringID regID0, regID1, regID2; + StringID corID0, corID1, corID2; +}; + +TEST(RegisteredStringMap, create) { + + RegisteredStringMap regMap; + ASSERT_EQ(0, regMap.getEntries().size()); + ASSERT_FALSE(regMap.isModified()); +} + +TEST_F(RegisteredStringMapTest, addNewValues) { + + regID0 = regMap.getStringID("RegVal0"); + ASSERT_TRUE(regMap.isModified()); + ASSERT_EQ(1, regMap.getEntries().size()); + + regID1 = regMap.getStringID("RegVal1"); + ASSERT_TRUE(regMap.isModified()); + ASSERT_EQ(2, regMap.getEntries().size()); + + regID2 = regMap.getStringID("RegVal2"); + ASSERT_TRUE(regMap.isModified()); + ASSERT_EQ(3, regMap.getEntries().size()); +} + +TEST_F(RegisteredStringMapTest, checkExistingValues) { + + regMap.clearModifiedFlag(); + + StringID regID = regMap.getStringID("RegVal0"); + ASSERT_FALSE(regMap.isModified()); + ASSERT_EQ(3, regMap.getEntries().size()); + ASSERT_EQ(0, regID.value()); + + regID = regMap.getStringID("RegVal1"); + ASSERT_FALSE(regMap.isModified()); + ASSERT_EQ(3, regMap.getEntries().size()); + ASSERT_EQ(1, regID.value()); + + regID = regMap.getStringID("RegVal2"); + ASSERT_FALSE(regMap.isModified()); + ASSERT_EQ(3, regMap.getEntries().size()); + ASSERT_EQ(2, regID.value()); +} + +TEST_F(RegisteredStringMapTest, getValues) { + + ASSERT_STREQ("RegVal0", regMap.getStringFromId(regID0).c_str()); + ASSERT_STREQ("RegVal1", regMap.getStringFromId(regID1).c_str()); + ASSERT_STREQ("RegVal2", regMap.getStringFromId(regID2).c_str()); + ASSERT_EQ(0, std::strlen(regMap.getStringFromId(StringID(1000)).c_str())); + + ASSERT_STREQ("CorVal0", corMap.getStringFromId(corID0).c_str()); + ASSERT_STREQ("CorVal1", corMap.getStringFromId(corID1).c_str()); + ASSERT_STREQ("CorVal2", corMap.getStringFromId(corID2).c_str()); + ASSERT_EQ(0, std::strlen(corMap.getStringFromId(StringID(1000)).c_str())); +} + +TEST_F(RegisteredStringMapTest, getEntries) { + + auto entries = regMap.getEntries(); + ASSERT_EQ(3, entries.size()); + ASSERT_STREQ("RegVal0", entries[0].c_str()); + ASSERT_STREQ("RegVal1", entries[1].c_str()); + ASSERT_STREQ("RegVal2", entries[2].c_str()); +} + +TEST_F(RegisteredStringMapTest, checkModified) { + regMap.clearModifiedFlag(); + ASSERT_FALSE(regMap.isModified()); +} + +TEST_F(RegisteredStringMapTest, checkEmptyPeerMapping) { + + StringID emptID = corMap.convertPeerToLocalID(PeerStringID(100)); + ASSERT_TRUE(emptID.empty()); +} + +TEST_F(RegisteredStringMapTest, checkSetupPeerMappings) { + + auto entries = regMap.getEntries(); + corMap.setupPeerMappings(entries); + + StringID corID3 = corMap.convertPeerToLocalID(PeerStringID(regID0.value())); + StringID corID4 = corMap.convertPeerToLocalID(PeerStringID(regID1.value())); + StringID corID5 = corMap.convertPeerToLocalID(PeerStringID(regID2.value())); + + ASSERT_STREQ("RegVal0", corMap.getStringFromId(corID3).c_str()); + ASSERT_STREQ("RegVal1", corMap.getStringFromId(corID4).c_str()); + ASSERT_STREQ("RegVal2", corMap.getStringFromId(corID5).c_str()); +} From b15b8fa6cf6c5a1115148decd466b42081b1be38 Mon Sep 17 00:00:00 2001 From: Georgiy Frolov Date: Mon, 21 Sep 2015 18:55:30 -0400 Subject: [PATCH 8/9] add SetUp function, add additional test --- tests/cplusplus/Common/RegStringMap.cpp | 28 +++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/tests/cplusplus/Common/RegStringMap.cpp b/tests/cplusplus/Common/RegStringMap.cpp index e05906ab7..e7cc2fd3c 100644 --- a/tests/cplusplus/Common/RegStringMap.cpp +++ b/tests/cplusplus/Common/RegStringMap.cpp @@ -38,7 +38,15 @@ using osvr::common::CorrelatedStringMap; class RegisteredStringMapTest : public ::testing::Test { public: - RegisteredStringMapTest() {} + virtual void SetUp() { + regID0 = regMap.getStringID("RegVal0"); + regID1 = regMap.getStringID("RegVal1"); + regID2 = regMap.getStringID("RegVal2"); + + corID0 = corMap.getStringID("CorVal0"); + corID1 = corMap.getStringID("CorVal1"); + corID2 = corMap.getStringID("CorVal2"); + } RegisteredStringMap regMap; CorrelatedStringMap corMap; @@ -54,17 +62,19 @@ TEST(RegisteredStringMap, create) { ASSERT_FALSE(regMap.isModified()); } -TEST_F(RegisteredStringMapTest, addNewValues) { +TEST(RegisteredStringMap, addNewValues) { + RegisteredStringMap regMap; + CorrelatedStringMap corMap; - regID0 = regMap.getStringID("RegVal0"); + StringID regID0 = regMap.getStringID("RegVal0"); ASSERT_TRUE(regMap.isModified()); ASSERT_EQ(1, regMap.getEntries().size()); - regID1 = regMap.getStringID("RegVal1"); + StringID regID1 = regMap.getStringID("RegVal1"); ASSERT_TRUE(regMap.isModified()); ASSERT_EQ(2, regMap.getEntries().size()); - regID2 = regMap.getStringID("RegVal2"); + StringID regID2 = regMap.getStringID("RegVal2"); ASSERT_TRUE(regMap.isModified()); ASSERT_EQ(3, regMap.getEntries().size()); } @@ -116,9 +126,15 @@ TEST_F(RegisteredStringMapTest, checkModified) { ASSERT_FALSE(regMap.isModified()); } +TEST_F(RegisteredStringMapTest, checkOutOfRangePeerID) { + + ASSERT_THROW(corMap.convertPeerToLocalID(PeerStringID(100)), + std::out_of_range); +} + TEST_F(RegisteredStringMapTest, checkEmptyPeerMapping) { - StringID emptID = corMap.convertPeerToLocalID(PeerStringID(100)); + StringID emptID = corMap.convertPeerToLocalID(PeerStringID()); ASSERT_TRUE(emptID.empty()); } From 35ab745139d90aad9c07d5b7fee52b645bfcff89 Mon Sep 17 00:00:00 2001 From: Georgiy Frolov Date: Tue, 22 Sep 2015 12:37:08 -0400 Subject: [PATCH 9/9] move fixture down after separate tests, use constructor instead of SetUp function, remove unused lines, use _eq not _streq for c++ str --- tests/cplusplus/Common/RegStringMap.cpp | 47 ++++++++++++------------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/tests/cplusplus/Common/RegStringMap.cpp b/tests/cplusplus/Common/RegStringMap.cpp index e7cc2fd3c..044eadf9a 100644 --- a/tests/cplusplus/Common/RegStringMap.cpp +++ b/tests/cplusplus/Common/RegStringMap.cpp @@ -36,25 +36,6 @@ using osvr::util::PeerStringID; using osvr::common::RegisteredStringMap; using osvr::common::CorrelatedStringMap; -class RegisteredStringMapTest : public ::testing::Test { - public: - virtual void SetUp() { - regID0 = regMap.getStringID("RegVal0"); - regID1 = regMap.getStringID("RegVal1"); - regID2 = regMap.getStringID("RegVal2"); - - corID0 = corMap.getStringID("CorVal0"); - corID1 = corMap.getStringID("CorVal1"); - corID2 = corMap.getStringID("CorVal2"); - } - - RegisteredStringMap regMap; - CorrelatedStringMap corMap; - - StringID regID0, regID1, regID2; - StringID corID0, corID1, corID2; -}; - TEST(RegisteredStringMap, create) { RegisteredStringMap regMap; @@ -64,7 +45,6 @@ TEST(RegisteredStringMap, create) { TEST(RegisteredStringMap, addNewValues) { RegisteredStringMap regMap; - CorrelatedStringMap corMap; StringID regID0 = regMap.getStringID("RegVal0"); ASSERT_TRUE(regMap.isModified()); @@ -79,6 +59,25 @@ TEST(RegisteredStringMap, addNewValues) { ASSERT_EQ(3, regMap.getEntries().size()); } +class RegisteredStringMapTest : public ::testing::Test { + public: + RegisteredStringMapTest() { + regID0 = regMap.getStringID("RegVal0"); + regID1 = regMap.getStringID("RegVal1"); + regID2 = regMap.getStringID("RegVal2"); + + corID0 = corMap.getStringID("CorVal0"); + corID1 = corMap.getStringID("CorVal1"); + corID2 = corMap.getStringID("CorVal2"); + } + + RegisteredStringMap regMap; + CorrelatedStringMap corMap; + + StringID regID0, regID1, regID2; + StringID corID0, corID1, corID2; +}; + TEST_F(RegisteredStringMapTest, checkExistingValues) { regMap.clearModifiedFlag(); @@ -101,10 +100,10 @@ TEST_F(RegisteredStringMapTest, checkExistingValues) { TEST_F(RegisteredStringMapTest, getValues) { - ASSERT_STREQ("RegVal0", regMap.getStringFromId(regID0).c_str()); - ASSERT_STREQ("RegVal1", regMap.getStringFromId(regID1).c_str()); - ASSERT_STREQ("RegVal2", regMap.getStringFromId(regID2).c_str()); - ASSERT_EQ(0, std::strlen(regMap.getStringFromId(StringID(1000)).c_str())); + ASSERT_EQ("RegVal0", regMap.getStringFromId(regID0)); + ASSERT_EQ("RegVal1", regMap.getStringFromId(regID1)); + ASSERT_EQ("RegVal2", regMap.getStringFromId(regID2)); + ASSERT_TRUE(regMap.getStringFromId(StringID(1000)).empty()); ASSERT_STREQ("CorVal0", corMap.getStringFromId(corID0).c_str()); ASSERT_STREQ("CorVal1", corMap.getStringFromId(corID1).c_str());