diff --git a/groups/nts/ntsa/ntsa_endpoint.cpp b/groups/nts/ntsa/ntsa_endpoint.cpp index 04e5175b..c62914a7 100644 --- a/groups/nts/ntsa/ntsa_endpoint.cpp +++ b/groups/nts/ntsa/ntsa_endpoint.cpp @@ -224,5 +224,49 @@ bsl::ostream& Endpoint::print(bsl::ostream& stream, return stream; } +const bdlat_SelectionInfo* Endpoint::lookupSelectionInfo(int id) +{ + const int numSelections = + sizeof(SELECTION_INFO_ARRAY) / sizeof(SELECTION_INFO_ARRAY[0]); + + if (id < 0 || id >= numSelections) { + return 0; + } + + return &SELECTION_INFO_ARRAY[id]; +} + +const bdlat_SelectionInfo* Endpoint::lookupSelectionInfo( + const char* name, + int nameLength) +{ + const bsl::size_t numSelections = + sizeof(SELECTION_INFO_ARRAY) / sizeof(SELECTION_INFO_ARRAY[0]); + + for (bsl::size_t i = 0; i < numSelections; ++i) { + const bdlat_SelectionInfo& selectionInfo = SELECTION_INFO_ARRAY[i]; + if (selectionInfo.d_nameLength == nameLength) { + const int compare = + bsl::memcmp(selectionInfo.d_name_p, name, nameLength); + if (compare == 0) { + return &selectionInfo; + } + } + } + + return 0; +} + +const char Endpoint::CLASS_NAME[15] = "ntsa::Endpoint"; + +// clang-format off +const bdlat_SelectionInfo Endpoint::SELECTION_INFO_ARRAY[3] = +{ + { ntsa::EndpointType::e_UNDEFINED, "undefined", 9, "", 0 }, + { ntsa::EndpointType::e_IP, "ip", 2, "", 0 }, + { ntsa::EndpointType::e_LOCAL, "local", 5, "", 0 } +}; +// clang-format on + } // close package namespace } // close enterprise namespace diff --git a/groups/nts/ntsa/ntsa_endpoint.h b/groups/nts/ntsa/ntsa_endpoint.h index d647f767..b178f652 100644 --- a/groups/nts/ntsa/ntsa_endpoint.h +++ b/groups/nts/ntsa/ntsa_endpoint.h @@ -27,6 +27,9 @@ BSLS_IDENT("$Id: $") #include #include #include +#include +#include +#include #include #include #include @@ -93,6 +96,10 @@ class Endpoint ntsa::EndpointType::Value d_type; public: + /// Defines a type alias for the base serialization type customized by this + /// type. + typedef bslstl::StringRef BaseType; + /// Create a new endpoint having an undefined type. Endpoint(); @@ -254,6 +261,51 @@ class Endpoint int level = 0, int spacesPerLevel = 4) const; + /// Set the value of this object to be the default for the selection + /// indicated by the specified 'id'. Return 0 on success, and non-zero + /// value otherwise (i.e., the selection is not found). + int makeSelection(int id); + + /// Set the value of this object to be the default for the selection + /// indicated by the specified 'name' of the specified 'nameLength'. + /// Return 0 on success, and non-zero value otherwise (i.e., the selection + /// is not found). + int makeSelection(const char* name, int nameLength); + + /// Return the selection ID of the current selection in the choice. + int selectionId() const; + + /// Invoke the specified 'manipulator' on the address of the modifiable + /// selection, supplying 'manipulator' with the corresponding selection + /// information structure. Return the value returned from the invocation + /// of 'manipulator' if this object has a defined selection, and -1 + /// otherwise. + template + int manipulateSelection(MANIPULATOR& manipulator); + + /// Invoke the specified 'accessor' on the non-modifiable selection, + /// supplying 'accessor' with the corresponding selection information + /// structure. Return the value returned from the invocation of 'accessor' + /// if this object has a defined selection, and -1 otherwise. + template + int accessSelection(ACCESSOR& accessor) const; + + /// Return the compiler-independant name for this class. + static const char CLASS_NAME[15]; + + /// The selection info array, indexed by selection index. + static const bdlat_SelectionInfo SELECTION_INFO_ARRAY[3]; + + /// Return selection information for the selection indicated by the + /// specified 'id' if the selection exists, and 0 otherwise. + static const bdlat_SelectionInfo* lookupSelectionInfo(int id); + + /// Return selection information for the selection indicated by the + /// specified 'name' of the specified 'nameLength' if the selection + /// exists, and 0 otherwise. + static const bdlat_SelectionInfo* lookupSelectionInfo( + const char* name, int nameLength); + /// Defines the traits of this type. These traits can be used to select, /// at compile-time, the most efficient algorithm to manipulate objects /// of this type. @@ -552,6 +604,107 @@ void hashAppend(HASH_ALGORITHM& algorithm, const Endpoint& value) } } +NTSCFG_INLINE +int Endpoint::makeSelection(int id) +{ + switch (id) { + case ntsa::EndpointType::e_UNDEFINED: + this->reset(); + break; + case ntsa::EndpointType::e_IP: + this->makeIp(); + break; + case ntsa::EndpointType::e_LOCAL: + this->makeLocal(); + break; + default: + return -1; + } + + return 0; +} + +NTSCFG_INLINE +int Endpoint::makeSelection(const char* name, int nameLength) +{ + const bdlat_SelectionInfo *selectionInfo = + ntsa::Endpoint::lookupSelectionInfo(name, nameLength); + if (selectionInfo == 0) { + return -1; + } + + return this->makeSelection(selectionInfo->d_id); +} + +NTSCFG_INLINE +int Endpoint::selectionId() const +{ + return static_cast(d_type); +} + +template +int Endpoint::manipulateSelection(MANIPULATOR& manipulator) +{ + int rc; + + if (d_type == ntsa::EndpointType::e_UNDEFINED) { + ; + } + else if (d_type == ntsa::EndpointType::e_IP) { + rc = manipulator(&d_ip.object(), SELECTION_INFO_ARRAY[d_type]); + if (rc != 0) { + return rc; + } + } + else if (d_type == ntsa::EndpointType::e_LOCAL) { + rc = manipulator(&d_local.object(), SELECTION_INFO_ARRAY[d_type]); + if (rc != 0) { + return rc; + } + } + else { + return -1; + } + + return 0; +} + +template +int Endpoint::accessSelection(ACCESSOR& accessor) const +{ + int rc; + + const bdlat_SelectionInfo *selectionInfo = + ntsa::Endpoint::lookupSelectionInfo(d_type); + if (selectionInfo == 0) { + return -1; + } + + if (d_type == ntsa::EndpointType::e_UNDEFINED) { + ; + } + else if (d_type == ntsa::EndpointType::e_IP) { + rc = accessor(d_ip.object(), SELECTION_INFO_ARRAY[d_type]); + if (rc != 0) { + return rc; + } + } + else if (d_type == ntsa::EndpointType::e_LOCAL) { + rc = accessor(d_local.object(), SELECTION_INFO_ARRAY[d_type]); + if (rc != 0) { + return rc; + } + } + else { + return -1; + } + + return 0; +} + } // close package namespace + +BDLAT_DECL_CHOICE_TRAITS(ntsa::Endpoint) + } // close enterprise namespace #endif diff --git a/groups/nts/ntsa/ntsa_endpoint.t.cpp b/groups/nts/ntsa/ntsa_endpoint.t.cpp index 84619065..e9bcf7d8 100644 --- a/groups/nts/ntsa/ntsa_endpoint.t.cpp +++ b/groups/nts/ntsa/ntsa_endpoint.t.cpp @@ -15,6 +15,12 @@ #include #include +#include +#include +#include +#include +#include +#include #include #include @@ -200,10 +206,114 @@ NTSCFG_TEST_CASE(3) } } +NTSCFG_TEST_CASE(4) +{ + int rc; + + ntscfg::TestAllocator ta; + { + ntsa::Endpoint e1("10.26.55.100:12345"); + ntsa::Endpoint e2; + + bdlsb::MemOutStreamBuf osb(&ta); + + balber::BerEncoder encoder(0, &ta); + rc = encoder.encode(&osb, e1); + if (rc != 0) { + NTSCFG_TEST_LOG_DEBUG << encoder.loggedMessages() + << NTSCFG_TEST_LOG_END; + + NTSCFG_TEST_EQ(rc, 0); + } + + rc = osb.pubsync(); + NTSCFG_TEST_EQ(rc, 0); + + NTSCFG_TEST_GT(osb.length(), 0); + NTSCFG_TEST_NE(osb.data(), 0); + + NTSCFG_TEST_LOG_DEBUG << "Encoded:\n" + << bdlb::PrintStringHexDumper( + osb.data(), + static_cast(osb.length())) + << NTSCFG_TEST_LOG_END; + + bdlsb::FixedMemInStreamBuf isb(osb.data(), osb.length()); + + balber::BerDecoder decoder(0, &ta); + rc = decoder.decode(&isb, &e2); + if (rc != 0) { + NTSCFG_TEST_LOG_DEBUG << encoder.loggedMessages() + << NTSCFG_TEST_LOG_END; + + NTSCFG_TEST_EQ(rc, 0); + } + + NTSCFG_TEST_EQ(e2, e1); + } + NTSCFG_TEST_EQ(ta.numBlocksInUse(), 0); +} + +NTSCFG_TEST_CASE(5) +{ + int rc; + + ntscfg::TestAllocator ta; + { + bsl::vector e1(&ta); + bsl::vector e2(&ta); + + e1.push_back(ntsa::Endpoint("10.26.55.100:12345")); + + bdlsb::MemOutStreamBuf osb; + + baljsn::Encoder encoder(&ta); + rc = encoder.encode(&osb, e1); + if (rc != 0) { + NTSCFG_TEST_LOG_DEBUG << encoder.loggedMessages() + << NTSCFG_TEST_LOG_END; + + NTSCFG_TEST_EQ(rc, 0); + } + + rc = osb.pubsync(); + NTSCFG_TEST_EQ(rc, 0); + + NTSCFG_TEST_GT(osb.length(), 0); + NTSCFG_TEST_NE(osb.data(), 0); + + NTSCFG_TEST_LOG_DEBUG << "Encoded: " + << bsl::string_view( + osb.data(), + static_cast(osb.length())) + << NTSCFG_TEST_LOG_END; + + bdlsb::FixedMemInStreamBuf isb(osb.data(), osb.length()); + + baljsn::Decoder decoder(&ta); + rc = decoder.decode(&isb, &e2); + if (rc != 0) { + NTSCFG_TEST_LOG_DEBUG << encoder.loggedMessages() + << NTSCFG_TEST_LOG_END; + + NTSCFG_TEST_EQ(rc, 0); + } + + NTSCFG_TEST_EQ(e2.size(), e1.size()); + + for (bsl::size_t i = 0; i < e1.size(); ++i) { + NTSCFG_TEST_EQ(e2[i], e1[i]); + } + } + NTSCFG_TEST_EQ(ta.numBlocksInUse(), 0); +} + NTSCFG_TEST_DRIVER { NTSCFG_TEST_REGISTER(1); NTSCFG_TEST_REGISTER(2); NTSCFG_TEST_REGISTER(3); + NTSCFG_TEST_REGISTER(4); + NTSCFG_TEST_REGISTER(5); } NTSCFG_TEST_DRIVER_END; diff --git a/groups/nts/ntsa/ntsa_ipendpoint.cpp b/groups/nts/ntsa/ntsa_ipendpoint.cpp index fd95e811..6900f8b9 100644 --- a/groups/nts/ntsa/ntsa_ipendpoint.cpp +++ b/groups/nts/ntsa/ntsa_ipendpoint.cpp @@ -330,5 +330,48 @@ bool operator<(const IpEndpoint& lhs, const IpEndpoint& rhs) return lhs.less(rhs); } +const bdlat_AttributeInfo* IpEndpoint::lookupAttributeInfo(int id) +{ + const int numAttributes = + sizeof(ATTRIBUTE_INFO_ARRAY) / sizeof(ATTRIBUTE_INFO_ARRAY[0]); + + if (id < 0 || id >= numAttributes) { + return 0; + } + + return &ATTRIBUTE_INFO_ARRAY[id]; +} + +const bdlat_AttributeInfo* IpEndpoint::lookupAttributeInfo( + const char* name, + int nameLength) +{ + const bsl::size_t numAttributes = + sizeof(ATTRIBUTE_INFO_ARRAY) / sizeof(ATTRIBUTE_INFO_ARRAY[0]); + + for (bsl::size_t i = 0; i < numAttributes; ++i) { + const bdlat_AttributeInfo& attributeInfo = ATTRIBUTE_INFO_ARRAY[i]; + if (attributeInfo.d_nameLength == nameLength) { + const int compare = + bsl::memcmp(attributeInfo.d_name_p, name, nameLength); + if (compare == 0) { + return &attributeInfo; + } + } + } + + return 0; +} + +const char IpEndpoint::CLASS_NAME[17] = "ntsa::IpEndpoint"; + +// clang-format off +const bdlat_AttributeInfo IpEndpoint::ATTRIBUTE_INFO_ARRAY[2] = +{ + { e_ATTRIBUTE_ID_HOST, "host", 4, "", 0 }, + { e_ATTRIBUTE_ID_PORT, "port", 4, "", 0 }, +}; +// clang-format on + } // close package namespace } // close enterprise namespace diff --git a/groups/nts/ntsa/ntsa_ipendpoint.h b/groups/nts/ntsa/ntsa_ipendpoint.h index 6c8d0631..c93c8baa 100644 --- a/groups/nts/ntsa/ntsa_ipendpoint.h +++ b/groups/nts/ntsa/ntsa_ipendpoint.h @@ -23,6 +23,10 @@ BSLS_IDENT("$Id: $") #include #include #include +#include +#include +#include +#include #include #include #include @@ -63,6 +67,11 @@ namespace ntsa { /// @ingroup module_ntsa_identity class IpEndpoint { + enum { + e_ATTRIBUTE_ID_HOST = 0, + e_ATTRIBUTE_ID_PORT = 1 + }; + ntsa::IpAddress d_host; ntsa::Port d_port; @@ -180,6 +189,61 @@ class IpEndpoint int level = 0, int spacesPerLevel = 4) const; + /// Invoke the specified 'manipulator' sequentially on the address of each + /// (modifiable) attribute of this object, supplying 'manipulator' with + /// the corresponding attribute information structure until such + /// invocation returns a non-zero value. Return the value from the last + /// invocation of 'manipulator' (i.e., the invocation that terminated the + /// sequence). + template + int manipulateAttributes(MANIPULATOR& manipulator); + + /// Invoke the specified 'manipulator' on the address of the (modifiable) + /// attribute indicated by the specified 'id', supplying 'manipulator' + /// with the corresponding attribute information structure. Return the + /// value returned from the invocation of 'manipulator' if 'id' identifies + /// an attribute of this class, and -1 otherwise. + template + int manipulateAttribute(MANIPULATOR& manipulator, int id); + + /// Invoke the specified 'manipulator' on the address of the (modifiable) + /// attribute indicated by the specified 'name' of the specified + /// 'nameLength', supplying 'manipulator' with the corresponding attribute + /// information structure. Return the value returned from the invocation + /// of 'manipulator' if 'name' identifies an attribute of this class, and + /// -1 otherwise. + template + int manipulateAttribute(MANIPULATOR& manipulator, + const char* name, + int nameLength); + + /// Invoke the specified 'accessor' sequentially on each (non-modifiable) + /// attribute of this object, supplying 'accessor' with the corresponding + /// attribute information structure until such invocation returns a + /// non-zero value. Return the value from the last invocation of + /// 'accessor' (i.e., the invocation that terminated the sequence). + template + int accessAttributes(ACCESSOR& accessor) const; + + /// Invoke the specified 'accessor' on the (non-modifiable) attribute of + /// this object indicated by the specified 'id', supplying 'accessor' with + /// the corresponding attribute information structure. Return the value + /// returned from the invocation of 'accessor' if 'id' identifies an + /// attribute of this class, and -1 otherwise. + template + int accessAttribute(ACCESSOR& accessor, int id) const; + + /// Invoke the specified 'accessor' on the (non-modifiable) attribute of + /// this object indicated by the specified 'name' of the specified + /// 'nameLength', supplying 'accessor' with the corresponding attribute + /// information structure. Return the value returned from the invocation + /// of 'accessor' if 'name' identifies an attribute of this class, and -1 + /// otherwise. + template + int accessAttribute(ACCESSOR& accessor, + const char* name, + int nameLength) const; + /// Return the IPv4 address that represents any address. static ntsa::IpAddress anyIpv4Address(); @@ -204,6 +268,22 @@ class IpEndpoint /// Return the port number that represents any port. static ntsa::Port anyPort(); + /// Return attribute information for the attribute indicated by the + /// specified 'id' if the attribute exists, and 0 otherwise. + static const bdlat_AttributeInfo* lookupAttributeInfo(int id); + + /// Return attribute information for the attribute indicated by the + /// specified 'name' of the specified 'nameLength' if the attribute + /// exists, and 0 otherwise. + static const bdlat_AttributeInfo* lookupAttributeInfo( + const char* name, int nameLength); + + /// Return the compiler-independant name for this class. + static const char CLASS_NAME[17]; + + /// The attribute info array, indexed by attribute index. + static const bdlat_AttributeInfo ATTRIBUTE_INFO_ARRAY[2]; + /// Defines the traits of this type. These traits can be used to select, /// at compile-time, the most efficient algorithm to manipulate objects /// of this type. @@ -350,6 +430,140 @@ void hashAppend(HASH_ALGORITHM& algorithm, const IpEndpoint& value) hashAppend(algorithm, value.port()); } +template +int IpEndpoint::manipulateAttributes(MANIPULATOR& manipulator) +{ + int rc; + + rc = this->manipulateAttribute(manipulator, e_ATTRIBUTE_ID_HOST); + if (rc != 0) { + return rc; + } + + rc = this->manipulateAttribute(manipulator, e_ATTRIBUTE_ID_PORT); + if (rc != 0) { + return rc; + } + + return 0; +} + +template +int IpEndpoint::manipulateAttribute(MANIPULATOR& manipulator, int id) +{ + int rc; + + if (id == e_ATTRIBUTE_ID_HOST) { + bsl::string host; + rc = manipulator(&host, ATTRIBUTE_INFO_ARRAY[id]); + if (rc != 0) { + return rc; + } + + if (!d_host.parse(host)) { + return 1; + } + } + else if (id == e_ATTRIBUTE_ID_PORT) { + bdlb::NullableValue port; + rc = manipulator(&port, ATTRIBUTE_INFO_ARRAY[id]); + if (rc != 0) { + return rc; + } + + if (port.has_value()) { + d_port = port.value(); + } + else { + d_port = 0; + } + } + else { + return -1; + } + + return 0; +} + +template +int IpEndpoint::manipulateAttribute(MANIPULATOR& manipulator, + const char* name, + int nameLength) +{ + const bdlat_AttributeInfo* info = + ntsa::IpEndpoint::lookupAttributeInfo(name, nameLength); + if (info == 0) { + return -1; + } + + return this->manipulateAttribute(manipulator, info->d_id); +} + +template +int IpEndpoint::accessAttributes(ACCESSOR& accessor) const +{ + int rc; + + rc = this->accessAttribute(accessor, e_ATTRIBUTE_ID_HOST); + if (rc != 0) { + return rc; + } + + rc = this->accessAttribute(accessor, e_ATTRIBUTE_ID_PORT); + if (rc != 0) { + return rc; + } + + return 0; +} + +template +int IpEndpoint::accessAttribute(ACCESSOR& accessor, int id) const +{ + int rc; + + if (id == e_ATTRIBUTE_ID_HOST) { + bsl::string host = d_host.text(); + rc = accessor(host, ATTRIBUTE_INFO_ARRAY[id]); + if (rc != 0) { + return rc; + } + } + else if (id == e_ATTRIBUTE_ID_PORT) { + bdlb::NullableValue port; + if (d_port != 0) { + port.makeValue(d_port); + } + + rc = accessor(port, ATTRIBUTE_INFO_ARRAY[id]); + if (rc != 0) { + return rc; + } + } + else { + return -1; + } + + return 0; +} + +template +int IpEndpoint::accessAttribute(ACCESSOR& accessor, + const char* name, + int nameLength) const +{ + const bdlat_AttributeInfo* info = + ntsa::IpEndpoint::lookupAttributeInfo(name, nameLength); + if (info == 0) { + return -1; + } + + return this->accessAttribute(accessor, info->d_id); +} + } // close package namespace + +BDLAT_DECL_SEQUENCE_TRAITS(ntsa::IpEndpoint) + } // close enterprise namespace #endif diff --git a/groups/nts/ntsa/ntsa_ipendpoint.t.cpp b/groups/nts/ntsa/ntsa_ipendpoint.t.cpp index d41b7bc6..8dc5f9cf 100644 --- a/groups/nts/ntsa/ntsa_ipendpoint.t.cpp +++ b/groups/nts/ntsa/ntsa_ipendpoint.t.cpp @@ -15,6 +15,12 @@ #include #include +#include +#include +#include +#include +#include +#include #include using namespace BloombergLP; @@ -57,9 +63,113 @@ NTSCFG_TEST_CASE(2) NTSCFG_TEST_EQ(ipEndpoint.port(), 12345); } +NTSCFG_TEST_CASE(3) +{ + int rc; + + ntscfg::TestAllocator ta; + { + ntsa::IpEndpoint e1("10.26.55.100:12345"); + ntsa::IpEndpoint e2; + + bdlsb::MemOutStreamBuf osb(&ta); + + balber::BerEncoder encoder(0, &ta); + rc = encoder.encode(&osb, e1); + if (rc != 0) { + NTSCFG_TEST_LOG_DEBUG << encoder.loggedMessages() + << NTSCFG_TEST_LOG_END; + + NTSCFG_TEST_EQ(rc, 0); + } + + rc = osb.pubsync(); + NTSCFG_TEST_EQ(rc, 0); + + NTSCFG_TEST_GT(osb.length(), 0); + NTSCFG_TEST_NE(osb.data(), 0); + + NTSCFG_TEST_LOG_DEBUG << "Encoded:\n" + << bdlb::PrintStringHexDumper( + osb.data(), + static_cast(osb.length())) + << NTSCFG_TEST_LOG_END; + + bdlsb::FixedMemInStreamBuf isb(osb.data(), osb.length()); + + balber::BerDecoder decoder(0, &ta); + rc = decoder.decode(&isb, &e2); + if (rc != 0) { + NTSCFG_TEST_LOG_DEBUG << encoder.loggedMessages() + << NTSCFG_TEST_LOG_END; + + NTSCFG_TEST_EQ(rc, 0); + } + + NTSCFG_TEST_EQ(e2, e1); + } + NTSCFG_TEST_EQ(ta.numBlocksInUse(), 0); +} + +NTSCFG_TEST_CASE(4) +{ + int rc; + + ntscfg::TestAllocator ta; + { + bsl::vector e1(&ta); + bsl::vector e2(&ta); + + e1.push_back(ntsa::IpEndpoint("10.26.55.100:12345")); + + bdlsb::MemOutStreamBuf osb(&ta); + + baljsn::Encoder encoder(&ta); + rc = encoder.encode(&osb, e1); + if (rc != 0) { + NTSCFG_TEST_LOG_DEBUG << encoder.loggedMessages() + << NTSCFG_TEST_LOG_END; + + NTSCFG_TEST_EQ(rc, 0); + } + + rc = osb.pubsync(); + NTSCFG_TEST_EQ(rc, 0); + + NTSCFG_TEST_GT(osb.length(), 0); + NTSCFG_TEST_NE(osb.data(), 0); + + NTSCFG_TEST_LOG_DEBUG << "Encoded: " + << bsl::string_view( + osb.data(), + static_cast(osb.length())) + << NTSCFG_TEST_LOG_END; + + bdlsb::FixedMemInStreamBuf isb(osb.data(), osb.length()); + + baljsn::Decoder decoder(&ta); + rc = decoder.decode(&isb, &e2); + if (rc != 0) { + NTSCFG_TEST_LOG_DEBUG << encoder.loggedMessages() + << NTSCFG_TEST_LOG_END; + + NTSCFG_TEST_EQ(rc, 0); + } + + NTSCFG_TEST_EQ(e2.size(), e1.size()); + + for (bsl::size_t i = 0; i < e1.size(); ++i) { + NTSCFG_TEST_EQ(e2[i], e1[i]); + } + } + NTSCFG_TEST_EQ(ta.numBlocksInUse(), 0); +} + NTSCFG_TEST_DRIVER { NTSCFG_TEST_REGISTER(1); NTSCFG_TEST_REGISTER(2); + NTSCFG_TEST_REGISTER(3); + NTSCFG_TEST_REGISTER(4); } NTSCFG_TEST_DRIVER_END; diff --git a/groups/nts/ntsa/ntsa_localname.cpp b/groups/nts/ntsa/ntsa_localname.cpp index cb8c30b7..05f3ccef 100644 --- a/groups/nts/ntsa/ntsa_localname.cpp +++ b/groups/nts/ntsa/ntsa_localname.cpp @@ -275,5 +275,48 @@ ntsa::Error LocalName::generateUnique(ntsa::LocalName* name) return error; } +const bdlat_AttributeInfo* LocalName::lookupAttributeInfo(int id) +{ + const int numAttributes = + sizeof(ATTRIBUTE_INFO_ARRAY) / sizeof(ATTRIBUTE_INFO_ARRAY[0]); + + if (id < 0 || id >= numAttributes) { + return 0; + } + + return &ATTRIBUTE_INFO_ARRAY[id]; +} + +const bdlat_AttributeInfo* LocalName::lookupAttributeInfo( + const char* name, + int nameLength) +{ + const bsl::size_t numAttributes = + sizeof(ATTRIBUTE_INFO_ARRAY) / sizeof(ATTRIBUTE_INFO_ARRAY[0]); + + for (bsl::size_t i = 0; i < numAttributes; ++i) { + const bdlat_AttributeInfo& attributeInfo = ATTRIBUTE_INFO_ARRAY[i]; + if (attributeInfo.d_nameLength == nameLength) { + const int compare = + bsl::memcmp(attributeInfo.d_name_p, name, nameLength); + if (compare == 0) { + return &attributeInfo; + } + } + } + + return 0; +} + +const char LocalName::CLASS_NAME[16] = "ntsa::LocalName"; + +// clang-format off +const bdlat_AttributeInfo LocalName::ATTRIBUTE_INFO_ARRAY[2] = +{ + { e_ATTRIBUTE_ID_PATH, "path", 4, "", 0 }, + { e_ATTRIBUTE_ID_ABSTRACT, "abstract", 8, "", 0 }, +}; +// clang-format on + } // close package namespace } // close enterprise namespace diff --git a/groups/nts/ntsa/ntsa_localname.h b/groups/nts/ntsa/ntsa_localname.h index 76d77f1f..5fceb816 100644 --- a/groups/nts/ntsa/ntsa_localname.h +++ b/groups/nts/ntsa/ntsa_localname.h @@ -22,6 +22,10 @@ BSLS_IDENT("$Id: $") #include #include #include +#include +#include +#include +#include #include #include #include @@ -58,6 +62,11 @@ class LocalName #endif private: + enum { + e_ATTRIBUTE_ID_PATH = 0, + e_ATTRIBUTE_ID_ABSTRACT = 1 + }; + char d_path[k_MAX_PATH_LENGTH]; bsl::uint8_t d_size; bool d_abstract; @@ -150,6 +159,61 @@ class LocalName int level = 0, int spacesPerLevel = 4) const; + /// Invoke the specified 'manipulator' sequentially on the address of each + /// (modifiable) attribute of this object, supplying 'manipulator' with + /// the corresponding attribute information structure until such + /// invocation returns a non-zero value. Return the value from the last + /// invocation of 'manipulator' (i.e., the invocation that terminated the + /// sequence). + template + int manipulateAttributes(MANIPULATOR& manipulator); + + /// Invoke the specified 'manipulator' on the address of the (modifiable) + /// attribute indicated by the specified 'id', supplying 'manipulator' + /// with the corresponding attribute information structure. Return the + /// value returned from the invocation of 'manipulator' if 'id' identifies + /// an attribute of this class, and -1 otherwise. + template + int manipulateAttribute(MANIPULATOR& manipulator, int id); + + /// Invoke the specified 'manipulator' on the address of the (modifiable) + /// attribute indicated by the specified 'name' of the specified + /// 'nameLength', supplying 'manipulator' with the corresponding attribute + /// information structure. Return the value returned from the invocation + /// of 'manipulator' if 'name' identifies an attribute of this class, and + /// -1 otherwise. + template + int manipulateAttribute(MANIPULATOR& manipulator, + const char* name, + int nameLength); + + /// Invoke the specified 'accessor' sequentially on each (non-modifiable) + /// attribute of this object, supplying 'accessor' with the corresponding + /// attribute information structure until such invocation returns a + /// non-zero value. Return the value from the last invocation of + /// 'accessor' (i.e., the invocation that terminated the sequence). + template + int accessAttributes(ACCESSOR& accessor) const; + + /// Invoke the specified 'accessor' on the (non-modifiable) attribute of + /// this object indicated by the specified 'id', supplying 'accessor' with + /// the corresponding attribute information structure. Return the value + /// returned from the invocation of 'accessor' if 'id' identifies an + /// attribute of this class, and -1 otherwise. + template + int accessAttribute(ACCESSOR& accessor, int id) const; + + /// Invoke the specified 'accessor' on the (non-modifiable) attribute of + /// this object indicated by the specified 'name' of the specified + /// 'nameLength', supplying 'accessor' with the corresponding attribute + /// information structure. Return the value returned from the invocation + /// of 'accessor' if 'name' identifies an attribute of this class, and -1 + /// otherwise. + template + int accessAttribute(ACCESSOR& accessor, + const char* name, + int nameLength) const; + /// Generate a unique local name. The name will be abstract if the /// platform supports abstract names (Linux only). static ntsa::LocalName generateUnique(); @@ -161,6 +225,22 @@ class LocalName /// TMP directory is longer than sockaddr_un can store) static ntsa::Error generateUnique(ntsa::LocalName* name); + /// Return attribute information for the attribute indicated by the + /// specified 'id' if the attribute exists, and 0 otherwise. + static const bdlat_AttributeInfo* lookupAttributeInfo(int id); + + /// Return attribute information for the attribute indicated by the + /// specified 'name' of the specified 'nameLength' if the attribute + /// exists, and 0 otherwise. + static const bdlat_AttributeInfo* lookupAttributeInfo( + const char* name, int nameLength); + + /// Return the compiler-independant name for this class. + static const char CLASS_NAME[16]; + + /// The attribute info array, indexed by attribute index. + static const bdlat_AttributeInfo ATTRIBUTE_INFO_ARRAY[2]; + /// Defines the traits of this type. These traits can be used to select, /// at compile-time, the most efficient algorithm to manipulate objects /// of this type. @@ -225,6 +305,138 @@ void hashAppend(HASH_ALGORITHM& algorithm, const LocalName& value) algorithm(text.data(), text.size()); } +template +int LocalName::manipulateAttributes(MANIPULATOR& manipulator) +{ + int rc; + + rc = this->manipulateAttribute(manipulator, e_ATTRIBUTE_ID_PATH); + if (rc != 0) { + return rc; + } + + rc = this->manipulateAttribute(manipulator, e_ATTRIBUTE_ID_ABSTRACT); + if (rc != 0) { + return rc; + } + + return 0; +} + +template +int LocalName::manipulateAttribute(MANIPULATOR& manipulator, int id) +{ + int rc; + + if (id == e_ATTRIBUTE_ID_PATH) { + bsl::string path; + rc = manipulator(&path, ATTRIBUTE_INFO_ARRAY[id]); + if (rc != 0) { + return rc; + } + + this->setValue(path); + } + else if (id == e_ATTRIBUTE_ID_ABSTRACT) { + bdlb::NullableValue abstract; + rc = manipulator(&abstract, ATTRIBUTE_INFO_ARRAY[id]); + if (rc != 0) { + return rc; + } + + if (abstract.has_value() && abstract.value()) { + d_abstract = true; + } + else { + d_abstract = false; + } + } + else { + return -1; + } + + return 0; +} + +template +int LocalName::manipulateAttribute(MANIPULATOR& manipulator, + const char* name, + int nameLength) +{ + const bdlat_AttributeInfo* info = + ntsa::LocalName::lookupAttributeInfo(name, nameLength); + if (info == 0) { + return -1; + } + + return this->manipulateAttribute(manipulator, info->d_id); +} + +template +int LocalName::accessAttributes(ACCESSOR& accessor) const +{ + int rc; + + rc = this->accessAttribute(accessor, e_ATTRIBUTE_ID_PATH); + if (rc != 0) { + return rc; + } + + rc = this->accessAttribute(accessor, e_ATTRIBUTE_ID_ABSTRACT); + if (rc != 0) { + return rc; + } + + return 0; +} + +template +int LocalName::accessAttribute(ACCESSOR& accessor, int id) const +{ + int rc; + + if (id == e_ATTRIBUTE_ID_PATH) { + bsl::string path = this->value(); + rc = accessor(path, ATTRIBUTE_INFO_ARRAY[id]); + if (rc != 0) { + return rc; + } + } + else if (id == e_ATTRIBUTE_ID_ABSTRACT) { + bdlb::NullableValue abstract; + if (d_abstract) { + abstract.makeValue(true); + } + + rc = accessor(abstract, ATTRIBUTE_INFO_ARRAY[id]); + if (rc != 0) { + return rc; + } + } + else { + return -1; + } + + return 0; +} + +template +int LocalName::accessAttribute(ACCESSOR& accessor, + const char* name, + int nameLength) const +{ + const bdlat_AttributeInfo* info = + ntsa::LocalName::lookupAttributeInfo(name, nameLength); + if (info == 0) { + return -1; + } + + return this->accessAttribute(accessor, info->d_id); +} + } // close package namespace + +BDLAT_DECL_SEQUENCE_TRAITS(ntsa::LocalName) + } // close enterprise namespace #endif diff --git a/groups/nts/ntsa/ntsa_localname.t.cpp b/groups/nts/ntsa/ntsa_localname.t.cpp index d7af72d7..84792337 100644 --- a/groups/nts/ntsa/ntsa_localname.t.cpp +++ b/groups/nts/ntsa/ntsa_localname.t.cpp @@ -15,6 +15,12 @@ #include #include +#include +#include +#include +#include +#include +#include #include using namespace BloombergLP; @@ -362,6 +368,113 @@ NTSCFG_TEST_CASE(5) } } +NTSCFG_TEST_CASE(6) +{ + int rc; + + ntscfg::TestAllocator ta; + { + ntsa::LocalName e1; + e1.setValue("/tmp/ntf/test"); + + ntsa::LocalName e2; + + bdlsb::MemOutStreamBuf osb(&ta); + + balber::BerEncoder encoder(0, &ta); + rc = encoder.encode(&osb, e1); + if (rc != 0) { + NTSCFG_TEST_LOG_DEBUG << encoder.loggedMessages() + << NTSCFG_TEST_LOG_END; + + NTSCFG_TEST_EQ(rc, 0); + } + + rc = osb.pubsync(); + NTSCFG_TEST_EQ(rc, 0); + + NTSCFG_TEST_GT(osb.length(), 0); + NTSCFG_TEST_NE(osb.data(), 0); + + NTSCFG_TEST_LOG_DEBUG << "Encoded:\n" + << bdlb::PrintStringHexDumper( + osb.data(), + static_cast(osb.length())) + << NTSCFG_TEST_LOG_END; + + bdlsb::FixedMemInStreamBuf isb(osb.data(), osb.length()); + + balber::BerDecoder decoder(0, &ta); + rc = decoder.decode(&isb, &e2); + if (rc != 0) { + NTSCFG_TEST_LOG_DEBUG << encoder.loggedMessages() + << NTSCFG_TEST_LOG_END; + + NTSCFG_TEST_EQ(rc, 0); + } + + NTSCFG_TEST_EQ(e2, e1); + } + NTSCFG_TEST_EQ(ta.numBlocksInUse(), 0); +} + +NTSCFG_TEST_CASE(7) +{ + int rc; + + ntscfg::TestAllocator ta; + { + ntsa::LocalName localName; + localName.setValue("/tmp/ntf/test"); + + bsl::vector e1(&ta); + bsl::vector e2(&ta); + + e1.push_back(localName); + + bdlsb::MemOutStreamBuf osb(&ta); + + baljsn::Encoder encoder(&ta); + rc = encoder.encode(&osb, e1); + if (rc != 0) { + NTSCFG_TEST_LOG_DEBUG << encoder.loggedMessages() + << NTSCFG_TEST_LOG_END; + + NTSCFG_TEST_EQ(rc, 0); + } + + rc = osb.pubsync(); + NTSCFG_TEST_EQ(rc, 0); + + NTSCFG_TEST_GT(osb.length(), 0); + NTSCFG_TEST_NE(osb.data(), 0); + + NTSCFG_TEST_LOG_DEBUG << "Encoded: " + << bsl::string_view( + osb.data(), + static_cast(osb.length())) + << NTSCFG_TEST_LOG_END; + + bdlsb::FixedMemInStreamBuf isb(osb.data(), osb.length()); + + baljsn::Decoder decoder(&ta); + rc = decoder.decode(&isb, &e2); + if (rc != 0) { + NTSCFG_TEST_LOG_DEBUG << encoder.loggedMessages() + << NTSCFG_TEST_LOG_END; + + NTSCFG_TEST_EQ(rc, 0); + } + + NTSCFG_TEST_EQ(e2.size(), e1.size()); + + for (bsl::size_t i = 0; i < e1.size(); ++i) { + NTSCFG_TEST_EQ(e2[i], e1[i]); + } + } + NTSCFG_TEST_EQ(ta.numBlocksInUse(), 0); +} + NTSCFG_TEST_DRIVER { NTSCFG_TEST_REGISTER(1); @@ -369,6 +482,8 @@ NTSCFG_TEST_DRIVER NTSCFG_TEST_REGISTER(3); NTSCFG_TEST_REGISTER(4); NTSCFG_TEST_REGISTER(5); + NTSCFG_TEST_REGISTER(6); + NTSCFG_TEST_REGISTER(7); } NTSCFG_TEST_DRIVER_END;